[recipes/inline-editing] Initial dnd reordering support



commit c89dd8c3b9de3d3a8c7d2044ab5a3d44994bef56
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Apr 21 21:01:47 2017 -0400

    Initial dnd reordering support
    
    Instead of the up/down arrows, show a drag handle, and
    support drag-and-drop reordering. As a little benefit,
    we can now support reordering between different lists.

 src/gr-ingredients-viewer-row.c  |   97 +++++++++++++++++++++++++++++++++----
 src/gr-ingredients-viewer-row.ui |   46 ++----------------
 src/gr-ingredients-viewer.c      |   27 ++++++-----
 src/recipes-dark.css             |    5 ++
 src/recipes-light.css            |    5 ++
 5 files changed, 117 insertions(+), 63 deletions(-)
---
diff --git a/src/gr-ingredients-viewer-row.c b/src/gr-ingredients-viewer-row.c
index c8dd6a2..a8b0cea 100644
--- a/src/gr-ingredients-viewer-row.c
+++ b/src/gr-ingredients-viewer-row.c
@@ -24,6 +24,7 @@
 #include <glib/gi18n.h>
 
 #include "gr-ingredients-viewer-row.h"
+#include "gr-ingredients-viewer.h"
 #include "gr-ingredient.h"
 
 
@@ -34,6 +35,7 @@ struct _GrIngredientsViewerRow
         GtkWidget *unit_label;
         GtkWidget *ingredient_label;
         GtkWidget *buttons_stack;
+        GtkWidget *ebox;
 
         char *amount;
         char *unit;
@@ -228,15 +230,8 @@ emit_delete (GrIngredientsViewerRow *row)
 }
 
 static void
-emit_move_up (GrIngredientsViewerRow *row)
+drag_handle_clicked (GrIngredientsViewerRow *row)
 {
-        g_signal_emit (row, signals[MOVE], 0, -1);
-}
-
-static void
-emit_move_down (GrIngredientsViewerRow *row)
-{
-        g_signal_emit (row, signals[MOVE], 0, 1);
 }
 
 static void
@@ -294,17 +289,90 @@ gr_ingredients_viewer_row_class_init (GrIngredientsViewerRowClass *klass)
                                       0,
                                       NULL, NULL,
                                       NULL,
-                                      G_TYPE_NONE, 1, G_TYPE_INT);
+                                      G_TYPE_NONE, 1, GR_TYPE_INGREDIENTS_VIEWER_ROW);
 
         gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Recipes/gr-ingredients-viewer-row.ui");
 
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewerRow, unit_label);
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewerRow, ingredient_label);
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewerRow, buttons_stack);
+        gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewerRow, ebox);
 
         gtk_widget_class_bind_template_callback (widget_class, emit_delete);
-        gtk_widget_class_bind_template_callback (widget_class, emit_move_up);
-        gtk_widget_class_bind_template_callback (widget_class, emit_move_down);
+        gtk_widget_class_bind_template_callback (widget_class, drag_handle_clicked);
+}
+
+static GtkTargetEntry entries[] = {
+        { "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 }
+};
+
+static void
+drag_begin (GtkWidget      *widget,
+            GdkDragContext *context,
+            gpointer        data)
+{
+        GtkAllocation alloc;
+        cairo_surface_t *surface;
+        cairo_t *cr;
+        GtkWidget *row;
+        int x, y;
+
+        row = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
+
+        gtk_widget_get_allocation (row, &alloc);
+        surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
+        cr = cairo_create (surface);
+
+        gtk_style_context_add_class (gtk_widget_get_style_context (row), "during-dnd");
+        gtk_widget_draw (row, cr);
+        gtk_style_context_remove_class (gtk_widget_get_style_context (row), "during-dnd");
+
+        gtk_widget_translate_coordinates (widget, row, 0, 0, &x, &y);
+        cairo_surface_set_device_offset (surface, -x, -y);
+        gtk_drag_set_icon_surface (context, surface);
+
+        cairo_destroy (cr);
+        cairo_surface_destroy (surface);
+}
+
+void
+drag_data_get (GtkWidget        *widget,
+               GdkDragContext   *context,
+               GtkSelectionData *selection_data,
+               guint             info,
+               guint             time,
+               gpointer          data)
+{
+        gtk_selection_data_set (selection_data,
+                                gdk_atom_intern_static_string ("GTK_LIST_BOX_ROW"),
+                                32,
+                                (const guchar *)&widget,
+                                sizeof (gpointer));
+}
+
+static void
+drag_data_received (GtkWidget        *widget,
+                    GdkDragContext   *context,
+                    gint              x,
+                    gint              y,
+                    GtkSelectionData *selection_data,
+                    guint             info,
+                    guint32           time,
+                    gpointer          data)
+{
+        GtkWidget *target;
+        GtkWidget *row;
+        GtkWidget *source;
+
+        target = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
+
+        row = (gpointer)* (gpointer*)gtk_selection_data_get_data (selection_data);
+        source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW);
+
+        if (target == source)
+                return;
+
+        g_signal_emit (source, signals[MOVE], 0, target);
 }
 
 static void
@@ -312,4 +380,11 @@ gr_ingredients_viewer_row_init (GrIngredientsViewerRow *self)
 {
         gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
         gtk_widget_init_template (GTK_WIDGET (self));
+
+        gtk_drag_source_set (self->ebox, GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE);
+        g_signal_connect (self->ebox, "drag-begin", G_CALLBACK (drag_begin), NULL);
+        g_signal_connect (self->ebox, "drag-data-get", G_CALLBACK (drag_data_get), NULL);
+
+        gtk_drag_dest_set (GTK_WIDGET (self), GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE);
+        g_signal_connect (self, "drag-data-received", G_CALLBACK (drag_data_received), NULL);
 }
diff --git a/src/gr-ingredients-viewer-row.ui b/src/gr-ingredients-viewer-row.ui
index 0608480..ae66467 100644
--- a/src/gr-ingredients-viewer-row.ui
+++ b/src/gr-ingredients-viewer-row.ui
@@ -49,42 +49,7 @@
                   <object class="GtkButton">
                     <property name="visible">1</property>
                     <property name="relief">none</property>
-                    <signal name="clicked" handler="emit_move_up" swapped="yes"/>
-                    <style>
-                      <class name="image-button"/>
-                      <class name="circular"/>
-                    </style>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">1</property>
-                        <property name="icon-name">go-up-symbolic</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkButton">
-                    <property name="visible">1</property>
-                    <property name="relief">none</property>
-                    <signal name="clicked" handler="emit_move_down" swapped="yes"/>
-                    <style>
-                      <class name="image-button"/>
-                      <class name="circular"/>
-                    </style>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">1</property>
-                        <property name="icon-name">go-down-symbolic</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkButton">
-                    <property name="visible">1</property>
-                    <property name="relief">none</property>
+                    <signal name="clicked" handler="emit_delete" swapped="yes"/>
                     <style>
                       <class name="image-button"/>
                       <class name="circular"/>
@@ -92,17 +57,17 @@
                     <child>
                       <object class="GtkImage">
                         <property name="visible">1</property>
-                        <property name="icon-name">document-edit-symbolic</property>
+                        <property name="icon-name">user-trash-symbolic</property>
                         <property name="icon-size">1</property>
                       </object>
                     </child>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkButton">
+                  <object class="GtkButton" id="ebox">
                     <property name="visible">1</property>
                     <property name="relief">none</property>
-                    <signal name="clicked" handler="emit_delete" swapped="yes"/>
+                    <signal name="clicked" handler="drag_handle_clicked" swapped="yes"/>
                     <style>
                       <class name="image-button"/>
                       <class name="circular"/>
@@ -110,8 +75,9 @@
                     <child>
                       <object class="GtkImage">
                         <property name="visible">1</property>
-                        <property name="icon-name">user-trash-symbolic</property>
+                        <property name="icon-name">open-menu-symbolic</property>
                         <property name="icon-size">1</property>
+                        <property name="margin">4</property>
                       </object>
                     </child>
                   </object>
diff --git a/src/gr-ingredients-viewer.c b/src/gr-ingredients-viewer.c
index b305a67..1084c93 100644
--- a/src/gr-ingredients-viewer.c
+++ b/src/gr-ingredients-viewer.c
@@ -200,23 +200,26 @@ delete_row (GrIngredientsViewerRow *row,
 }
 
 static void
-move_row (GrIngredientsViewerRow *row,
-          int                     steps,
-          GrIngredientsViewer    *viewer)
+move_row (GtkWidget           *source,
+          GtkWidget           *target,
+          GrIngredientsViewer *viewer)
 {
-        GtkWidget *list;
+        GtkWidget *source_parent;
+        GtkWidget *target_parent;
         int index;
 
-        list = gtk_widget_get_parent (GTK_WIDGET (row));
-        index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (row));
-        gtk_list_box_unselect_row (GTK_LIST_BOX (list), GTK_LIST_BOX_ROW (row));
+        index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
+
+        source_parent = gtk_widget_get_parent (source);
+        target_parent = gtk_widget_get_parent (target);
+
+        g_object_ref (source);
+        gtk_container_remove (GTK_CONTAINER (source_parent), source);
+        gtk_list_box_insert (GTK_LIST_BOX (target_parent), source, index);
+        g_object_unref (source);
 
-        g_object_ref (row);
-        gtk_container_remove (GTK_CONTAINER (list), GTK_WIDGET (row));
-        gtk_list_box_insert (GTK_LIST_BOX (list), GTK_WIDGET (row), index + steps);
-        g_object_unref (row);
+        gtk_list_box_select_row (GTK_LIST_BOX (target_parent), GTK_LIST_BOX_ROW (source));
 
-        gtk_list_box_select_row (GTK_LIST_BOX (list), GTK_LIST_BOX_ROW (row));
         g_object_notify (G_OBJECT (viewer), "ingredients");
 }
 
diff --git a/src/recipes-dark.css b/src/recipes-dark.css
index 7ee631e..f308e10 100644
--- a/src/recipes-dark.css
+++ b/src/recipes-dark.css
@@ -25,3 +25,8 @@
   background: #868d94;
 }
 
+.during-dnd {
+  background: #232729;
+  border: 1px solid alpha(white, 0.3);
+  outline-width: 0;
+}
diff --git a/src/recipes-light.css b/src/recipes-light.css
index 7b287f8..bad8565 100644
--- a/src/recipes-light.css
+++ b/src/recipes-light.css
@@ -23,3 +23,8 @@
   background: #cbd6e1;
 }
 
+.during-dnd {
+  background: white;
+  border: 1px solid alpha(black, 0.3);
+  outline-width: 0;
+}


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