[gnome-maps/wip/drag-n-drop] dragndrop



commit fea39866138366e93e04c270534707fe3674dc39
Author: Jonas Danielsson <jonas threetimestwo org>
Date:   Thu Nov 27 04:13:24 2014 -0500

    dragndrop

 data/gnome-maps.css |    4 ++
 src/route-entry.ui  |   37 +++++----------
 src/routeEntry.js   |   17 ++++---
 src/routeQuery.js   |   10 ++++
 src/sidebar.js      |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 158 insertions(+), 33 deletions(-)
---
diff --git a/data/gnome-maps.css b/data/gnome-maps.css
index d655e3a..fdb4899 100644
--- a/data/gnome-maps.css
+++ b/data/gnome-maps.css
@@ -2,6 +2,10 @@
     padding: 5px;
 }
 
+#dragged-entry {
+    color: #939695
+}
+
 .layer-radio-button {
     background-image: none;
     padding: 0px;
diff --git a/src/route-entry.ui b/src/route-entry.ui
index 0615e37..72c57c1 100644
--- a/src/route-entry.ui
+++ b/src/route-entry.ui
@@ -25,35 +25,22 @@
       <object class="GtkGrid" id="entryGrid">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="hexpand">True</property>
+        <property name="width-request">230</property>
+        <property name="hexpand">False</property>
       </object>
     </child>
     <child>
-      <object class="GtkGrid" id="buttonGrid">
-        <property name="visible">True</property>
+      <object class="GtkButton" id="button">
+        <property name="visible">False</property>
+        <property name="no_show_all">True</property>
+        <property name="can-focus">True</property>
+        <property name="valign">center</property>
+        <property name="height-request">31</property>
+        <property name="margin-start">5</property>
+        <property name="margin-end">10</property>
         <child>
-          <object class="GtkButton" id="button">
-            <property name="visible">False</property>
-            <property name="no_show_all">True</property>
-            <property name="can-focus">True</property>
-            <property name="valign">center</property>
-            <property name="height-request">31</property>
-            <property name="margin-start">4</property>
-            <property name="margin-end">10</property>
-            <child>
-              <object class="GtkImage" id="buttonImage">
-                <property name="visible">True</property>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkGrid" id="buttonPlaceHolder">
-            <property name="visible">False</property>
-            <property name="no_show_all">True</property>
-            <property name="margin_start">5</property>
-            <property name="margin_end">12</property>
-            <property name="width-request">31</property>
+          <object class="GtkImage" id="buttonImage">
+            <property name="visible">True</property>
           </object>
         </child>
       </object>
diff --git a/src/routeEntry.js b/src/routeEntry.js
index add85c5..a38011d 100644
--- a/src/routeEntry.js
+++ b/src/routeEntry.js
@@ -39,17 +39,16 @@ const RouteEntry = new Lang.Class({
     InternalChildren: [ 'entryGrid',
                         'icon',
                         'button',
-                        'buttonImage',
-                        'buttonPlaceHolder'],
+                        'buttonImage' ],
     
     _init: function(params) {
         this._type = params.type;
         delete params.type;
 
-        this._point = params.point;
+        this._point = params.point || null;
         delete params.point;
 
-        this._mapView = params.mapView;
+        this._mapView = params.mapView || null;
         delete params.mapView;
 
         this.parent(params);
@@ -61,9 +60,11 @@ const RouteEntry = new Lang.Class({
                                                  mapView: this._mapView,
                                                  parseOnFocusOut: true,
                                                  maxChars: 15 });
-        this.entry.bind_property('place',
-                                 this._point, 'place',
-                                 GObject.BindingFlags.BIDIRECTIONAL);
+        if (this._point) {
+            this.entry.bind_property('place',
+                                     this._point, 'place',
+                                     GObject.BindingFlags.BIDIRECTIONAL);
+        }
         this._entryGrid.add(this.entry);
 
         switch(this._type) {
@@ -78,7 +79,7 @@ const RouteEntry = new Lang.Class({
                 break;
             case Type.TO:
                 this._icon.icon_name = 'maps-point-end-symbolic';
-                this._buttonPlaceHolder.show();
+                this._button.hide();
                 break;
         }
     },
diff --git a/src/routeQuery.js b/src/routeQuery.js
index 554d68b..5eac0c6 100644
--- a/src/routeQuery.js
+++ b/src/routeQuery.js
@@ -111,6 +111,16 @@ const RouteQuery = new Lang.Class({
         }
     },
 
+    getIndex: function(point) {
+        for (let i = 0; i < this._points.length; i++) {
+            if (this._points[i] === point) {
+                return i;
+            }
+        }
+
+        return -1;
+    },
+
     set transportation(transportation) {
         this._transportation = transportation;
         this.notify('transportation');
diff --git a/src/sidebar.js b/src/sidebar.js
index 8695f32..97231cf 100644
--- a/src/sidebar.js
+++ b/src/sidebar.js
@@ -21,9 +21,12 @@
  *         Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
+const Cairo = imports.cairo;
+const Gdk = imports.gi.Gdk;
 const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
 const Lang = imports.lang;
+const Mainloop = imports.mainloop;
 const _ = imports.gettext.gettext;
 
 const Application = imports.application;
@@ -96,6 +99,7 @@ const Sidebar = new Lang.Class({
         this._initTransportationToggles(ui.modePedestrianToggle,
                                         ui.modeBikeToggle,
                                         ui.modeCarToggle);
+
         this._initQuerySignals(ui.viaGridContainer);
 
         let query = Application.routeService.query;
@@ -178,6 +182,8 @@ const Sidebar = new Lang.Class({
                 Application.routeService.query.removePoint(row.get_index());
             });
         }
+
+        this._initRouteDragAndDrop(routeEntry);
     },
 
     _initInstructionList: function() {
@@ -228,5 +234,122 @@ const Sidebar = new Lang.Class({
 
         this._timeInfo.label = '';
         this._distanceInfo.label = '';
+    },
+
+    _onDragDrop: function(row, context, x, y, time) {
+        let routeEntry = row.get_child();
+        let srcPlace = this._draggedPoint.place;
+        let query = Application.routeService.query;
+        let srcIndex = query.getIndex(this._draggedPoint);
+        let destIndex = query.getIndex(routeEntry.point);
+        let step;
+
+        // Hold off on notifying the changes to query.points until
+        // we have re-arranged the places.
+        query.freeze_notify();
+
+        // Iterate over points and establish the new order of places
+        if (srcIndex < destIndex)
+            step = -1;
+        else
+            step = 1;
+
+        for (let i = destIndex; i !== (srcIndex + step); i += step) {
+            let tmpPlace = query.points[i].place;
+
+            query.points[i].place = srcPlace;
+            srcPlace = tmpPlace;
+        }
+
+        query.thaw_notify();
+        Gtk.drag_finish(context, true, false, time);
+        return true;
+    },
+
+    // Set the opacity of the row we are currently dragging above
+    // to semi transparent.
+    _onDragMotion: function(row, context, x, y, time) {
+        let routeEntry = row.get_child();
+
+        if (this._draggedPoint && this._draggedPoint !== routeEntry.point) {
+            row.opacity = 0.6;
+            Gdk.drag_status(context, Gdk.DragAction.MOVE, time);
+        } else
+            Gdk.drag_status(context, 0, time);
+        return true;
+    },
+
+    // Drag ends, show the dragged row again.
+    _onDragEnd: function(context, row) {
+        this._draggedPoint = null;
+        row.show();
+    },
+
+    // Drag begins, set the correct drag icon and hide the dragged row.
+    _onDragBegin: function(context, row) {
+        let routeEntry = row.get_child();
+        let dragEntry = this._dragWidget.get_child();
+
+        this._draggedPoint = routeEntry.point;
+        row.hide();
+        dragEntry.entry.text = routeEntry.entry.text;
+        Gtk.drag_set_icon_surface(context,
+                                  this._dragWidget.get_surface(), 0, 0);
+    },
+
+    // We add RouteEntry to an OffscreenWindow and paint the backgroind
+    // of the entry to be semi transparent.
+    // We can later use the GtkOffscreenWindow method get_surface to
+    // generate our drag icon.
+    _initDragWidget: function() {
+        let dragEntry = new RouteEntry.RouteEntry({ type: RouteEntry.Type.TO });
+        this._dragWidget = new Gtk.OffscreenWindow({ visible: true,
+                                                     width_request: 320 });
+
+        dragEntry.entry.name = 'dragged-entry';
+        dragEntry.app_paintable = true;
+        dragEntry.connect('draw', (function(widget, cr) {
+            let row = this._entryList.get_row_at_index(0);
+            let style = row.get_style_context();
+            let rgba = style.get_background_color(Gtk.StateFlags.NORMAL);
+
+            cr.setSourceRGBA(rgba.red, rgba.green,  rgba.blue, 0.5);
+            cr.setOperator(Cairo.Operator.SOURCE);
+            cr.paint();
+            cr.setOperator(Cairo.Operator.OVER);
+        }).bind(this));
+
+        this._dragWidget.add(dragEntry);
+    },
+
+    // Set up drag and drop between RouteEntrys. The drag source is from a
+    // GtkEventBox that contains the start/end icon next in the entry. And
+    // the drag destination is the ListBox row.
+    _initRouteDragAndDrop: function(routeEntry) {
+        let dragIcon = routeEntry.iconEventBox;
+        let row = routeEntry.get_parent();
+
+        dragIcon.drag_source_set(Gdk.ModifierType.BUTTON1_MASK,
+                                 null,
+                                 Gdk.DragAction.MOVE);
+        dragIcon.drag_source_add_image_targets();
+
+        row.drag_dest_set(Gtk.DestDefaults.MOTION,
+                           null,
+                           Gdk.DragAction.MOVE);
+        row.drag_dest_add_image_targets();
+
+        dragIcon.connect('drag-begin', (function(icon, context) {
+            this._onDragBegin(context, row);
+        }).bind(this));
+        dragIcon.connect('drag-end', (function(icon, context) {
+            this._onDragEnd(context, row);
+        }).bind(this));
+
+        row.connect('drag-leave', row.set_opacity.bind(row, 1.0));
+        row.connect('drag-motion', this._onDragMotion.bind(this));
+        row.connect('drag-drop', this._onDragDrop.bind(this));
+
+        this._initDragWidget();
     }
 });


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