[gtk/prop-list: 52/57] columnview: Interactive column resizing



commit 802bf9822dfede21c4427ae847662750aaa94f28
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Dec 20 12:17:45 2019 -0500

    columnview: Interactive column resizing
    
    This copies just enough of the treeview code to
    get columns moving.

 gtk/gtkcolumnview.c              | 119 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkcolumnviewcolumn.c        |  25 ++++++--
 gtk/gtkcolumnviewcolumnprivate.h |   4 ++
 3 files changed, 144 insertions(+), 4 deletions(-)
---
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 3ca4d5be6b..356b9712dc 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -36,6 +36,8 @@
 #include "gtkwidgetprivate.h"
 #include "gtksizerequest.h"
 #include "gtkadjustment.h"
+#include "gtkgesturedrag.h"
+#include "gtkeventcontrollermotion.h"
 
 /**
  * SECTION:gtkcolumnview
@@ -67,6 +69,10 @@ struct _GtkColumnView
   GtkSorter *sorter;
 
   GtkAdjustment *hadjustment;
+
+  gboolean in_column_resize;
+  int drag_pos;
+  int drag_x;
 };
 
 struct _GtkColumnViewClass
@@ -531,9 +537,111 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
   gtk_widget_class_set_css_name (widget_class, I_("treeview"));
 }
 
+static void
+header_drag_begin (GtkGestureDrag *gesture,
+                   double          start_x,
+                   double          start_y,
+                   GtkColumnView  *self)
+{
+  int i;
+
+  for (i = 0; !self->in_column_resize && i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
+
+      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;
+
+          gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+
+          gtk_column_view_column_get_allocation (column, NULL, &size);
+          gtk_column_view_column_set_fixed_width (column, size);
+          self->drag_pos = i;
+          self->drag_x = start_x - size;
+          self->in_column_resize = TRUE;
+        }
+
+      g_clear_object (&column);
+    }
+}
+
+static void
+header_drag_end (GtkGestureDrag *gesture,
+                 double          offset_x,
+                 double          offset_y,
+                 GtkColumnView  *self)
+{
+  self->in_column_resize = FALSE;
+}
+
+static void
+drag_update_resize_column (GtkColumnView *self,
+                           double         x,
+                           double         y)
+{
+  GtkColumnViewColumn *column;
+  int new_width;
+
+  new_width = MAX (x - self->drag_x, 0);
+
+  column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
+  gtk_column_view_column_set_fixed_width (column, new_width);
+  g_object_unref (column);
+}
+
+static void
+header_drag_update (GtkGestureDrag *gesture,
+                    double          offset_x,
+                    double          offset_y,
+                    GtkColumnView  *self)
+{
+  double start_x, start_y;
+  double x, y;
+
+  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);
+}
+
+static void
+header_motion (GtkEventControllerMotion *controller,
+               double                    x,
+               double                    y,
+               GtkColumnView            *self)
+{
+  gboolean cursor_set = FALSE;
+  int i;
+
+  for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
+
+      if (gtk_column_view_column_get_resizable (column) &&
+          gtk_column_view_column_get_visible (column) &&
+          gtk_column_view_column_in_resize_rect (column, x, y))
+        {
+          gtk_widget_set_cursor_from_name (self->header, "col-resize");
+          cursor_set = TRUE;
+        }
+
+      g_object_unref (column);
+    }
+
+  if (!cursor_set)
+    gtk_widget_set_cursor (self->header, NULL);
+}
+
 static void
 gtk_column_view_init (GtkColumnView *self)
 {
+  GtkEventController *controller;
+
   self->columns = g_list_store_new (GTK_TYPE_COLUMN_VIEW_COLUMN);
 
   self->header = gtk_list_item_widget_new (NULL, "header");
@@ -541,6 +649,17 @@ gtk_column_view_init (GtkColumnView *self)
   gtk_widget_set_layout_manager (self->header, gtk_column_view_layout_new (self));
   gtk_widget_set_parent (self->header, GTK_WIDGET (self));
 
+  controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
+  g_signal_connect (controller, "drag-begin", G_CALLBACK (header_drag_begin), self);
+  g_signal_connect (controller, "drag-update", G_CALLBACK (header_drag_update), self);
+  g_signal_connect (controller, "drag-end", G_CALLBACK (header_drag_end), self);
+  gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
+  gtk_widget_add_controller (self->header, controller);
+
+  controller = gtk_event_controller_motion_new ();
+  g_signal_connect (controller, "motion", G_CALLBACK (header_motion), self);
+  gtk_widget_add_controller (self->header, controller);
+
   self->sorter = gtk_column_view_sorter_new ();
   self->factory = gtk_column_list_item_factory_new (self);
   self->listview = GTK_LIST_VIEW (gtk_list_view_new_with_factory (
diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c
index 6c80736066..58ebc7657c 100644
--- a/gtk/gtkcolumnviewcolumn.c
+++ b/gtk/gtkcolumnviewcolumn.c
@@ -813,7 +813,6 @@ gtk_column_view_column_set_fixed_width (GtkColumnViewColumn *self,
                                         int                  fixed_width)
 {
   GtkOverflow overflow;
-  GtkColumnViewCell *cell;
 
   g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
   g_return_if_fail (fixed_width >= -1);
@@ -830,13 +829,13 @@ gtk_column_view_column_set_fixed_width (GtkColumnViewColumn *self,
 
   if (overflow != gtk_widget_get_overflow (GTK_WIDGET (self->header)))
     {
+      GtkColumnViewCell *cell;
+
       if (self->header)
         gtk_widget_set_overflow (GTK_WIDGET (self->header), overflow);
 
       for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell))
-        {
-          gtk_widget_set_overflow (GTK_WIDGET (cell), overflow);
-        }
+        gtk_widget_set_overflow (GTK_WIDGET (cell), overflow);
     }
 
   gtk_column_view_column_queue_resize (self);
@@ -851,3 +850,21 @@ gtk_column_view_column_get_fixed_width (GtkColumnViewColumn *self)
 
   return self->fixed_width;
 }
+
+#define DRAG_WIDTH 6
+
+gboolean
+gtk_column_view_column_in_resize_rect (GtkColumnViewColumn *self,
+                                       double               x,
+                                       double               y)
+{
+  graphene_rect_t rect;
+
+  if (!gtk_widget_compute_bounds (self->header, GTK_WIDGET (self->view), &rect))
+    return FALSE;
+
+  rect.origin.x += rect.size.width - DRAG_WIDTH / 2;
+  rect.size.width = DRAG_WIDTH;
+
+  return graphene_rect_contains_point (&rect, &(graphene_point_t) { x, y});
+}
diff --git a/gtk/gtkcolumnviewcolumnprivate.h b/gtk/gtkcolumnviewcolumnprivate.h
index fe46663e63..a4b588252f 100644
--- a/gtk/gtkcolumnviewcolumnprivate.h
+++ b/gtk/gtkcolumnviewcolumnprivate.h
@@ -47,4 +47,8 @@ void                    gtk_column_view_column_get_allocation           (GtkColu
 
 void                    gtk_column_view_column_notify_sort              (GtkColumnViewColumn    *self);
 
+gboolean                gtk_column_view_column_in_resize_rect           (GtkColumnViewColumn    *self,
+                                                                         double                  x,
+                                                                         double                  y);
+
 #endif  /* __GTK_COLUMN_VIEW_COLUMN_PRIVATE_H__ */


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