[recipes/drag-reorder] Initial dnd reordering support



commit e75163a758e1c19b5fd64fb2f1701673f99444a6
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  |   85 ++++++++++++++++++++++++++++++++++++++
 src/gr-ingredients-viewer-row.ui |   50 ++--------------------
 src/recipes-dark.css             |    5 ++
 src/recipes-light.css            |    5 ++
 4 files changed, 100 insertions(+), 45 deletions(-)
---
diff --git a/src/gr-ingredients-viewer-row.c b/src/gr-ingredients-viewer-row.c
index c8dd6a2..57b2078 100644
--- a/src/gr-ingredients-viewer-row.c
+++ b/src/gr-ingredients-viewer-row.c
@@ -34,6 +34,7 @@ struct _GrIngredientsViewerRow
         GtkWidget *unit_label;
         GtkWidget *ingredient_label;
         GtkWidget *buttons_stack;
+        GtkWidget *ebox;
 
         char *amount;
         char *unit;
@@ -301,15 +302,99 @@ gr_ingredients_viewer_row_class_init (GrIngredientsViewerRowClass *klass)
         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);
 }
 
+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);
+        g_print ("offset %d %d\n", 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;
+        int pos;
+
+        target = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
+
+        pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
+        row = (gpointer)* (gpointer*)gtk_selection_data_get_data (selection_data);
+        source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW);
+
+        g_object_ref (source);
+        gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (source)), source);
+        gtk_list_box_insert (GTK_LIST_BOX (gtk_widget_get_parent (target)), source, pos);
+        g_object_unref (source);
+}
+
 static void
 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..da276b8 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,26 +57,21 @@
                     <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="GtkEventBox" id="ebox">
                     <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"/>
-                    </style>
                     <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/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]