[gtk/columnview-scrolling: 24/24] columnview: Implement horizontal scrolling



commit 1bdccbe36ea32757c5838e494a2753c65fbb50f2
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Dec 17 00:34:14 2019 -0500

    columnview: Implement horizontal scrolling
    
    The listview inside always thinks it gets its full size,
    and updates its horizontal adjustment accordingly.
    
    So keep our own adjustment, and update it in size_allocate.

 docs/reference/gtk/gtk4-sections.txt |  2 +
 gtk/gtkcolumnview.c                  | 50 ++++++++++++++++---
 gtk/gtkcolumnviewcell.c              |  8 +++
 gtk/gtkcolumnviewcolumn.c            | 94 ++++++++++++++++++++++++++++++++++++
 gtk/gtkcolumnviewcolumn.h            |  6 +++
 gtk/gtkcolumnviewtitle.c             |  8 +++
 6 files changed, 161 insertions(+), 7 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 8d98f71601..c1c2ac74d8 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -532,6 +532,8 @@ gtk_column_view_column_set_sorter
 gtk_column_view_column_get_sorter
 gtk_column_view_column_set_visible
 gtk_column_view_column_get_visible
+gtk_column_view_column_set_fixed_width
+gtk_column_view_column_get_fixed_width
 <SUBSECTION Standard>
 GTK_COLUMN_VIEW_COLUMN
 GTK_COLUMN_VIEW_COLUMN_CLASS
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 503c4c41b1..e190b812bc 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -35,6 +35,7 @@
 #include "gtkscrollable.h"
 #include "gtkwidgetprivate.h"
 #include "gtksizerequest.h"
+#include "gtkadjustment.h"
 
 /**
  * SECTION:gtkcolumnview
@@ -64,6 +65,8 @@ struct _GtkColumnView
   GtkColumnListItemFactory *factory;
 
   GtkSorter *sorter;
+
+  GtkAdjustment *hadjustment;
 };
 
 struct _GtkColumnViewClass
@@ -170,7 +173,7 @@ gtk_column_view_allocate_columns (GtkColumnView *self,
                                   int            width)
 {
   GtkScrollablePolicy scroll_policy;
-  int col_min, col_nat, widget_min, widget_nat, extra, col_size, x;
+  int col_min, col_nat, extra, col_size, x;
   guint i;
   int n;
   GtkRequestedSize *sizes;
@@ -228,8 +231,9 @@ gtk_column_view_allocate (GtkWidget *widget,
                           int        baseline)
 {
   GtkColumnView *self = GTK_COLUMN_VIEW (widget);
-  int full_width, header_height, min, nat;
+  int full_width, header_height, min, nat, x;
 
+  x = gtk_adjustment_get_value (self->hadjustment);
   full_width = gtk_column_view_allocate_columns (self, width);
 
   gtk_widget_measure (self->header, GTK_ORIENTATION_VERTICAL, full_width, &min, &nat, NULL, NULL);
@@ -237,11 +241,14 @@ gtk_column_view_allocate (GtkWidget *widget,
     header_height = min;
   else
     header_height = nat;
-  gtk_widget_allocate (self->header, full_width, header_height, -1, NULL);
+  gtk_widget_allocate (self->header, full_width, header_height, -1,
+                       gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-x, 0)));
 
   gtk_widget_allocate (GTK_WIDGET (self->listview),
                        full_width, height - header_height, -1,
-                       gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (0, header_height)));
+                       gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-x, header_height)));
+
+  gtk_adjustment_configure (self->hadjustment,  x, 0, full_width, width * 0.1, width * 0.9, width);
 }
 
 static void
@@ -252,6 +259,23 @@ gtk_column_view_activate_cb (GtkListView   *listview,
   g_signal_emit (self, signals[ACTIVATE], 0, pos);
 }
 
+static void
+adjustment_value_changed_cb (GtkAdjustment *adjustment,
+                             GtkColumnView *self)
+{
+  gtk_widget_queue_allocate (GTK_WIDGET (self));
+}
+
+static void
+clear_adjustment (GtkColumnView *self)
+{
+  if (self->hadjustment == NULL)
+    return;
+
+  g_signal_handlers_disconnect_by_func (self->hadjustment, adjustment_value_changed_cb, self);
+  g_clear_object (&self->hadjustment);
+}
+
 static void
 gtk_column_view_dispose (GObject *object)
 {
@@ -270,6 +294,7 @@ gtk_column_view_dispose (GObject *object)
   g_clear_object (&self->factory);
 
   g_clear_object (&self->sorter);
+  clear_adjustment (self);
 
   G_OBJECT_CLASS (gtk_column_view_parent_class)->dispose (object);
 }
@@ -299,7 +324,7 @@ gtk_column_view_get_property (GObject    *object,
       break;
 
     case PROP_HADJUSTMENT:
-      g_value_set_object (value, gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (self->listview)));
+      g_value_set_object (value, self->hadjustment);
       break;
 
     case PROP_HSCROLL_POLICY:
@@ -343,13 +368,24 @@ gtk_column_view_set_property (GObject      *object,
                               GParamSpec   *pspec)
 {
   GtkColumnView *self = GTK_COLUMN_VIEW (object);
+  GtkAdjustment *adjustment;
 
   switch (property_id)
     {
     case PROP_HADJUSTMENT:
-      if (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (self->listview)) != g_value_get_object (value))
+      adjustment = g_value_get_object (value);
+      if (adjustment == NULL)
+        adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+      g_object_ref_sink (adjustment);
+
+      if (self->hadjustment != adjustment)
         {
-          gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (self->listview), g_value_get_object (value));
+          clear_adjustment (self);
+
+          self->hadjustment = adjustment;
+
+          g_signal_connect (adjustment, "value-changed", G_CALLBACK (adjustment_value_changed_cb), self);
+
           g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HADJUSTMENT]);
         }
       break;
diff --git a/gtk/gtkcolumnviewcell.c b/gtk/gtkcolumnviewcell.c
index 4df02a0194..4088222359 100644
--- a/gtk/gtkcolumnviewcell.c
+++ b/gtk/gtkcolumnviewcell.c
@@ -53,10 +53,18 @@ gtk_column_view_cell_measure (GtkWidget      *widget,
                               int            *minimum_baseline,
                               int            *natural_baseline)
 {
+  GtkColumnViewCell *cell = GTK_COLUMN_VIEW_CELL (widget);
   GtkWidget *child = gtk_widget_get_first_child (widget);
 
   if (child)
     gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      int fixed_width = gtk_column_view_column_get_fixed_width (cell->column);
+      if (fixed_width > -1)
+        *minimum = *natural = fixed_width;
+    }
 }
 
 static void
diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c
index 0d4cb1c234..2fa955296c 100644
--- a/gtk/gtkcolumnviewcolumn.c
+++ b/gtk/gtkcolumnviewcolumn.c
@@ -63,6 +63,8 @@ struct _GtkColumnViewColumn
 
   gboolean visible;
 
+  int fixed_width;
+
   /* This list isn't sorted - this is just caching for performance */
   GtkColumnViewCell *first_cell; /* no reference, just caching */
 };
@@ -80,6 +82,7 @@ enum
   PROP_TITLE,
   PROP_SORTER,
   PROP_VISIBLE,
+  PROP_FIXED_WIDTH,
 
   N_PROPS
 };
@@ -133,6 +136,10 @@ gtk_column_view_column_get_property (GObject    *object,
       g_value_set_boolean (value, self->visible);
       break;
 
+    case PROP_FIXED_WIDTH:
+      g_value_set_int (value, self->fixed_width);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -165,6 +172,10 @@ gtk_column_view_column_set_property (GObject      *object,
       gtk_column_view_column_set_visible (self, g_value_get_boolean (value));
       break;
 
+    case PROP_FIXED_WIDTH:
+      gtk_column_view_column_set_fixed_width (self, g_value_get_int (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -240,6 +251,19 @@ gtk_column_view_column_class_init (GtkColumnViewColumnClass *klass)
                           TRUE,
                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+  /**
+   * GtkColumnViewColumn:fixed-width:
+   *
+   * If not -1, this is the width that the column is allocated,
+   * regardless of the size of its content.
+   */
+  properties[PROP_FIXED_WIDTH] =
+    g_param_spec_int ("fixed-width",
+                      P_("Fixed width"),
+                      P_("Fixed width of this column"),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (gobject_class, N_PROPS, properties);
 }
 
@@ -249,6 +273,7 @@ gtk_column_view_column_init (GtkColumnViewColumn *self)
   self->minimum_size_request = -1;
   self->natural_size_request = -1;
   self->visible = TRUE;
+  self->fixed_width = -1;
 }
 
 /**
@@ -357,6 +382,12 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self,
                                 int                 *minimum,
                                 int                 *natural)
 {
+  if (self->fixed_width > -1)
+    {
+      self->minimum_size_request  = self->fixed_width;
+      self->natural_size_request  = self->fixed_width;
+    }
+
   if (self->minimum_size_request < 0)
     {
       GtkColumnViewCell *cell;
@@ -721,3 +752,66 @@ gtk_column_view_column_get_visible (GtkColumnViewColumn *self)
 
   return self->visible;
 }
+
+/**
+ * gtk_column_view_column_set_fixed_width:
+ * @self: a #GtkColumnViewColumn
+ * @fixed_width: the new fixed width, or -1
+ *
+ * If @fixed_width is not -1, sets the fixed width of @column;
+ * otherwise unsets it.
+ *
+ * Setting a fixed width overrides the automatically calculated
+ * width. Interactive resizing also sets the “fixed-width” property.
+ */
+void
+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);
+
+  if (self->fixed_width == fixed_width)
+    return;
+
+  self->fixed_width = fixed_width;
+
+  if (fixed_width > -1)
+    overflow = GTK_OVERFLOW_HIDDEN;
+  else
+    overflow = GTK_OVERFLOW_VISIBLE;
+
+  if (overflow != gtk_widget_get_overflow (GTK_WIDGET (self->header)))
+    {
+      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_column_view_column_queue_resize (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FIXED_WIDTH]);
+}
+
+/**
+ * gtk_column_view_column_get_fixed_width:
+ * @self: a #GtkColumnViewColumn
+ *
+ * Gets the fixed width of the column.
+ *
+ * Returns: the fixed with of the column
+ */
+int
+gtk_column_view_column_get_fixed_width (GtkColumnViewColumn *self)
+{
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), -1);
+
+  return self->fixed_width;
+}
diff --git a/gtk/gtkcolumnviewcolumn.h b/gtk/gtkcolumnviewcolumn.h
index f0005809be..32392612b2 100644
--- a/gtk/gtkcolumnviewcolumn.h
+++ b/gtk/gtkcolumnviewcolumn.h
@@ -78,6 +78,12 @@ void                    gtk_column_view_column_set_visible              (GtkColu
 GDK_AVAILABLE_IN_ALL
 gboolean                gtk_column_view_column_get_visible              (GtkColumnViewColumn    *self);
 
+GDK_AVAILABLE_IN_ALL
+void                    gtk_column_view_column_set_fixed_width          (GtkColumnViewColumn    *self,
+                                                                         int                     
fixed_width);
+GDK_AVAILABLE_IN_ALL
+int                     gtk_column_view_column_get_fixed_width          (GtkColumnViewColumn    *self);
+
 G_END_DECLS
 
 #endif  /* __GTK_COLUMN_VIEW_COLUMN_H__ */
diff --git a/gtk/gtkcolumnviewtitle.c b/gtk/gtkcolumnviewtitle.c
index 306064bcd8..e6bcf0ef5f 100644
--- a/gtk/gtkcolumnviewtitle.c
+++ b/gtk/gtkcolumnviewtitle.c
@@ -58,10 +58,18 @@ gtk_column_view_title_measure (GtkWidget      *widget,
                                int            *minimum_baseline,
                                int            *natural_baseline)
 {
+  GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
   GtkWidget *child = gtk_widget_get_first_child (widget);
 
   if (child)
     gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      int fixed_width = gtk_column_view_column_get_fixed_width (self->column);
+      if (fixed_width > -1)
+        *minimum = *natural = fixed_width;
+    }
 }
 
 static void


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