[gnome-maps/wip/cdavis/post-port-cleanups: 20/29] general: Rework context menu
- From: Christopher Davis <christopherdavis src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-maps/wip/cdavis/post-port-cleanups: 20/29] general: Rework context menu
- Date: Sun, 21 Aug 2022 23:37:12 +0000 (UTC)
commit 3d73517cfc82af997033fe456428c37c9d2cf57c
Author: Christopher Davis <christopherdavis gnome org>
Date: Sun Aug 21 12:53:28 2022 -0400
general: Rework context menu
The context menu had a few papercuts after the port, notably
placement. The code was also a bit hard to follow - the actions
were declared in mainWindow.js, but defined in contextMenu.js.
This commit removes the ContextMenu class, and instead builds
and displays the popover in mapView.js. This also allows
us to move our actions to mapView.js using a custom action group.
The placement is also fixed.
data/ui/context-menu.ui | 16 +--
po/POTFILES.in | 1 -
src/contextMenu.js | 218 --------------------------------
src/mainWindow.js | 10 --
src/mapView.js | 189 +++++++++++++++++++++++++++
src/org.gnome.Maps.src.gresource.xml.in | 1 -
6 files changed, 195 insertions(+), 240 deletions(-)
---
diff --git a/data/ui/context-menu.ui b/data/ui/context-menu.ui
index 07100c3e..2904df1b 100644
--- a/data/ui/context-menu.ui
+++ b/data/ui/context-menu.ui
@@ -4,34 +4,30 @@
<section>
<item>
<attribute name="label" translatable="yes">Route from here</attribute>
- <attribute name="action">win.route-from-here</attribute>
+ <attribute name="action">view.route-from-here</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Add intermediate destination</attribute>
- <attribute name="action">win.add-intermediate-destination</attribute>
+ <attribute name="action">view.add-intermediate-destination</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Route to here</attribute>
- <attribute name="action">win.route-to-here</attribute>
+ <attribute name="action">view.route-to-here</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">What's here?</attribute>
- <attribute name="action">win.whats-here</attribute>
+ <attribute name="action">view.whats-here</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Copy location</attribute>
- <attribute name="action">win.copy-location</attribute>
+ <attribute name="action">view.copy-location</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Add to OpenStreetMap</attribute>
- <attribute name="action">win.add-osm-location</attribute>
+ <attribute name="action">view.add-osm-location</attribute>
</item>
</section>
</menu>
- <template class="Gjs_ContextMenu" parent="GtkPopoverMenu">
- <property name="menu-model">context-menu</property>
- <property name="has-arrow">False</property>
- </template>
</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8bac3868..e840e653 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -29,7 +29,6 @@ data/ui/zoom-in-dialog.ui
lib/maps-file-data-source.c
lib/maps-osm.c
src/application.js
-src/contextMenu.js
src/exportViewDialog.js
src/geoclue.js
src/geoJSONSource.js
diff --git a/src/mainWindow.js b/src/mainWindow.js
index 5c4b806d..019c6d09 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -31,7 +31,6 @@ import Adw from 'gi://Adw';
import Shumate from 'gi://Shumate';
import {Application} from './application.js';
-import {ContextMenu} from './contextMenu.js';
import {ExportViewDialog} from './exportViewDialog.js';
import {FavoritesPopover} from './favoritesPopover.js';
import * as Geoclue from './geoclue.js';
@@ -123,9 +122,6 @@ export class MainWindow extends Gtk.ApplicationWindow {
this._initDND();
this._initPlaceBar();
- this._contextMenu = new ContextMenu({ mapView: this._mapView,
- mainWindow: this });
-
this._grid.attach(this._sidebar, 1, 0, 1, 2);
/* for some reason, setting the title of the window through the .ui
@@ -239,12 +235,6 @@ export class MainWindow extends Gtk.ApplicationWindow {
'export-as-image': {
onActivate: () => this._onExportActivated()
},
- 'route-from-here': {},
- 'add-intermediate-destination': {},
- 'route-to-here': {},
- 'whats-here': {},
- 'copy-location': {},
- 'add-osm-location': {}
};
// when aerial tiles are available, add shortcuts to switch
diff --git a/src/mapView.js b/src/mapView.js
index 81993de3..e077a5dd 100644
--- a/src/mapView.js
+++ b/src/mapView.js
@@ -33,14 +33,19 @@ import {Application} from './application.js';
import {BoundingBox} from './boundingBox.js';
import * as Color from './color.js';
import * as Geoclue from './geoclue.js';
+import * as GeocodeFactory from './geocode.js';
import {GeoJSONShapeLayer} from './geoJSONShapeLayer.js';
import {KmlShapeLayer} from './kmlShapeLayer.js';
import {GpxShapeLayer} from './gpxShapeLayer.js';
import {Location} from './location.js';
import * as MapSource from './mapSource.js';
import {MapWalker} from './mapWalker.js';
+import {OSMAccountDialog} from './osmAccountDialog.js';
+import {OSMEdit} from './osmEdit.js';
+import {OSMEditDialog} from './osmEditDialog.js';
import {Place} from './place.js';
import {PlaceMarker} from './placeMarker.js';
+import {RouteQuery} from './routeQuery.js';
import * as Service from './service.js';
import {ShapeLayer} from './shapeLayer.js';
import {StoredRoute} from './storedRoute.js';
@@ -50,6 +55,7 @@ import {TransitWalkMarker} from './transitWalkMarker.js';
import {TurnPointMarker} from './turnPointMarker.js';
import {UserLocationMarker} from './userLocationMarker.js';
import * as Utils from './utils.js';
+import {ZoomInDialog} from './zoomInDialog.js';
const _LOCATION_STORE_TIMEOUT = 500;
const MapMinZoom = 2;
@@ -153,6 +159,49 @@ export class MapView extends Gtk.Overlay {
Application.geoclue.connect('notify::state',
this._updateUserLocation.bind(this));
this._connectRouteSignals();
+
+ let actions = {
+ 'route-from-here': {
+ onActivate: () => this._onRouteFromHereActivated()
+ },
+ 'add-intermediate-destination': {
+ onActivate: () => this._onAddIntermediateDestinationActivated()
+ },
+ 'route-to-here': {
+ onActivate: () => this._onRouteToHereActivated()
+ },
+ 'whats-here': {
+ onActivate: () => this._onWhatsHereActivated()
+ },
+ 'copy-location': {
+ onActivate: () => this._onCopyLocationActivated()
+ },
+ 'add-osm-location': {
+ onActivate: () => this._onAddOSMLocationActivated()
+ }
+ };
+
+ let actionGroup = new Gio.SimpleActionGroup();
+ Utils.addActions(actionGroup, actions, null);
+ this.insert_action_group('view', actionGroup);
+
+ this._routeFromHereAction = actionGroup.lookup('route-from-here');
+ this._routeToHereAction = actionGroup.lookup('route-to-here');
+ this._addIntermediateDestinationAction = actionGroup.lookup('add-intermediate-destination');
+
+ let builder = Gtk.Builder.new_from_resource('/org/gnome/Maps/ui/context-menu.ui');
+ let menuModel = builder.get_object('context-menu');
+ this._contextMenu = new Gtk.PopoverMenu({ menu_model: menuModel, has_arrow: false });
+ this._contextMenu.set_parent(this);
+
+ this._clickGesture = new Gtk.GestureClick({ button: Gdk.BUTTON_SECONDARY });
+ this._clickGesture.connect('pressed', this._onClickGesturePressed.bind(this));
+ this.add_controller(this._clickGesture);
+ }
+
+ vfunc_size_allocate(width, height, baseline) {
+ super.vfunc_size_allocate(width, height, baseline);
+ this._contextMenu.present();
}
zoomIn() {
@@ -336,6 +385,16 @@ export class MapView extends Gtk.Overlay {
this._instructionMarkerLayer.remove_all();
this.routeShowing = false;
});
+
+ query.connect('notify::points', () => {
+ let query = Application.routeQuery;
+ let numPoints = query.points.length;
+
+ this._routeFromHereAction.enabled = numPoints < RouteQuery.MAX_QUERY_POINTS;
+ this._routeToHereAction.enabled = numPoints < RouteQuery.MAX_QUERY_POINTS;
+ this._addIntermediateDestinationAction.enabled =
+ query.filledPoints.length >= 2 && numPoints < RouteQuery.MAX_QUERY_POINTS;
+ });
}
_getStoredMapType() {
@@ -899,6 +958,136 @@ export class MapView extends Gtk.Overlay {
onSetMarkerSelected(selectedMarker) {
this.emit('marker-selected', selectedMarker);
}
+
+ _onClickGesturePressed(gesture, n_presses, x, y) {
+ if (n_presses > 1) {
+ gesture.set_state(Gtk.EventSequenceState.DENIED);
+ return;
+ }
+
+ let event = gesture.get_current_event();
+ if (event.triggers_context_menu()) {
+ let viewport = this.map.viewport;
+ let rect = new Gdk.Rectangle({ x: x, y: y, width: 0, height: 0 });
+
+ [this._latitude, this._longitude] = viewport.widget_coords_to_location(this, x, y);
+
+ if (this.direction === Gtk.TextDirection.RTL) {
+ this._contextMenu.halign = Gtk.Align.END;
+ } else {
+ this._contextMenu.halign = Gtk.Align.START;
+ }
+
+ this._contextMenu.pointing_to = rect;
+ this._contextMenu.popup();
+ gesture.set_state(Gtk.EventSequenceState.CLAIMED);
+ }
+
+ gesture.set_state(Gtk.EventSequenceState.DENIED);
+ }
+
+ _onRouteFromHereActivated() {
+ let query = Application.routeQuery;
+ let location = new Location({ latitude: this._latitude,
+ longitude: this._longitude,
+ accuracy: 0 });
+ let place = new Place({ location: location, store: false });
+
+ query.points[0].place = place;
+ }
+
+ _onAddIntermediateDestinationActivated() {
+ let query = Application.routeQuery;
+ let location = new Location({ latitude: this._latitude,
+ longitude: this._longitude,
+ accuracy: 0 });
+ let place = new Place({ location: location, store: false });
+
+ query.addPoint(-1).place = place;
+ }
+
+ _onRouteToHereActivated() {
+ let query = Application.routeQuery;
+ let location = new Location({ latitude: this._latitude,
+ longitude: this._longitude,
+ accuracy: 0 });
+ let place = new Place({ location: location, store: false });
+
+ query.points.last().place = place;
+ }
+
+ _onWhatsHereActivated() {
+ GeocodeFactory.getGeocoder().reverse(this._latitude, this._longitude,
+ (place) => {
+ if (place) {
+ this.showPlace(place, true);
+ } else {
+ let msg = _("Nothing found here!");
+
+ Utils.showDialog(msg, Gtk.MessageType.INFO, this._mainWindow);
+ }
+ });
+ }
+
+ _onCopyLocationActivated() {
+ let location = new Location({ latitude: this._latitude,
+ longitude: this._longitude,
+ accuracy: 0 });
+ let clipboard = this.get_clipboard();
+ let uri = location.to_uri(GeocodeGlib.LocationURIScheme.GEO);
+
+ clipboard.set(uri);
+ }
+
+ _onAddOSMLocationActivated() {
+ let osmEdit = Application.osmEdit;
+ /* if the user is not already signed in, show the account dialog */
+ if (!osmEdit.isSignedIn) {
+ let dialog = osmEdit.createAccountDialog(this._mainWindow, true);
+
+ dialog.show();
+ dialog.connect('response', (dialog, response) => {
+ dialog.destroy();
+ if (response === OSMAccountDialog.Response.SIGNED_IN)
+ this._addOSMLocation();
+ });
+
+ return;
+ }
+
+ this._addOSMLocation();
+ }
+
+ _addOSMLocation() {
+ let osmEdit = Application.osmEdit;
+ let viewport = this.map.viewport;
+
+ if (viewport.zoom_level < OSMEdit.MIN_ADD_LOCATION_ZOOM_LEVEL) {
+ let zoomInDialog =
+ new ZoomInDialog({ longitude: this._longitude,
+ latitude: this._latitude,
+ map: this.map,
+ transient_for: this._mainWindow,
+ modal: true });
+
+ zoomInDialog.connect('response', () => zoomInDialog.destroy());
+ zoomInDialog.show();
+ return;
+ }
+
+ let dialog =
+ osmEdit.createEditNewDialog(this._mainWindow,
+ this._latitude, this._longitude);
+
+ dialog.show();
+ dialog.connect('response', (dialog, response) => {
+ dialog.destroy();
+ if (response === OSMEditDialog.Response.UPLOADED) {
+ Utils.showDialog(_("Location was added to the map, note that it may take a while before it
shows on the map and in search results."),
+ Gtk.MessageType.INFO, this._mainWindow);
+ }
+ });
+ }
}
GObject.registerClass({
diff --git a/src/org.gnome.Maps.src.gresource.xml.in b/src/org.gnome.Maps.src.gresource.xml.in
index 84abec3f..5ae187da 100644
--- a/src/org.gnome.Maps.src.gresource.xml.in
+++ b/src/org.gnome.Maps.src.gresource.xml.in
@@ -5,7 +5,6 @@
<file>application.js</file>
<file>boundingBox.js</file>
<file>color.js</file>
- <file>contextMenu.js</file>
<file>constants.js</file>
<file>epaf.js</file>
<file>exportViewDialog.js</file>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]