summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmisha Singla <amishas157@gmail.com>2016-02-15 22:08:15 +0530
committerJonas Danielsson <jonas@threetimestwo.org>2016-02-16 10:09:54 +0100
commitac88800dccbbc836b6e7a7bd6e5ee20fb225a997 (patch)
tree78d32753cb97e142b5f6858c69d3b987ca073a13
parentc6308b145131a135f8d061914426a5c023249a08 (diff)
downloadgnome-maps-ac88800dccbbc836b6e7a7bd6e5ee20fb225a997.tar.gz
Add Print Route Feature
Print Operation class is added to draw the cairo surfaces given to it. Print Layout acts as a tool-box which sub-classes like short Route layout , long route layout use to layout the surfaces as per the respective requirements of rendering various surfaces. GUI is added to give users an ability to access print Route feature. https://bugzilla.gnome.org/show_bug.cgi?id=746790
-rw-r--r--data/ui/help-overlay.ui9
-rw-r--r--data/ui/main-window.ui21
-rw-r--r--po/POTFILES.in2
-rw-r--r--src/longPrintLayout.js98
-rw-r--r--src/mainWindow.js18
-rw-r--r--src/org.gnome.Maps.src.gresource.xml4
-rw-r--r--src/printLayout.js277
-rw-r--r--src/printOperation.js108
-rw-r--r--src/route.js4
-rw-r--r--src/shortPrintLayout.js61
10 files changed, 598 insertions, 4 deletions
diff --git a/data/ui/help-overlay.ui b/data/ui/help-overlay.ui
index 45c11d7a..70b36928 100644
--- a/data/ui/help-overlay.ui
+++ b/data/ui/help-overlay.ui
@@ -23,7 +23,7 @@
<property name="accelerator">&lt;Primary&gt;F</property>
</object>
</child>
- <child>
+ <child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="title" translatable="yes" context="shortcut window">Toggle route planner</property>
@@ -33,6 +33,13 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
+ <property name="title" translatable="yes" context="shortcut window">Print route</property>
+ <property name="accelerator">&lt;Primary&gt;P</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="visible">1</property>
<property name="title" translatable="yes" context="shortcut window">Quit</property>
<property name="accelerator">&lt;Primary&gt;Q</property>
</object>
diff --git a/data/ui/main-window.ui b/data/ui/main-window.ui
index f91dce29..e350f791 100644
--- a/data/ui/main-window.ui
+++ b/data/ui/main-window.ui
@@ -97,6 +97,27 @@
<property name="pack-type">end</property>
</packing>
</child>
+ <child>
+ <object class="GtkButton" id="printRouteButton">
+ <property name="name">print-route</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes">Print Route</property>
+ <property name="action-name">win.print-route</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="print-route-button-image">
+ <property name="visible">True</property>
+ <property name="icon-name">document-print-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
</object>
</child>
<child>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cc069f75..df436e19 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -38,6 +38,8 @@ src/osmEditDialog.js
src/placeBubble.js
src/placeEntry.js
src/place.js
+src/printLayout.js
+src/printOperation.js
src/routeService.js
src/sendToDialog.js
src/shapeLayer.js
diff --git a/src/longPrintLayout.js b/src/longPrintLayout.js
new file mode 100644
index 00000000..22ae720f
--- /dev/null
+++ b/src/longPrintLayout.js
@@ -0,0 +1,98 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Amisha Singla <amishas157@gmail.com>
+ */
+
+const Lang = imports.lang;
+
+const PrintLayout = imports.printLayout;
+
+const _NUM_MINIMAPS = 5;
+
+/* All following constants are ratios of surface size to page size */
+const _Instruction = {
+ SCALE_X: 0.57,
+ SCALE_Y: 0.05,
+ SCALE_MARGIN: 0.01
+};
+const _MiniMapView = {
+ SCALE_X: 0.4,
+ SCALE_Y: 0.20,
+ SCALE_MARGIN: 0.03,
+ ZOOM_LEVEL: 18
+};
+
+const LongPrintLayout = new Lang.Class({
+ Name: 'LongPrintLayout',
+ Extends: PrintLayout.PrintLayout,
+
+ _init: function(params) {
+ this._route = params.route;
+ delete params.route;
+
+ /* (Header + 3 maps) + instructions */
+ let totalSurfaces = 4 + this._route.turnPoints.length;
+ params.totalSurfaces = totalSurfaces;
+
+ this.parent(params);
+ },
+
+ render: function() {
+ this.parent();
+
+ let instructionWidth = _Instruction.SCALE_X * this._pageWidth;
+ let instructionHeight = _Instruction.SCALE_Y * this._pageHeight;
+ let instructionMargin = _Instruction.SCALE_MARGIN * this._pageHeight;
+
+ let miniMapViewWidth = _MiniMapView.SCALE_X * this._pageWidth;
+ let miniMapViewHeight = _MiniMapView.SCALE_Y * this._pageHeight;
+ let miniMapViewMargin = _MiniMapView.SCALE_MARGIN * this._pageHeight;
+ let miniMapViewZoomLevel = _MiniMapView.ZOOM_LEVEL;
+
+ let dy = 0;
+ let locationsLength = this._route.turnPoints.length;
+
+ /* Fixed number of locations are plotted on minimaps which requires a
+ * check on instructions bound. Later on this can be made dynamic
+ * depending upon factors like total number of instructions, complexity
+ * of neighbourhood areas, etc.
+ */
+ let nthStartLocation = Math.min(_NUM_MINIMAPS, locationsLength);
+ let startLocations = this._createLocationArray(0, nthStartLocation);
+ this._drawMapView(miniMapViewWidth, miniMapViewHeight,
+ miniMapViewZoomLevel, startLocations);
+
+ /* x-cursor is increased temporarily for rendering instructions */
+ let tmpX = this._cursorX;
+ this._route.turnPoints.forEach(function(turnPoint) {
+ dy = instructionHeight + instructionMargin;
+ this._adjustPage(dy);
+ this._cursorX = tmpX + miniMapViewWidth + miniMapViewMargin;
+ this._drawInstruction(instructionWidth, instructionHeight,
+ turnPoint);
+ this._cursorY += dy;
+ }.bind(this));
+ this._cursorX = tmpX;
+
+ let firstEndLocation = Math.max(0, locationsLength - _NUM_MINIMAPS);
+ let endLocations = this._createLocationArray(firstEndLocation,
+ locationsLength);
+ this._cursorY = Math.max(0, this._cursorY - miniMapViewHeight);
+ this._drawMapView(miniMapViewWidth, miniMapViewHeight,
+ miniMapViewZoomLevel, endLocations);
+ }
+});
diff --git a/src/mainWindow.js b/src/mainWindow.js
index 3c388de9..afb7297f 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -38,6 +38,7 @@ const LocationServiceNotification = imports.locationServiceNotification;
const MapView = imports.mapView;
const PlaceEntry = imports.placeEntry;
const PlaceStore = imports.placeStore;
+const PrintOperation = imports.printOperation;
const Sidebar = imports.sidebar;
const Utils = imports.utils;
const ZoomControl = imports.zoomControl;
@@ -57,7 +58,8 @@ const MainWindow = new Lang.Class({
'gotoUserLocationButton',
'toggleSidebarButton',
'layersButton',
- 'favoritesButton' ],
+ 'favoritesButton',
+ 'printRouteButton' ],
get mapView() {
return this._mapView;
@@ -202,6 +204,10 @@ const MainWindow = new Lang.Class({
'find': {
accels: ['<Primary>F'],
onActivate: this._placeEntry.grab_focus.bind(this._placeEntry)
+ },
+ 'print-route': {
+ accels: ['<Primary>P'],
+ onActivate: this._printRouteActivate.bind(this)
}
});
},
@@ -248,6 +254,9 @@ const MainWindow = new Lang.Class({
this._favoritesButton.sensitive = favoritesPopover.rows > 0;
}).bind(this));
+ this._mapView.bind_property('routeVisible', this._printRouteButton,
+ 'visible', GObject.BindingFlags.DEFAULT);
+
Application.geoclue.connect('notify::state',
this._updateLocationSensitivity.bind(this));
this.application.connect('notify::connected', (function() {
@@ -259,6 +268,7 @@ const MainWindow = new Lang.Class({
this._favoritesButton.sensitive = (app.connected &&
favoritesPopover.rows > 0);
this._placeEntry.sensitive = app.connected;
+ this._printRouteButton.sensitive = app.connected;
}).bind(this));
},
@@ -365,6 +375,12 @@ const MainWindow = new Lang.Class({
}
},
+ _printRouteActivate: function() {
+ if (this._mapView.routeVisible) {
+ let operation = new PrintOperation.PrintOperation({ mainWindow: this });
+ }
+ },
+
_onMapTypeMenuActivate: function(action) {
let state = action.get_state().get_boolean();
action.set_state(GLib.Variant.new('b', !state));
diff --git a/src/org.gnome.Maps.src.gresource.xml b/src/org.gnome.Maps.src.gresource.xml
index 769ec812..ecd8ef4f 100644
--- a/src/org.gnome.Maps.src.gresource.xml
+++ b/src/org.gnome.Maps.src.gresource.xml
@@ -26,6 +26,7 @@
<file>layersPopover.js</file>
<file>location.js</file>
<file>locationServiceNotification.js</file>
+ <file>longPrintLayout.js</file>
<file>main.js</file>
<file>mainWindow.js</file>
<file>mapBubble.js</file>
@@ -52,6 +53,8 @@
<file>placeMarker.js</file>
<file>placePopover.js</file>
<file>placeStore.js</file>
+ <file>printLayout.js</file>
+ <file>printOperation.js</file>
<file>route.js</file>
<file>routeEntry.js</file>
<file>routeQuery.js</file>
@@ -61,6 +64,7 @@
<file>settings.js</file>
<file>sendToDialog.js</file>
<file>shapeLayer.js</file>
+ <file>shortPrintLayout.js</file>
<file>sidebar.js</file>
<file>socialPlace.js</file>
<file>socialPlaceListBox.js</file>
diff --git a/src/printLayout.js b/src/printLayout.js
new file mode 100644
index 00000000..b4e72fad
--- /dev/null
+++ b/src/printLayout.js
@@ -0,0 +1,277 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Amisha Singla <amishas157@gmail.com>
+ */
+
+const Cairo = imports.cairo;
+const Champlain = imports.gi.Champlain;
+const Clutter = imports.gi.Clutter;
+const GObject = imports.gi.GObject;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Pango = imports.gi.Pango;
+const PangoCairo = imports.gi.PangoCairo;
+
+const Application = imports.application;
+const InstructionRow = imports.instructionRow;
+const MapMarker = imports.mapMarker;
+const MapView = imports.mapView;
+const TurnPointMarker = imports.turnPointMarker;
+
+/* Following constant has unit as meters */
+const _SHORT_LAYOUT_MAX_DISTANCE = 3000;
+
+const _STROKE_COLOR = new Clutter.Color({ red: 0,
+ blue: 255,
+ green: 0,
+ alpha: 100 });
+const _STROKE_WIDTH = 5.0;
+
+/* All following constants are ratios of surface size to page size */
+const _Header = {
+ SCALE_X: 0.9,
+ SCALE_Y: 0.03,
+ SCALE_MARGIN: 0.01
+};
+const _MapView = {
+ SCALE_X: 1.0,
+ SCALE_Y: 0.4,
+ SCALE_MARGIN: 0.04,
+ ZOOM_LEVEL: 18
+};
+
+function newFromRoute(route, pageWidth, pageHeight) {
+ /*
+ * To avoid the circular dependencies, imports has
+ * been carried out in this method
+ */
+ if (route.distance > _SHORT_LAYOUT_MAX_DISTANCE) {
+ return new imports.longPrintLayout.LongPrintLayout({
+ route: route,
+ pageWidth: pageWidth,
+ pageHeight: pageHeight
+ });
+ } else {
+ return new imports.shortPrintLayout.ShortPrintLayout({
+ route: route,
+ pageWidth: pageWidth,
+ pageHeight: pageHeight
+ });
+ }
+}
+
+const PrintLayout = new Lang.Class({
+ Name: 'PrintLayout',
+ Extends: GObject.Object,
+ Abstract: true,
+ Signals: {
+ 'render-complete': { }
+ },
+
+ _init: function(params) {
+ this._pageWidth = params.pageWidth;
+ delete params.pageWidth;
+
+ this._pageHeight = params.pageHeight;
+ delete params.pageHeight;
+
+ this._totalSurfaces = params.totalSurfaces;
+ delete params.totalSurfaces;
+
+ this.parent();
+
+ this.numPages = 0;
+ this.surfaceObjects = [];
+ this._surfacesRendered = 0;
+ this.renderFinished = false;
+ this._initSignals();
+ },
+
+ render: function() {
+ let headerWidth = _Header.SCALE_X * this._pageWidth;
+ let headerHeight = _Header.SCALE_Y * this._pageHeight;
+ let headerMargin = _Header.SCALE_MARGIN * this._pageHeight;
+
+ let mapViewWidth = _MapView.SCALE_X * this._pageWidth;
+ let mapViewHeight = _MapView.SCALE_Y * this._pageHeight;
+ let mapViewMargin = _MapView.SCALE_MARGIN * this._pageHeight;
+ let mapViewZoomLevel = _MapView.ZOOM_LEVEL;
+
+ this._createNewPage();
+ let dy = 0;
+
+ /*
+ * Before rendering each surface, page adjustment is done. It is checked if it
+ * can be adjusted in current page, otherwise a new page is created
+ */
+ dy = headerHeight + headerMargin;
+ this._adjustPage(dy);
+ this._drawHeader(headerWidth, headerHeight);
+ this._cursorY += dy;
+
+ dy = mapViewHeight + mapViewMargin;
+ this._adjustPage(dy);
+ let locationsLength = this._route.turnPoints.length;
+ let allLocations = this._createLocationArray(0, locationsLength);
+ this._drawMapView(mapViewWidth, mapViewHeight,
+ mapViewZoomLevel, allLocations);
+ this._cursorY += dy;
+ },
+
+ _initSignals: function() {
+ this.connect('render-complete', (function() {
+ this.renderFinished = true;
+ }).bind(this));
+ },
+
+ _drawMapView: function(width, height, zoomLevel, locations) {
+ let pageNum = this.numPages - 1;
+ let x = this._cursorX;
+ let y = this._cursorY;
+ let factory = Champlain.MapSourceFactory.dup_default();
+ let mapSource = factory.create_cached_source(MapView.MapType.STREET);
+ let view = new Champlain.View({ width: width,
+ height: height,
+ zoom_level: zoomLevel });
+ view.set_map_source(mapSource);
+
+ this._addRouteLayer(view);
+
+ view.ensure_visible(this._route.createBBox(locations), false);
+ if (view.state !== Champlain.State.DONE) {
+ let notifyId = view.connect('notify::state', (function() {
+ if (view.state === Champlain.State.DONE) {
+ view.disconnect(notifyId);
+ let surface = view.to_surface(true);
+ if (surface)
+ this._addSurface(surface, x, y, pageNum);
+ }
+ }).bind(this));
+ } else {
+ let surface = view.to_surface(true);
+ if (surface)
+ this._addSurface(surface, x, y, pageNum);
+ }
+ },
+
+ _createLocationArray: function(startIndex, endIndex) {
+ let locationArray = [];
+ for (let i = startIndex; i < endIndex; i++) {
+ locationArray.push(this._route.turnPoints[i].coordinate);
+ }
+ return locationArray;
+ },
+
+ _addRouteLayer: function(view) {
+ let routeLayer = new Champlain.PathLayer({ stroke_width: _STROKE_WIDTH,
+ stroke_color: _STROKE_COLOR });
+ view.add_layer(routeLayer);
+ this._route.path.forEach(routeLayer.add_node.bind(routeLayer));
+ },
+
+ _drawInstruction: function(width, height, turnPoint) {
+ let pageNum = this.numPages - 1;
+ let x = this._cursorX;
+ let y = this._cursorY;
+ let instructionWidget = new Gtk.OffscreenWindow({ visible: true });
+ let instructionEntry = new InstructionRow.InstructionRow({
+ visible: true,
+ turnPoint: turnPoint
+ });
+
+ instructionWidget.width_request = width;
+ instructionWidget.height_request = height;
+
+ /* Paint the background of the entry to be transparent */
+ instructionEntry.connect('draw', (function(widget, cr) {
+ cr.setSourceRGBA(0.0, 0.0, 0.0, 0.0);
+ cr.setOperator(Cairo.Operator.SOURCE);
+ cr.paint();
+ cr.setOperator(Cairo.Operator.OVER);
+ }).bind(this));
+
+ instructionEntry.queue_draw();
+ instructionWidget.add(instructionEntry);
+ instructionWidget.set_valign(Gtk.Align.START);
+ instructionWidget.connect('damage-event', (function(widget) {
+ let surface = widget.get_surface();
+ this._addSurface(surface, x, y, pageNum);
+ }).bind(this));
+ },
+
+ _drawHeader: function(width, height) {
+ let pageNum = this.numPages - 1;
+ let x = this._cursorX;
+ let y = this._cursorY;
+ let surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height);
+ let cr = new Cairo.Context(surface);
+ let layout = PangoCairo.create_layout(cr);
+ let from = this._formatQueryPlaceName(0);
+ let to = this._formatQueryPlaceName(-1);
+ let header = _("From %s to %s").format(from, to);
+ let desc = Pango.FontDescription.from_string("sans");
+
+ layout.set_text(header, -1);
+ layout.set_height(Pango.units_from_double(height));
+ layout.set_width(Pango.units_from_double(width));
+ layout.set_font_description(desc);
+ layout.set_alignment(Pango.Alignment.CENTER);
+ PangoCairo.layout_path(cr, layout);
+ cr.setSourceRGB(0.0,0.0,0.0);
+ cr.fill();
+
+ this._addSurface(surface, x, y, pageNum);
+ },
+
+ _addSurface: function(surface, x, y, pageNum) {
+ this.surfaceObjects[pageNum].push({ surface: surface, x: x, y: y });
+ this._surfacesRendered++;
+ if (this._surfacesRendered === this._totalSurfaces)
+ this.emit('render-complete');
+ },
+
+ _adjustPage: function(dy) {
+ if (this._cursorY + dy > this._pageHeight)
+ this._createNewPage();
+ },
+
+ _createNewPage: function() {
+ this.numPages++;
+ this.surfaceObjects[this.numPages - 1] = [];
+ this._cursorX = 0;
+ this._cursorY = 0;
+ },
+
+ _formatQueryPlaceName: function(index) {
+ let query = Application.routeService.query;
+ if (index === -1)
+ index = query.filledPoints.length - 1;
+ let name;
+ let place = query.filledPoints[index].place;
+ if (place.name) {
+ name = place.name;
+ if (name.length > 25)
+ name = name.substr(0, 22) + '\u2026';
+ } else {
+ let lat = place.location.latitude.toFixed(5);
+ let lon = place.location.latitude.toFixed(5);
+ name = '%s, %s'.format(lat, lon);
+ }
+
+ return name;
+ }
+});
diff --git a/src/printOperation.js b/src/printOperation.js
new file mode 100644
index 00000000..422490d8
--- /dev/null
+++ b/src/printOperation.js
@@ -0,0 +1,108 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Amisha Singla <amishas157@gmail.com>
+ */
+
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+
+const Application = imports.application;
+const PrintLayout = imports.printLayout;
+const Utils = imports.utils;
+
+const _MIN_TIME_TO_ABORT = 3000;
+
+const PrintOperation = new Lang.Class({
+ Name: 'PrintOperation',
+
+ _init: function(params) {
+ this._mainWindow = params.mainWindow;
+ delete params.mainWindow;
+
+ this._operation = new Gtk.PrintOperation({ embed_page_setup: true });
+ this._operation.connect('begin-print', this._beginPrint.bind(this));
+ this._operation.connect('paginate', this._paginate.bind(this));
+ this._operation.connect('draw-page', this._drawPage.bind(this));
+
+ this._abortDialog = new Gtk.MessageDialog({
+ transient_for: this._mainWindow,
+ destroy_with_parent: true,
+ message_type: Gtk.MessageType.OTHER,
+ modal: true,
+ text: _("Loading map tiles for printing"),
+ secondary_text: _("You can abort printing if this takes too long")
+ });
+ this._abortDialog.add_button(_("Abort printing"),
+ Gtk.ResponseType.CANCEL);
+ this._responseId = this._abortDialog.connect('response',
+ this.onAbortDialogResponse.bind(this));
+
+ this._runPrintOperation();
+ },
+
+ _beginPrint: function(operation, context, data) {
+ let route = Application.routeService.route;
+ let width = context.get_width();
+ let height = context.get_height();
+
+ Mainloop.timeout_add(_MIN_TIME_TO_ABORT, (function() {
+ if (this._operation.get_status() !== Gtk.PrintStatus.FINISHED) {
+ this._abortDialog.show();
+ }
+ return false;
+ }).bind(this), null);
+
+ this._layout = PrintLayout.newFromRoute(route, width, height);
+ this._layout.render();
+ },
+
+ onAbortDialogResponse: function(dialog, response) {
+ if (response === Gtk.ResponseType.DELETE_EVENT ||
+ response === Gtk.ResponseType.CANCEL) {
+ this._abortDialog.disconnect(this._responseId);
+ this._operation.cancel();
+ this._abortDialog.close();
+ }
+ },
+
+ _paginate: function(operation, context) {
+ if (this._layout.renderFinished) {
+ operation.set_n_pages(this._layout.numPages);
+ this._abortDialog.close();
+ }
+ return this._layout.renderFinished;
+ },
+
+ _drawPage: function(operation, context, page_num, data) {
+ let cr = context.get_cairo_context();
+ this._layout.surfaceObjects[page_num].forEach((function(so) {
+ cr.setSourceSurface(so.surface, so.x, so.y);
+ cr.paint();
+ }).bind(this));
+ },
+
+ _runPrintOperation: function() {
+ let result = this._operation.run(Gtk.PrintOperationAction.PRINT_DIALOG,
+ this._mainWindow, null);
+
+ if (result === Gtk.PrintOperationResult.ERROR) {
+ let error = this._operation.get_error();
+ Utils.debug('Failed to print: %s'.format(error));
+ }
+ }
+});
diff --git a/src/route.js b/src/route.js
index 61df3aef..2b4656d2 100644
--- a/src/route.js
+++ b/src/route.js
@@ -53,7 +53,7 @@ const Route = new Lang.Class({
this.turnPoints = turnPoints;
this.distance = distance;
this.time = time;
- this.bbox = bbox || this._createBBox(path);
+ this.bbox = bbox || this.createBBox(path);
this.emit('update');
},
@@ -67,7 +67,7 @@ const Route = new Lang.Class({
this.emit('reset');
},
- _createBBox: function(coordinates) {
+ createBBox: function(coordinates) {
let bbox = new Champlain.BoundingBox();
coordinates.forEach(function({ latitude, longitude }) {
bbox.extend(latitude, longitude);
diff --git a/src/shortPrintLayout.js b/src/shortPrintLayout.js
new file mode 100644
index 00000000..61be99b1
--- /dev/null
+++ b/src/shortPrintLayout.js
@@ -0,0 +1,61 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Amisha Singla <amishas157@gmail.com>
+ */
+
+const Lang = imports.lang;
+
+const PrintLayout = imports.printLayout;
+
+/* All following constants are ratios of surface size to page size */
+const _Instruction = {
+ SCALE_X: 1.0,
+ SCALE_Y: 0.05,
+ SCALE_MARGIN: 0.01
+};
+
+const ShortPrintLayout = new Lang.Class({
+ Name: 'ShortPrintLayout',
+ Extends: PrintLayout.PrintLayout,
+
+ _init: function(params) {
+ this._route = params.route;
+ delete params.route;
+
+ /* (Header + map) + instructions */
+ let totalSurfaces = 2 + this._route.turnPoints.length;
+ params.totalSurfaces = totalSurfaces;
+
+ this.parent(params);
+ },
+
+ render: function() {
+ this.parent();
+
+ let instructionWidth = _Instruction.SCALE_X * this._pageWidth;
+ let instructionHeight = _Instruction.SCALE_Y * this._pageHeight;
+ let instructionMargin = _Instruction.SCALE_MARGIN * this._pageHeight;
+ let dy = 0;
+
+ this._route.turnPoints.forEach(function(turnPoint) {
+ dy = instructionHeight + instructionMargin;
+ this._adjustPage(dy);
+ this._drawInstruction(instructionWidth, instructionHeight, turnPoint);
+ this._cursorY += dy;
+ }.bind(this));
+ }
+});