[gtk/wip/otte/listview: 290/309] columnview: Add header



commit 2120b72d228a488db6d4961c9ab973594d98c92b
Author: Benjamin Otte <otte redhat com>
Date:   Fri Nov 8 21:23:03 2019 +0100

    columnview: Add header
    
    This uses a custom GtkColumnViewTitle widget. So far that widget is
    pretty boring, but that will change once we added
    resizing, reordering, dnd, sorting, hiding/showing of columns or
    whatever UIs we want.

 docs/reference/gtk/meson.build  |   1 +
 gtk/gtkcolumnview.c             |  43 ++++++++++--
 gtk/gtkcolumnviewcolumn.c       |  55 ++++++++++++++--
 gtk/gtkcolumnviewlayout.c       |   9 ++-
 gtk/gtkcolumnviewprivate.h      |   4 ++
 gtk/gtkcolumnviewtitle.c        | 142 ++++++++++++++++++++++++++++++++++++++++
 gtk/gtkcolumnviewtitleprivate.h |  47 +++++++++++++
 gtk/meson.build                 |   1 +
 8 files changed, 291 insertions(+), 11 deletions(-)
---
diff --git a/docs/reference/gtk/meson.build b/docs/reference/gtk/meson.build
index 797784e81c..40584ab31f 100644
--- a/docs/reference/gtk/meson.build
+++ b/docs/reference/gtk/meson.build
@@ -29,6 +29,7 @@ private_headers = [
   'gtkcolumnviewcolumnprivate.h',
   'gtkcolumnviewlayoutprivate.h',
   'gtkcolumnviewprivate.h',
+  'gtkcolumnviewtitleprivate.h',
   'gtkcomboboxprivate.h',
   'gtkconstraintexpressionprivate.h',
   'gtkconstraintguideprivate.h',
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 8582e7293d..d6170dfc46 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -25,6 +25,7 @@
 #include "gtkbuildable.h"
 #include "gtkcolumnlistitemfactoryprivate.h"
 #include "gtkcolumnviewcolumnprivate.h"
+#include "gtkcolumnviewlayoutprivate.h"
 #include "gtkcssnodeprivate.h"
 #include "gtkintl.h"
 #include "gtklistview.h"
@@ -49,6 +50,8 @@ struct _GtkColumnView
 
   GListStore *columns;
 
+  GtkWidget *header;
+
   GtkListView *listview;
   GtkColumnListItemFactory *factory;
 };
@@ -135,10 +138,18 @@ gtk_column_view_measure (GtkWidget      *widget,
     }
   else
     {
+      int header_min, header_nat, list_min, list_nat;
+
+      gtk_widget_measure (GTK_WIDGET (self->listview),
+                          orientation, for_size,
+                          &header_min, &header_nat,
+                          NULL, NULL);
       gtk_widget_measure (GTK_WIDGET (self->listview),
                           orientation, for_size,
-                          minimum, natural, 
-                          minimum_baseline, natural_baseline);
+                          &list_min, &list_nat,
+                          NULL, NULL);
+      *minimum = header_min + list_min;
+      *natural = header_nat + list_nat;
     }
 }
 
@@ -151,7 +162,7 @@ gtk_column_view_allocate_columns (GtkColumnView *self,
   guint i;
 
   gtk_column_view_measure_across (self, &col_min, &col_nat);
-  gtk_widget_measure (GTK_WIDGET (self->listview),
+  gtk_widget_measure (GTK_WIDGET (self),
                       GTK_ORIENTATION_HORIZONTAL, -1,
                       &widget_min, &widget_nat,
                       NULL, NULL);
@@ -198,11 +209,20 @@ gtk_column_view_allocate (GtkWidget *widget,
                           int        baseline)
 {
   GtkColumnView *self = GTK_COLUMN_VIEW (widget);
-  int full_width;
+  int full_width, header_height, min, nat;
 
   full_width = gtk_column_view_allocate_columns (self, width);
 
-  gtk_widget_allocate (GTK_WIDGET (self->listview), full_width, height, baseline, NULL);
+  gtk_widget_measure (self->header, GTK_ORIENTATION_VERTICAL, full_width, &min, &nat, NULL, NULL);
+  if (gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (self->listview)) == GTK_SCROLL_MINIMUM)
+    header_height = min;
+  else
+    header_height = nat;
+  gtk_widget_allocate (self->header, full_width, header_height, -1, NULL);
+
+  gtk_widget_allocate (GTK_WIDGET (self->listview),
+                       full_width, height - header_height, -1,
+                       gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (0, header_height)));
 }
 
 static void
@@ -225,6 +245,8 @@ gtk_column_view_dispose (GObject *object)
       g_object_unref (column);
     }
 
+  g_clear_pointer (&self->header, gtk_widget_unparent);
+
   g_clear_pointer ((GtkWidget **) &self->listview, gtk_widget_unparent);
   g_clear_object (&self->factory);
 
@@ -441,6 +463,11 @@ gtk_column_view_init (GtkColumnView *self)
 {
   self->columns = g_list_store_new (GTK_TYPE_COLUMN_VIEW_COLUMN);
 
+  self->header = gtk_list_item_widget_new (NULL, "header");
+  gtk_widget_set_can_focus (self->header, FALSE);
+  gtk_widget_set_layout_manager (self->header, gtk_column_view_layout_new (self));
+  gtk_widget_set_parent (self->header, GTK_WIDGET (self));
+
   self->factory = gtk_column_list_item_factory_new (self);
   self->listview = GTK_LIST_VIEW (gtk_list_view_new_with_factory (
         GTK_LIST_ITEM_FACTORY (g_object_ref (self->factory))));
@@ -648,3 +675,9 @@ gtk_column_view_measure_across (GtkColumnView *self,
   *natural = nat;
 }
 
+GtkListItemWidget *
+gtk_column_view_get_header_widget (GtkColumnView *self)
+{
+  return GTK_LIST_ITEM_WIDGET (self->header);
+}
+
diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c
index aaa8c32fdc..c33c50cd53 100644
--- a/gtk/gtkcolumnviewcolumn.c
+++ b/gtk/gtkcolumnviewcolumn.c
@@ -21,6 +21,8 @@
 
 #include "gtkcolumnviewcolumnprivate.h"
 
+#include "gtkcolumnviewprivate.h"
+#include "gtkcolumnviewtitleprivate.h"
 #include "gtkintl.h"
 #include "gtklistbaseprivate.h"
 #include "gtklistitemwidgetprivate.h"
@@ -49,6 +51,7 @@ struct _GtkColumnViewColumn
 
   /* data for the view */
   GtkColumnView *view;
+  GtkWidget *header;
 
   int minimum_size_request;
   int natural_size_request;
@@ -291,6 +294,9 @@ gtk_column_view_column_queue_resize (GtkColumnViewColumn *self)
   self->minimum_size_request = -1;
   self->natural_size_request = -1;
 
+  if (self->header)
+    gtk_widget_queue_resize (self->header);
+
   for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell))
     {
       gtk_widget_queue_resize (GTK_WIDGET (cell));
@@ -307,8 +313,15 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self,
       GtkColumnViewCell *cell;
       int min, nat, cell_min, cell_nat;
 
-      min = 0;
-      nat = 0;
+      if (self->header)
+        {
+          gtk_widget_measure (self->header, GTK_ORIENTATION_HORIZONTAL, -1, &min, &nat, NULL, NULL);
+        }
+      else
+        {
+          min = 0;
+          nat = 0;
+        }
 
       for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell))
         {
@@ -385,6 +398,30 @@ gtk_column_view_column_remove_cells (GtkColumnViewColumn *self)
     gtk_column_view_cell_remove (self->first_cell);
 }
 
+static void
+gtk_column_view_column_create_header (GtkColumnViewColumn *self)
+{
+  if (self->header != NULL)
+    return;
+
+  self->header = gtk_column_view_title_new (self);
+  gtk_list_item_widget_add_child (gtk_column_view_get_header_widget (self->view),
+                                  self->header);
+  gtk_column_view_column_queue_resize (self);
+}
+
+static void
+gtk_column_view_column_remove_header (GtkColumnViewColumn *self)
+{
+  if (self->header == NULL)
+    return;
+
+  gtk_list_item_widget_remove_child (gtk_column_view_get_header_widget (self->view),
+                                     self->header);
+  self->header = NULL;
+  gtk_column_view_column_queue_resize (self);
+}
+
 static void
 gtk_column_view_column_ensure_cells (GtkColumnViewColumn *self)
 {
@@ -392,6 +429,11 @@ gtk_column_view_column_ensure_cells (GtkColumnViewColumn *self)
     gtk_column_view_column_create_cells (self);
   else
     gtk_column_view_column_remove_cells (self);
+
+  if (self->view)
+    gtk_column_view_column_create_header (self);
+  else
+    gtk_column_view_column_remove_header (self);
 }
 
 /**
@@ -419,10 +461,12 @@ gtk_column_view_column_set_column_view (GtkColumnViewColumn *self,
   if (self->view == view)
     return;
 
+  gtk_column_view_column_remove_cells (self);
+  gtk_column_view_column_remove_header (self);
+
   self->view = view;
 
-  if (view)
-    gtk_column_view_column_ensure_cells (self);
+  gtk_column_view_column_ensure_cells (self);
 
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLUMN_VIEW]);
 }
@@ -486,6 +530,9 @@ gtk_column_view_column_set_title (GtkColumnViewColumn *self,
   g_free (self->title);
   self->title = g_strdup (title);
 
+  if (self->header)
+    gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
+
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]);
 }
 
diff --git a/gtk/gtkcolumnviewlayout.c b/gtk/gtkcolumnviewlayout.c
index 3afd6a2af3..c4ba28a112 100644
--- a/gtk/gtkcolumnviewlayout.c
+++ b/gtk/gtkcolumnviewlayout.c
@@ -24,6 +24,7 @@
 #include "gtkcolumnviewcellprivate.h"
 #include "gtkcolumnviewcolumnprivate.h"
 #include "gtkcolumnviewprivate.h"
+#include "gtkcolumnviewtitleprivate.h"
 #include "gtkwidgetprivate.h"
 
 struct _GtkColumnViewLayout
@@ -113,10 +114,14 @@ gtk_column_view_layout_allocate (GtkLayoutManager *layout_manager,
        child != NULL;
        child = _gtk_widget_get_next_sibling (child))
     {
-      GtkColumnViewCell *cell = GTK_COLUMN_VIEW_CELL (child);
-      GtkColumnViewColumn *column = gtk_column_view_cell_get_column (cell);
+      GtkColumnViewColumn *column;
       int col_x, col_width;
 
+      if (GTK_IS_COLUMN_VIEW_CELL (child))
+        column = gtk_column_view_cell_get_column (GTK_COLUMN_VIEW_CELL (child));
+      else
+        column = gtk_column_view_title_get_column (GTK_COLUMN_VIEW_TITLE (child));
+
       gtk_column_view_column_get_allocation (column, &col_x, &col_width);
       gtk_widget_size_allocate (child, &(GtkAllocation) { col_x, 0, col_width, height }, baseline);
     }
diff --git a/gtk/gtkcolumnviewprivate.h b/gtk/gtkcolumnviewprivate.h
index d95577fe98..c356fae508 100644
--- a/gtk/gtkcolumnviewprivate.h
+++ b/gtk/gtkcolumnviewprivate.h
@@ -22,6 +22,10 @@
 
 #include "gtk/gtkcolumnview.h"
 
+#include "gtk/gtklistitemwidgetprivate.h"
+
+GtkListItemWidget *     gtk_column_view_get_header_widget       (GtkColumnView          *self);
+
 void                    gtk_column_view_measure_across          (GtkColumnView          *self,
                                                                  int                    *minimum,
                                                                  int                    *natural);
diff --git a/gtk/gtkcolumnviewtitle.c b/gtk/gtkcolumnviewtitle.c
new file mode 100644
index 0000000000..7170018eb4
--- /dev/null
+++ b/gtk/gtkcolumnviewtitle.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2019 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcolumnviewtitleprivate.h"
+
+#include "gtkcolumnviewcolumnprivate.h"
+#include "gtkintl.h"
+#include "gtklabel.h"
+#include "gtkwidgetprivate.h"
+
+struct _GtkColumnViewTitle
+{
+  GtkWidget parent_instance;
+
+  GtkColumnViewColumn *column;
+
+  GtkWidget *title;
+};
+
+struct _GtkColumnViewTitleClass
+{
+  GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkColumnViewTitle, gtk_column_view_title, GTK_TYPE_WIDGET)
+
+static void
+gtk_column_view_title_measure (GtkWidget      *widget,
+                               GtkOrientation  orientation,
+                               int             for_size,
+                               int            *minimum,
+                               int            *natural,
+                               int            *minimum_baseline,
+                               int            *natural_baseline)
+{
+  GtkWidget *child = gtk_widget_get_first_child (widget);
+
+  if (child)
+    gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
+}
+
+static void
+gtk_column_view_title_size_allocate (GtkWidget *widget,
+                                     int        width,
+                                     int        height,
+                                     int        baseline)
+{
+  GtkWidget *child = gtk_widget_get_first_child (widget);
+
+  if (child)
+    gtk_widget_allocate (child, width, height, baseline, NULL);
+}
+
+static void
+gtk_column_view_title_dispose (GObject *object)
+{
+  GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (object);
+
+  g_clear_pointer(&self->title, gtk_widget_unparent);
+
+  g_clear_object (&self->column);
+
+  G_OBJECT_CLASS (gtk_column_view_title_parent_class)->dispose (object);
+}
+
+static void
+gtk_column_view_title_class_init (GtkColumnViewTitleClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  widget_class->measure = gtk_column_view_title_measure;
+  widget_class->size_allocate = gtk_column_view_title_size_allocate;
+
+  gobject_class->dispose = gtk_column_view_title_dispose;
+
+  gtk_widget_class_set_css_name (widget_class, I_("button"));
+}
+
+static void
+gtk_column_view_title_resize_func (GtkWidget *widget)
+{
+  GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
+
+  if (self->column)
+    gtk_column_view_column_queue_resize (self->column);
+}
+
+static void
+gtk_column_view_title_init (GtkColumnViewTitle *self)
+{
+  GtkWidget *widget = GTK_WIDGET (self);
+
+  widget->priv->resize_func = gtk_column_view_title_resize_func;
+
+  self->title = gtk_label_new (NULL);
+  gtk_widget_set_parent (self->title, widget);
+}
+
+GtkWidget *
+gtk_column_view_title_new (GtkColumnViewColumn *column)
+{
+  GtkColumnViewTitle *title;
+
+  title = g_object_new (GTK_TYPE_COLUMN_VIEW_TITLE,
+                        NULL);
+
+  title->column = g_object_ref (column);
+  gtk_column_view_title_update (title);
+
+  return GTK_WIDGET (title);
+}
+
+void
+gtk_column_view_title_update (GtkColumnViewTitle *self)
+{
+  gtk_label_set_label (GTK_LABEL (self->title), gtk_column_view_column_get_title (self->column));
+}
+
+GtkColumnViewColumn *
+gtk_column_view_title_get_column (GtkColumnViewTitle *self)
+{
+  return self->column;
+}
diff --git a/gtk/gtkcolumnviewtitleprivate.h b/gtk/gtkcolumnviewtitleprivate.h
new file mode 100644
index 0000000000..84bc6a4050
--- /dev/null
+++ b/gtk/gtkcolumnviewtitleprivate.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2019 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_COLUMN_VIEW_TITLE_PRIVATE_H__
+#define __GTK_COLUMN_VIEW_TITLE_PRIVATE_H__
+
+#include "gtkcolumnviewcolumn.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLUMN_VIEW_TITLE         (gtk_column_view_title_get_type ())
+#define GTK_COLUMN_VIEW_TITLE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COLUMN_VIEW_TITLE, 
GtkColumnViewTitle))
+#define GTK_COLUMN_VIEW_TITLE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_COLUMN_VIEW_TITLE, 
GtkColumnViewTitleClass))
+#define GTK_IS_COLUMN_VIEW_TITLE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COLUMN_VIEW_TITLE))
+#define GTK_IS_COLUMN_VIEW_TITLE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COLUMN_VIEW_TITLE))
+#define GTK_COLUMN_VIEW_TITLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COLUMN_VIEW_TITLE, 
GtkColumnViewTitleClass))
+
+typedef struct _GtkColumnViewTitle GtkColumnViewTitle;
+typedef struct _GtkColumnViewTitleClass GtkColumnViewTitleClass;
+
+GType                   gtk_column_view_title_get_type          (void) G_GNUC_CONST;
+
+GtkWidget *             gtk_column_view_title_new               (GtkColumnViewColumn    *column);
+
+void                    gtk_column_view_title_update            (GtkColumnViewTitle     *self);
+
+GtkColumnViewColumn *   gtk_column_view_title_get_column        (GtkColumnViewTitle     *self);
+
+G_END_DECLS
+
+#endif  /* __GTK_COLUMN_VIEW_TITLE_PRIVATE_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 565c23ad5b..642904b231 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -40,6 +40,7 @@ gtk_private_sources = files([
   'gtkcolumnlistitemfactory.c',
   'gtkcolumnviewcell.c',
   'gtkcolumnviewlayout.c',
+  'gtkcolumnviewtitle.c',
   'gtkconstraintexpression.c',
   'gtkconstraintsolver.c',
   'gtkconstraintvflparser.c',


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