[gnome-maps/wip/mlundblad/transit-routing: 8/23] Add list box row to display a leg of a transit itinerary



commit 81852cbf890b479364baf7cf404d8a9cae2e349f
Author: Marcus Lundblad <ml update uu se>
Date:   Mon Jun 6 23:19:56 2016 +0200

    Add list box row to display a leg of a transit itinerary
    
    This list box class is used to render a "leg" of an itinerary
    when "diving in" to a particular itinerary.
    I.e. part of a journey such as "Walk 500 m" or "Bus 42 leaving at 12:00".
    
    https://bugzilla.gnome.org/show_bug.cgi?id=755808

 data/gnome-maps.css                    |   10 ++
 data/org.gnome.Maps.data.gresource.xml |    1 +
 data/ui/transit-leg-row.ui             |  239 ++++++++++++++++++++++++++++++++
 po/POTFILES.in                         |    1 +
 src/org.gnome.Maps.src.gresource.xml   |    1 +
 src/transitLegRow.js                   |  234 +++++++++++++++++++++++++++++++
 6 files changed, 486 insertions(+), 0 deletions(-)
---
diff --git a/data/gnome-maps.css b/data/gnome-maps.css
index 5ff11b5..5f500fe 100644
--- a/data/gnome-maps.css
+++ b/data/gnome-maps.css
@@ -95,3 +95,13 @@
     min-height: 16px;
     font-size: smaller;
 }
+
+.small-circular {
+  border-radius: 14px;
+  min-width: 14px;
+  min-height: 14px;
+  padding: 0px 0px;
+  background-color: transparent;
+  -gtk-outline-radius: 14px;
+}
+
diff --git a/data/org.gnome.Maps.data.gresource.xml b/data/org.gnome.Maps.data.gresource.xml
index 33cbea1..ebf23a5 100644
--- a/data/org.gnome.Maps.data.gresource.xml
+++ b/data/org.gnome.Maps.data.gresource.xml
@@ -32,6 +32,7 @@
     <file preprocess="xml-stripblanks">ui/social-place-more-results-row.ui</file>
     <file preprocess="xml-stripblanks">ui/social-place-row.ui</file>
     <file preprocess="xml-stripblanks">ui/transit-itinerary-row.ui</file>
+    <file preprocess="xml-stripblanks">ui/transit-leg-row.ui</file>
     <file preprocess="xml-stripblanks">ui/transit-route-label.ui</file>
     <file preprocess="xml-stripblanks">ui/user-location-bubble.ui</file>
     <file preprocess="xml-stripblanks">ui/zoom-control.ui</file>
diff --git a/data/ui/transit-leg-row.ui b/data/ui/transit-leg-row.ui
new file mode 100644
index 0000000..7cc59e2
--- /dev/null
+++ b/data/ui/transit-leg-row.ui
@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="utf-8"?>
+<interface>
+  <requires lib="gtk+" version="3.14"/>
+  <template class="Gjs_TransitLegRow" parent="GtkListBoxRow">
+    <property name="visible">True</property>
+    <property name="can-focus">False</property>
+    <child>
+      <object class="GtkEventBox" id="eventBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <child>
+          <object class="GtkGrid" id="grid">
+            <property name="visible">True</property>
+            <property name="margin-top">0</property>
+            <property name="margin-bottom">0</property>
+            <property name="row-spacing">3</property>
+            <child>
+              <object class="GtkImage" id="modeImage">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="margin-start">12</property>
+                <property name="margin-end">12</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">0</property>
+                <property name="height">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="fromLabel">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="halign">GTK_ALIGN_START</property>
+                <property name="max-width-chars">25</property>
+                <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkGrid" id="routeGrid">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="timeLabel">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="margin-start">6</property>
+                <property name="margin-end">18</property>
+                <property name="hexpand">True</property>
+                <property name="halign">GTK_ALIGN_END</property>
+              </object>
+              <packing>
+                <property name="left-attach">2</property>
+                <property name="top-attach">0</property>
+                <property name="height">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRevealer" id="detailsRevealer">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <property name="margin-left">15</property>
+                    <property name="margin-right">15</property>
+                    <property name="row-spacing">1</property>
+                    <child>
+                      <object class="GtkLabel" id="agencyLabel">
+                        <property name="visible">False</property>
+                        <property name="use-markup">True</property>
+                        <property name="halign">GTK_ALIGN_START</property>
+                      </object>
+                      <packing>
+                        <property name="top-attach">0</property>
+                        <property name="left-attach">0</property>
+                        <property name="width">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkSeparator">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="valign">GTK_ALIGN_CENTER</property>
+                      </object>
+                      <packing>
+                        <property name="top-attach">1</property>
+                        <property name="left-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="collapsButton">
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="tooltip-text" translatable="yes">Show intermediate stops and 
information</property>
+                        <style>
+                          <class name="small-circular"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <property name="icon-name">go-up-symbolic</property>
+                            <property name="pixel-size">8</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="top-attach">1</property>
+                        <property name="left-attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkSeparator">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="valign">GTK_ALIGN_CENTER</property>
+                      </object>
+                      <packing>
+                        <property name="top-attach">1</property>
+                        <property name="left-attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkListBox" id="instructionList">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="top-attach">2</property>
+                        <property name="left-attach">0</property>
+                        <property name="width">3</property>
+                      </packing>
+                    </child>
+
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="top-attach">3</property>
+                <property name="left-attach">0</property>
+                <property name="width">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkStack" id="footerStack">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <child>
+                      <object class="GtkSeparator">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="valign">GTK_ALIGN_CENTER</property>
+                      </object>
+                      <packing>
+                        <property name="top-attach">0</property>
+                        <property name="left-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="expandButton">
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="tooltip-text" translatable="yes">Show intermediate stops and 
information</property>
+                        <style>
+                          <class name="small-circular"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <property name="icon-name">go-down-symbolic</property>
+                            <property name="pixel-size">8</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="top-attach">0</property>
+                        <property name="left-attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkSeparator">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="valign">GTK_ALIGN_CENTER</property>
+                      </object>
+                      <packing>
+                        <property name="top-attach">0</property>
+                        <property name="left-attach">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="name">expander</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkSeparator">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="valign">GTK_ALIGN_CENTER</property>
+                  </object>
+                  <packing>
+                    <property name="name">separator</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="top-attach">4</property>
+                <property name="left-attach">0</property>
+                <property name="width">3</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4da0060..5eaa2c9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -50,6 +50,7 @@ src/routeService.js
 src/sendToDialog.js
 src/shapeLayer.js
 src/sidebar.js
+src/transitLegRow.js
 src/transitPlan.js
 src/translations.js
 src/utils.js
diff --git a/src/org.gnome.Maps.src.gresource.xml b/src/org.gnome.Maps.src.gresource.xml
index 2ab28f4..8bcc629 100644
--- a/src/org.gnome.Maps.src.gresource.xml
+++ b/src/org.gnome.Maps.src.gresource.xml
@@ -76,6 +76,7 @@
     <file>storedRoute.js</file>
     <file>togeojson/togeojson.js</file>
     <file>transitItineraryRow.js</file>
+    <file>transitLegRow.js</file>
     <file>transitOptions.js</file>
     <file>transitPlan.js</file>
     <file>transitRouteLabel.js</file>
diff --git a/src/transitLegRow.js b/src/transitLegRow.js
new file mode 100644
index 0000000..c1e813c
--- /dev/null
+++ b/src/transitLegRow.js
@@ -0,0 +1,234 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * Copyright (c) 2016 Marcus Lundblad
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Marcus Lundblad <ml update uu se>
+ */
+
+const Lang = imports.lang;
+
+const _ = imports.gettext.gettext;
+
+const Gdk = imports.gi.Gdk;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+
+const InstructionRow = imports.instructionRow;
+const TransitRouteLabel = imports.transitRouteLabel;
+const TransitStopRow = imports.transitStopRow;
+const Utils = imports.utils;
+
+const TransitLegRow = new Lang.Class({
+    Name: 'TransitLegRow',
+    Extends: Gtk.ListBoxRow,
+    Template: 'resource:///org/gnome/Maps/ui/transit-leg-row.ui',
+    InternalChildren: ['grid',
+                       'modeImage',
+                       'fromLabel',
+                       'routeGrid',
+                       'timeLabel',
+                       'footerStack',
+                       'expandButton',
+                       'detailsRevealer',
+                       'agencyLabel',
+                       'collapsButton',
+                       'instructionList',
+                       'eventBox'],
+
+    _init: function(params) {
+        this._leg = params.leg;
+        delete params.leg;
+
+        this._start = params.start;
+        delete params.start;
+
+        this._mapView = params.mapView;
+        delete params.mapView;
+
+        this._print = params.print;
+        delete params.print;
+
+        this.parent();
+
+        this._modeImage.icon_name = this._leg.iconName;
+        if (this._start) {
+            if (this._leg.from) {
+                /* Translators: this is a format string indicating instructions
+                 * starting a journey at the address given as the parameter */
+                this._fromLabel.label = _("Start at %s").format(this._leg.from);
+            } else {
+                /* Translators: this indicates starting a journey at a location
+                 * with no set name (such as when the user started routing from
+                 * an arbitrary point on the map) */
+                this._fromLabel.label = _("Start");
+            }
+        } else {
+            this._fromLabel.label = this._leg.from;
+        }
+
+        if (this._leg.transit) {
+            let routeLabel =
+                new TransitRouteLabel.TransitRouteLabel({ leg: this._leg });
+
+            routeLabel.margin_end = 3;
+            routeLabel.hexpand = false;
+            routeLabel.halign = Gtk.Align.START;
+            this._routeGrid.add(routeLabel);
+        }
+
+        let maxWidthChars = this._print ? -1 : 20;
+        let headsignLabel = new Gtk.Label({ visible: true, can_focus: false,
+                                            use_markup: true, hexpand: true,
+                                            max_width_chars: maxWidthChars,
+                                            ellipsize: Pango.EllipsizeMode.END,
+                                            halign: Gtk.Align.START });
+        if (this._leg.transit && this._leg.headsign) {
+            headsignLabel.label =
+                '<span size="small">%s</span>'.format(this._leg.headsign);
+        } else if (!this._leg.transit) {
+            /* Translators: this is a format string indicating walking a certain
+             * distance, with the distance expression being the %s placeholder */
+            let label =
+                _("Walk %s").format(Utils.prettyDistance(this._leg.distance));
+            headsignLabel.label =
+                '<span size="small">%s</span>'.format(label);
+        }
+
+        headsignLabel.get_style_context().add_class('dim-label');
+        this._routeGrid.add(headsignLabel);
+
+        if (!this._leg.transit && this._start)
+            this._timeLabel.label = this._leg.prettyPrintDepartureTime();
+        else
+            this._timeLabel.label = this._leg.prettyPrintTimeInterval();
+
+        if (this._leg.transit) {
+            this._agencyLabel.visible = true;
+
+            if (this._leg.agencyUrl) {
+                let url = GLib.markup_escape_text(this._leg.agencyUrl, -1);
+                /* we need to double-escape the tooltip text, as GTK+ treats it as
+                 * markup */
+                let tooltip = GLib.markup_escape_text(url, -1);
+                this._agencyLabel.label =
+                    '<a href="%s" title="%s">%s</a>'.format(url, tooltip,
+                                                            this._leg.agencyName);
+            } else {
+                this._agencyLabel.label = this._leg.agencyName;
+            }
+        }
+
+        if (this._hasIntructions())
+            this._populateInstructions();
+        else
+            this._footerStack.visible_child_name = 'separator';
+
+        this._expandButton.connect('clicked', (function() {
+            this._expand();
+        }).bind(this));
+
+        this._collapsButton.connect('clicked', (function() {
+            this._collaps();
+        }).bind(this));
+
+        this._instructionList.connect('row-selected',(function(listbox, row) {
+            if (row) {
+                if (row.turnPoint)
+                    this._mapView.showTurnPoint(row.turnPoint);
+                else
+                    this._mapView.showTransitStop(row.stop, this._leg);
+            }
+        }).bind(this));
+
+        this._eventBox.connect('event', (function(widget, event) {
+            this._onEvent(event);
+            return true;
+        }).bind(this));
+
+        this._isExpanded = false;
+
+        /* hide expand/collaps row in printing mode */
+        this._footerStack.visible = !this._print;
+
+        /* allow more space for the departure label when printing */
+        if (this._print)
+            this._fromLabel.max_width_chars = -1;
+    },
+
+    _onEvent: function(event) {
+        let [isButton, button] = event.get_button();
+        let type = event.get_event_type();
+
+        if (isButton && button === 1 && !this._isExpanded &&
+            type === Gdk.EventType.BUTTON_PRESS) {
+            this._mapView.view.zoom_level = 16;
+            this._mapView.view.center_on(this._leg.fromCoordinate[0],
+                                         this._leg.fromCoordinate[1]);
+            if (this._hasIntructions())
+                this._expand();
+        }
+    },
+
+    _expand: function() {
+        this._footerStack.visible_child_name = 'separator';
+        this._detailsRevealer.reveal_child = true;
+        /* collaps the time label down to just show the start time when
+         * revealing intermediate stop times, as the arrival time is displayed
+         * at the last stop */
+        this._timeLabel.label = this._leg.prettyPrintDepartureTime();
+        this._isExpanded = true;
+    },
+
+    _collaps: function() {
+        this._footerStack.visible_child_name = 'expander';
+        this._detailsRevealer.reveal_child = false;
+        this._timeLabel.label = this._leg.prettyPrintTimeInterval();
+        this._isExpanded = false;
+    },
+
+    _hasIntructions: function() {
+        return this._leg.transit || this._leg.walkingInstructions;
+    },
+
+    _populateInstructions: function() {
+        if (this._leg.transit) {
+            let stops = this._leg.intermediateStops;
+            for (let index = 0; index < stops.length; index++) {
+                 let stop = stops[index];
+                 let row =
+                    new TransitStopRow.TransitStopRow({ visible: true,
+                                                        stop: stop,
+                                                        final: index === stops.length - 1 });
+                this._instructionList.add(row);
+            }
+        } else {
+            /* don't output the starting and ending instructions from the walk
+             * route, since these are explicitely added by the itinerary */
+            for (let index = 1;
+                 index < this._leg.walkingInstructions.length - 1;
+                 index++) {
+                let instruction = this._leg.walkingInstructions[index];
+                let row =
+                    new InstructionRow.InstructionRow({ visible: true,
+                                                        turnPoint: instruction });
+
+                this._instructionList.add(row);
+            }
+        }
+    }
+});


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]