[gtk/wip/otte/listview: 7/8] columnview: Add listitems for the columns



commit 828815d07eaa334c0194ebab92b4a09ff264e678
Author: Benjamin Otte <otte redhat com>
Date:   Wed Oct 30 18:03:23 2019 +0100

    columnview: Add listitems for the columns
    
    They are not aligned in columns yet, but they do exist.

 gtk/gtkcolumnlistitemfactory.c        | 306 ++++++++++++++++++++++++++++++++++
 gtk/gtkcolumnlistitemfactoryprivate.h |  62 +++++++
 gtk/gtkcolumnview.c                   |  70 +++++++-
 gtk/gtkcolumnviewprivate.h            |  35 ++++
 gtk/meson.build                       |   1 +
 5 files changed, 466 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkcolumnlistitemfactory.c b/gtk/gtkcolumnlistitemfactory.c
new file mode 100644
index 0000000000..4c643d2d4c
--- /dev/null
+++ b/gtk/gtkcolumnlistitemfactory.c
@@ -0,0 +1,306 @@
+/*
+ * 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 "gtkcolumnlistitemfactoryprivate.h"
+
+#include "gtkboxlayout.h"
+#include "gtkcolumnviewcolumnprivate.h"
+#include "gtklistitemfactoryprivate.h"
+#include "gtklistitemprivate.h"
+
+struct _GtkColumnListItemFactory
+{
+  GtkListItemFactory parent_instance;
+
+  GtkColumnView *view; /* no reference, the view references us */
+};
+
+struct _GtkColumnListItemFactoryClass
+{
+  GtkListItemFactoryClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkColumnListItemFactory, gtk_column_list_item_factory, GTK_TYPE_LIST_ITEM_FACTORY)
+
+static GtkListItem *
+get_nth_child (GtkListItem *parent,
+               guint        pos)
+{
+  GtkWidget *child;
+  guint i;
+
+  child = gtk_widget_get_first_child (GTK_WIDGET (parent));
+  for (i = 1; i < pos && child; i++)
+    child = gtk_widget_get_next_sibling (child);
+
+  return GTK_LIST_ITEM (child);
+}
+
+static void
+gtk_column_list_item_factory_setup (GtkListItemFactory *factory,
+                                    GtkListItem        *list_item)
+{
+  GtkColumnListItemFactory *self = GTK_COLUMN_LIST_ITEM_FACTORY (factory);
+  GListModel *columns;
+  guint i;
+
+  gtk_widget_set_layout_manager (GTK_WIDGET (list_item),
+                                 gtk_box_layout_new (GTK_ORIENTATION_HORIZONTAL));
+
+  GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->setup (factory, list_item);
+
+  columns = gtk_column_view_get_columns (self->view);
+
+  for (i = 0; i < g_list_model_get_n_items (columns); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (columns, i);
+
+      gtk_column_list_item_factory_add_column (self, 
+                                               list_item,
+                                               column,
+                                               FALSE);
+    }
+}
+
+static void
+gtk_column_list_item_factory_teardown (GtkListItemFactory *factory,
+                                       GtkListItem        *list_item)
+{
+  GtkColumnListItemFactory *self = GTK_COLUMN_LIST_ITEM_FACTORY (factory);
+  GListModel *columns;
+  guint i;
+
+  GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->teardown (factory, list_item);
+
+  columns = gtk_column_view_get_columns (self->view);
+
+  for (i = 0; i < g_list_model_get_n_items (columns); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (columns, i);
+      GtkListItemFactory *column_factory = gtk_column_view_column_get_factory (column);
+      GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (list_item));
+
+      if (column_factory)
+        gtk_list_item_factory_teardown (column_factory, GTK_LIST_ITEM (child));
+
+      gtk_widget_unparent (child);
+    }
+}
+
+static void                  
+gtk_column_list_item_factory_bind (GtkListItemFactory *factory,
+                                   GtkListItem        *list_item,
+                                   guint               position,
+                                   gpointer            item,
+                                   gboolean            selected)
+{
+  GtkColumnListItemFactory *self = GTK_COLUMN_LIST_ITEM_FACTORY (factory);
+  GListModel *columns;
+  GtkWidget *child;
+  guint i;
+
+  GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->bind (factory, list_item, 
position, item, selected);
+
+  child = gtk_widget_get_first_child (GTK_WIDGET (list_item));
+  columns = gtk_column_view_get_columns (self->view);
+
+  for (i = 0; i < g_list_model_get_n_items (columns); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (columns, i);
+      GtkListItemFactory *column_factory = gtk_column_view_column_get_factory (column);
+
+      if (column_factory)
+        gtk_list_item_factory_bind (column_factory, GTK_LIST_ITEM (child), position, item, selected);
+
+      child = gtk_widget_get_next_sibling (child);
+    }
+
+  g_assert (child == NULL);
+}
+
+static void
+gtk_column_list_item_factory_rebind (GtkListItemFactory *factory,
+                                     GtkListItem        *list_item,
+                                     guint               position,
+                                     gpointer            item,
+                                     gboolean            selected)
+{
+  GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->bind (factory, list_item, 
position, item, selected);
+  GtkColumnListItemFactory *self = GTK_COLUMN_LIST_ITEM_FACTORY (factory);
+  GListModel *columns;
+  GtkWidget *child;
+  guint i;
+
+  GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->setup (factory, list_item);
+
+  child = gtk_widget_get_first_child (GTK_WIDGET (list_item));
+  columns = gtk_column_view_get_columns (self->view);
+
+  for (i = 0; i < g_list_model_get_n_items (columns); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (columns, i);
+      GtkListItemFactory *column_factory = gtk_column_view_column_get_factory (column);
+
+      if (column_factory)
+        gtk_list_item_factory_setup (column_factory, GTK_LIST_ITEM (child));
+
+      child = gtk_widget_get_next_sibling (child);
+    }
+
+  g_assert (child == NULL);
+}
+
+static void
+gtk_column_list_item_factory_update (GtkListItemFactory *factory,
+                                     GtkListItem        *list_item,
+                                     guint               position,
+                                     gboolean            selected)
+{
+  GtkColumnListItemFactory *self = GTK_COLUMN_LIST_ITEM_FACTORY (factory);
+  GListModel *columns;
+  GtkWidget *child;
+  guint i;
+
+  GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->update (factory, list_item, 
position, selected);
+
+  child = gtk_widget_get_first_child (GTK_WIDGET (list_item));
+  columns = gtk_column_view_get_columns (self->view);
+
+  for (i = 0; i < g_list_model_get_n_items (columns); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (columns, i);
+      GtkListItemFactory *column_factory = gtk_column_view_column_get_factory (column);
+
+      if (column_factory)
+        gtk_list_item_factory_update (column_factory, GTK_LIST_ITEM (child), position, selected);
+
+      child = gtk_widget_get_next_sibling (child);
+    }
+
+  g_assert (child == NULL);
+}
+
+static void
+gtk_column_list_item_factory_unbind (GtkListItemFactory *factory,
+                                     GtkListItem        *list_item)
+{
+  GtkColumnListItemFactory *self = GTK_COLUMN_LIST_ITEM_FACTORY (factory);
+  GListModel *columns;
+  GtkWidget *child;
+  guint i;
+
+  GTK_LIST_ITEM_FACTORY_CLASS (gtk_column_list_item_factory_parent_class)->unbind (factory, list_item);
+
+  child = gtk_widget_get_first_child (GTK_WIDGET (list_item));
+  columns = gtk_column_view_get_columns (self->view);
+
+  for (i = 0; i < g_list_model_get_n_items (columns); i++)
+    {
+      GtkColumnViewColumn *column = g_list_model_get_item (columns, i);
+      GtkListItemFactory *column_factory = gtk_column_view_column_get_factory (column);
+
+      if (column_factory)
+        gtk_list_item_factory_unbind (column_factory, GTK_LIST_ITEM (child));
+
+      child = gtk_widget_get_next_sibling (child);
+    }
+
+  g_assert (child == NULL);
+}
+
+static void
+gtk_column_list_item_factory_class_init (GtkColumnListItemFactoryClass *klass)
+{
+  GtkListItemFactoryClass *factory_class = GTK_LIST_ITEM_FACTORY_CLASS (klass);
+
+  factory_class->setup = gtk_column_list_item_factory_setup;
+  factory_class->teardown = gtk_column_list_item_factory_teardown;
+  factory_class->bind = gtk_column_list_item_factory_bind;
+  factory_class->rebind = gtk_column_list_item_factory_rebind;
+  factory_class->update = gtk_column_list_item_factory_update;
+  factory_class->unbind = gtk_column_list_item_factory_unbind;
+}
+
+static void
+gtk_column_list_item_factory_init (GtkColumnListItemFactory *self)
+{
+}
+
+GtkColumnListItemFactory *
+gtk_column_list_item_factory_new (GtkColumnView *view)
+{
+  GtkColumnListItemFactory *result;
+
+  result = g_object_new (GTK_TYPE_COLUMN_LIST_ITEM_FACTORY, NULL);
+
+  result->view = view;
+
+  return result;
+}
+
+void
+gtk_column_list_item_factory_add_column (GtkColumnListItemFactory *factory,
+                                         GtkListItem              *list_item,
+                                         GtkColumnViewColumn      *column,
+                                         gboolean                  check_bind)
+{
+  GtkListItemFactory *column_factory;
+  GtkListItem *child;
+
+  column_factory = gtk_column_view_column_get_factory (column);
+
+  child = gtk_list_item_new ("cell");
+  gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (list_item));
+  if (column_factory)
+    {
+      gpointer item;
+
+      gtk_list_item_factory_setup (column_factory, child);
+      if (check_bind &&
+          (item = gtk_list_item_get_item (list_item)))
+        {
+          gtk_list_item_factory_bind (column_factory,
+                                      child,
+                                      gtk_list_item_get_position (list_item),
+                                      item,
+                                      gtk_list_item_get_selected (list_item));
+        }
+    }
+}
+
+void
+gtk_column_list_item_factory_remove_column (GtkColumnListItemFactory *factory,
+                                            GtkListItem              *list_item,
+                                            guint                     col_pos,
+                                            GtkColumnViewColumn      *column)
+{
+  GtkListItemFactory *column_factory;
+  GtkListItem *child;
+
+  column_factory = gtk_column_view_column_get_factory (column);
+  child = get_nth_child (list_item, col_pos);
+
+  if (gtk_list_item_get_item (GTK_LIST_ITEM (child)))
+    gtk_list_item_factory_unbind (column_factory, child);
+  
+  gtk_list_item_factory_teardown (column_factory, child);
+  gtk_widget_unparent (GTK_WIDGET (child));
+}
diff --git a/gtk/gtkcolumnlistitemfactoryprivate.h b/gtk/gtkcolumnlistitemfactoryprivate.h
new file mode 100644
index 0000000000..1822723027
--- /dev/null
+++ b/gtk/gtkcolumnlistitemfactoryprivate.h
@@ -0,0 +1,62 @@
+/*
+ * 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_LIST_ITEM_FACTORY_H__
+#define __GTK_COLUMN_LIST_ITEM_FACTORY_H__
+
+#include <gtk/gtklistitemfactory.h>
+#include <gtk/gtkcolumnview.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLUMN_LIST_ITEM_FACTORY         (gtk_column_list_item_factory_get_type ())
+#define GTK_COLUMN_LIST_ITEM_FACTORY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), 
GTK_TYPE_COLUMN_LIST_ITEM_FACTORY, GtkColumnListItemFactory))
+#define GTK_COLUMN_LIST_ITEM_FACTORY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), 
GTK_TYPE_COLUMN_LIST_ITEM_FACTORY, GtkColumnListItemFactoryClass))
+#define GTK_IS_COLUMN_LIST_ITEM_FACTORY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), 
GTK_TYPE_COLUMN_LIST_ITEM_FACTORY))
+#define GTK_IS_COLUMN_LIST_ITEM_FACTORY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), 
GTK_TYPE_COLUMN_LIST_ITEM_FACTORY))
+#define GTK_COLUMN_LIST_ITEM_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), 
GTK_TYPE_COLUMN_LIST_ITEM_FACTORY, GtkColumnListItemFactoryClass))
+
+/**
+ * GtkColumnListItemFactory:
+ *
+ * The object for the #GtkColumnListItemFactory.
+ **/
+typedef struct _GtkColumnListItemFactory GtkColumnListItemFactory;
+typedef struct _GtkColumnListItemFactoryClass GtkColumnListItemFactoryClass;
+
+
+GType                   gtk_column_list_item_factory_get_type   (void) G_GNUC_CONST;
+
+GtkColumnListItemFactory *
+                        gtk_column_list_item_factory_new        (GtkColumnView          *view);
+
+void                    gtk_column_list_item_factory_add_column (GtkColumnListItemFactory       *factory,
+                                                                 GtkListItem                    *list_item,
+                                                                 GtkColumnViewColumn            *column,
+                                                                 gboolean                        check_bind);
+void                    gtk_column_list_item_factory_remove_column
+                                                                (GtkColumnListItemFactory       *factory,
+                                                                 GtkListItem                    *list_item,
+                                                                 guint                           col_pos,
+                                                                 GtkColumnViewColumn            *column);
+
+
+G_END_DECLS
+
+#endif /* __GTK_COLUMN_LIST_ITEM_FACTORY_H__ */
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 14dec39135..d6a06096aa 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -19,10 +19,11 @@
 
 #include "config.h"
 
-#include "gtkcolumnview.h"
+#include "gtkcolumnviewprivate.h"
 
 #include "gtkboxlayout.h"
 #include "gtkbuildable.h"
+#include "gtkcolumnlistitemfactoryprivate.h"
 #include "gtkcolumnviewcolumnprivate.h"
 #include "gtkintl.h"
 #include "gtklistview.h"
@@ -47,6 +48,7 @@ struct _GtkColumnView
   GListStore *columns;
 
   GtkListView *listview;
+  GtkColumnListItemFactory *factory;
 };
 
 struct _GtkColumnViewClass
@@ -102,12 +104,37 @@ gtk_column_view_buildable_interface_init (GtkBuildableIface *iface)
 
   iface->add_child = gtk_column_view_buildable_add_child;
 }
+
 G_DEFINE_TYPE_WITH_CODE (GtkColumnView, gtk_column_view, GTK_TYPE_WIDGET,
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, 
gtk_column_view_buildable_interface_init))
 
 static GParamSpec *properties[N_PROPS] = { NULL, };
 static guint signals[LAST_SIGNAL] = { 0 };
 
+/* For now we do the iter with the children. We might switch that
+ * to use the item manager or track children directly in the factory
+ * later (depending on how code changes), so having this abstraction makes sense.
+ */
+GtkColumnViewIter *
+gtk_column_view_iter_init (GtkColumnView *self)
+{
+  return (GtkColumnViewIter *) gtk_widget_get_first_child (GTK_WIDGET (self->listview));
+}
+
+GtkListItem *
+gtk_column_view_iter_get_item (GtkColumnView     *self,
+                               GtkColumnViewIter *iter)
+{
+  return GTK_LIST_ITEM (iter);
+}
+
+GtkColumnViewIter *
+gtk_column_view_iter_next (GtkColumnView     *self,
+                           GtkColumnViewIter *iter)
+{
+  return (GtkColumnViewIter *) gtk_widget_get_next_sibling (GTK_WIDGET (iter));
+}
+
 static void
 gtk_column_view_activate_cb (GtkListView   *listview,
                              guint          pos,
@@ -129,6 +156,7 @@ gtk_column_view_dispose (GObject *object)
     }
 
   g_clear_pointer ((GtkWidget **) &self->listview, gtk_widget_unparent);
+  g_clear_object (&self->factory);
 
   G_OBJECT_CLASS (gtk_column_view_parent_class)->dispose (object);
 }
@@ -277,7 +305,11 @@ gtk_column_view_init (GtkColumnView *self)
 {
   self->columns = g_list_store_new (GTK_TYPE_COLUMN_VIEW_COLUMN);
 
-  self->listview = GTK_LIST_VIEW (gtk_list_view_new ());
+  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))));
+  gtk_widget_set_hexpand (GTK_WIDGET (self->listview), TRUE);
+  gtk_widget_set_vexpand (GTK_WIDGET (self->listview), TRUE);
   g_signal_connect (self->listview, "activate", G_CALLBACK (gtk_column_view_activate_cb), self);
   gtk_widget_set_parent (GTK_WIDGET (self->listview), GTK_WIDGET (self));
 }
@@ -409,12 +441,24 @@ void
 gtk_column_view_append_column (GtkColumnView       *self,
                                GtkColumnViewColumn *column)
 {
+  GtkColumnViewIter *iter;
+
   g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
   g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (column));
   g_return_if_fail (gtk_column_view_column_get_column_view (column) == NULL);
 
   gtk_column_view_column_set_column_view (column, self);
   g_list_store_append (self->columns, column);
+
+  for (iter = gtk_column_view_iter_init (self);
+       iter != NULL;
+       iter = gtk_column_view_iter_next (self, iter))
+    {
+      gtk_column_list_item_factory_add_column (self->factory,
+                                               gtk_column_view_iter_get_item (self, iter),
+                                               column,
+                                               TRUE);
+    }
 }
 
 /**
@@ -428,6 +472,7 @@ void
 gtk_column_view_remove_column (GtkColumnView       *self,
                                GtkColumnViewColumn *column)
 {
+  GtkColumnViewIter *iter;
   guint i;
 
   g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
@@ -440,13 +485,22 @@ gtk_column_view_remove_column (GtkColumnView       *self,
 
       g_object_unref (item);
       if (item == column)
-        {
-          gtk_column_view_column_set_column_view (column, NULL);
-          g_list_store_remove (self->columns, i);
-          return;
-        }
+        break;
+    }
+
+  g_assert (i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)));
+
+  for (iter = gtk_column_view_iter_init (self);
+       iter != NULL;
+       iter = gtk_column_view_iter_next (self, iter))
+    {
+      gtk_column_list_item_factory_remove_column (self->factory,
+                                                  gtk_column_view_iter_get_item (self, iter),
+                                                  i,
+                                                  column);
     }
 
-  g_assert_not_reached ();
+  gtk_column_view_column_set_column_view (column, NULL);
+  g_list_store_remove (self->columns, i);
 }
 
diff --git a/gtk/gtkcolumnviewprivate.h b/gtk/gtkcolumnviewprivate.h
new file mode 100644
index 0000000000..c1b85a06e9
--- /dev/null
+++ b/gtk/gtkcolumnviewprivate.h
@@ -0,0 +1,35 @@
+/*
+ * 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_PRIVATE_H__
+#define __GTK_COLUMN_VIEW_PRIVATE_H__
+
+#include "gtk/gtkcolumnview.h"
+
+/* This is really just a GtkListItemManagerItem for now, but
+ * proper layering ftw */
+typedef struct _GtkColumnViewIter GtkColumnViewIter;
+
+GtkColumnViewIter *     gtk_column_view_iter_init               (GtkColumnView          *self);
+GtkListItem *           gtk_column_view_iter_get_item           (GtkColumnView          *self,
+                                                                 GtkColumnViewIter      *iter);
+GtkColumnViewIter *     gtk_column_view_iter_next               (GtkColumnView          *self,
+                                                                 GtkColumnViewIter      *iter);
+
+#endif  /* __GTK_COLUMN_VIEW_PRIVATE_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index bddf4d8f8e..2fdac1c2ca 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -204,6 +204,7 @@ gtk_public_sources = files([
   'gtkcolorchooserdialog.c',
   'gtkcolorchooserwidget.c',
   'gtkcolorutils.c',
+  'gtkcolumnlistitemfactory.c',
   'gtkcolumnview.c',
   'gtkcolumnviewcolumn.c',
   'gtkcombobox.c',


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