[gtk/prop-list: 5/5] columnview: Interactive column reordering



commit f1932b41455fe02930bc069638f03a7ba0fa9415
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Dec 20 17:29:35 2019 -0500

    columnview: Interactive column reordering
    
    Allow rearranging columns by dragging, in the same
    way the treeview does.
    
    We add the "dnd" style class to the header while
    it is dragged, and we move the header of the dragged
    column to the end of its parents children, so that
    it gets drawn on top.

 gtk/gtkcolumnview.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 115 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 356b9712dc..327b4402d7 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -38,6 +38,7 @@
 #include "gtkadjustment.h"
 #include "gtkgesturedrag.h"
 #include "gtkeventcontrollermotion.h"
+#include "gtkdnd.h"
 
 /**
  * SECTION:gtkcolumnview
@@ -71,8 +72,11 @@ struct _GtkColumnView
   GtkAdjustment *hadjustment;
 
   gboolean in_column_resize;
+  gboolean in_column_reorder;
   int drag_pos;
   int drag_x;
+  int drag_offset;
+  int drag_column_x;
 };
 
 struct _GtkColumnViewClass
@@ -221,6 +225,9 @@ gtk_column_view_allocate_columns (GtkColumnView *self,
             col_size = sizes[i].natural_size;
 
           gtk_column_view_column_allocate (column, x, col_size);
+          if (self->in_column_reorder && i == self->drag_pos)
+            gtk_column_view_column_set_header_position (column, self->drag_x);
+
           x += col_size;
         }
 
@@ -549,8 +556,13 @@ header_drag_begin (GtkGestureDrag *gesture,
     {
       GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
 
+      if (!gtk_column_view_column_get_visible (column))
+        {
+          g_object_unref (column);
+          continue;
+        }
+
       if (gtk_column_view_column_get_resizable (column) &&
-          gtk_column_view_column_get_visible (column) &&
           gtk_column_view_column_in_resize_rect (column, start_x, start_y))
         {
           int size;
@@ -562,9 +574,24 @@ header_drag_begin (GtkGestureDrag *gesture,
           self->drag_pos = i;
           self->drag_x = start_x - size;
           self->in_column_resize = TRUE;
+
+          g_object_unref (column);
+          break;
+        }
+
+      if (gtk_column_view_column_in_header (column, start_x, start_y))
+        {
+          int pos;
+
+          gtk_column_view_column_get_allocation (column, &pos, NULL);
+          self->drag_pos = i;
+          self->drag_offset = start_x - pos;
+
+          g_object_unref (column);
+          break;
         }
 
-      g_clear_object (&column);
+      g_object_unref (column);
     }
 }
 
@@ -574,7 +601,49 @@ header_drag_end (GtkGestureDrag *gesture,
                  double          offset_y,
                  GtkColumnView  *self)
 {
-  self->in_column_resize = FALSE;
+  double start_x, x;
+
+  gtk_gesture_drag_get_start_point (gesture, &start_x, NULL);
+  x = start_x + offset_x;
+
+  if (self->in_column_resize)
+    {
+      self->in_column_resize = FALSE;
+    }
+  else if (self->in_column_reorder)
+    {
+      GtkColumnViewColumn *column;
+      GtkWidget *header;
+      int i;
+
+      column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
+      header = gtk_column_view_column_get_header (column);
+      gtk_style_context_remove_class (gtk_widget_get_style_context (header), "dnd");
+
+      for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
+        {
+          GtkColumnViewColumn *col = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
+
+          if (gtk_column_view_column_get_visible (col))
+            {
+              int pos, size;
+
+              gtk_column_view_column_get_allocation (col, &pos, &size);
+              if (pos <= x && x <= pos + size)
+                {
+                  gtk_column_view_insert_column (self, i, column);
+                  g_object_unref (col);
+                  break;
+                }
+            }
+
+          g_object_unref (col);
+        }
+
+      g_object_unref (column);
+
+      self->in_column_reorder = FALSE;
+    }
 }
 
 static void
@@ -592,6 +661,28 @@ drag_update_resize_column (GtkColumnView *self,
   g_object_unref (column);
 }
 
+static void
+drag_update_drag_column (GtkColumnView *self,
+                         double         x,
+                         double         y)
+{
+  GtkColumnViewColumn *column;
+  int width;
+  int size;
+
+  x += gtk_adjustment_get_value (self->hadjustment);
+  width = gtk_widget_get_allocated_width (GTK_WIDGET (self->header));
+
+  column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
+  gtk_column_view_column_get_allocation (column, NULL, &size);
+
+  self->drag_x = CLAMP (x - self->drag_offset, 0, width - size);
+
+  gtk_widget_queue_allocate (GTK_WIDGET (self));
+  gtk_column_view_column_queue_resize (column);
+  g_object_unref (column);
+}
+
 static void
 header_drag_update (GtkGestureDrag *gesture,
                     double          offset_x,
@@ -601,12 +692,33 @@ header_drag_update (GtkGestureDrag *gesture,
   double start_x, start_y;
   double x, y;
 
+  if (!self->in_column_resize && !self->in_column_reorder)
+    {
+      if (gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, 0))
+        {
+          GtkColumnViewColumn *column;
+          GtkWidget *header;
+
+          gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+
+          column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
+          header = gtk_column_view_column_get_header (column);
+          gtk_widget_insert_after (header, self->header, gtk_widget_get_last_child (self->header));
+          gtk_style_context_add_class (gtk_widget_get_style_context (header), "dnd");
+          g_object_unref (column);
+
+          self->in_column_reorder = TRUE;
+        }
+    }
+
   gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
   x = start_x + offset_x;
   y = start_y + offset_y;
 
   if (self->in_column_resize)
     drag_update_resize_column (self, x, y);
+  else if (self->in_column_reorder)
+    drag_update_drag_column (self, x, y);
 }
 
 static void


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