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



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

    dragndrop

 src/routeQuery.js |   10 +++++
 src/sidebar.js    |  114 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 0 deletions(-)
---
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..9970916 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;
@@ -103,6 +107,8 @@ const Sidebar = new Lang.Class({
         query.addPoint(0);
         query.addPoint(1);
 
+        this._offscreen = new Gtk.OffscreenWindow({ visible: true,
+                                                    width_request: 320 });
         this.add(ui.sidebar);
     },
 
@@ -178,6 +184,114 @@ const Sidebar = new Lang.Class({
                 Application.routeService.query.removePoint(row.get_index());
             });
         }
+
+        this._initRouteDragAndDrop(routeEntry);
+    },
+
+    // Set up drag and drop between route entries. The drag source is from a
+    // GtkEventBox that contains the start/end icon next to the entry. And
+    // The drag destination is the grid in each entry row.
+    _initRouteDragAndDrop: function(routeEntry) {
+        let query = Application.routeService.query;
+        let dragIcon = routeEntry.iconEventBox;
+        let index = query.getIndex(routeEntry.point);
+        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(widget, context, data) {
+            this._draggedPoint = routeEntry.point;
+
+            this._entryList.remove(row);
+            this._offscreen.add(row);
+            this._offscreen.show_all();
+            
+            if(routeEntry.type !== RouteEntry.Type.TO)
+                routeEntry.button.hide();
+
+            row.app_paintable = true;
+            let id = row.connect('draw', function(widget, cr) {
+                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);
+
+                row.disconnect(id);
+            });
+
+            // Wait for draw
+            this._offscreen.connect('damage-event', (function() {
+                Gtk.drag_set_icon_surface(context,
+                                          this._offscreen.get_surface(), 0, 0);
+            }).bind(this));
+        }).bind(this));
+
+        dragIcon.connect('drag-end', (function(widget, context, data) {
+            this._draggedPoint = null;
+
+            Mainloop.idle_add((function() {
+                this._offscreen.remove(row);
+
+                if(routeEntry.type !== RouteEntry.Type.TO)
+                    routeEntry.button.show();
+
+                this._entryList.insert(row, index);
+            }).bind(this));
+        }).bind(this));
+
+        row.connect('drag-leave', (function(widget) {
+            row.opacity = 1.0;
+        }).bind(this));
+
+        row.connect('drag-motion', (function(widget, context, x, y, time) {
+            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;
+        }).bind(this));
+
+        row.connect('drag-drop', (function(widget, context, x, y, time) {
+            let srcPlace = this._draggedPoint.place;
+            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;
+        }).bind(this));
     },
 
     _initInstructionList: function() {


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