[gtk/wip/otte/listview: 6/92] listview: Change how binding is done



commit f6a4d8049fee81181d82fa5a14d97fa72599ae1f
Author: Benjamin Otte <otte redhat com>
Date:   Mon Sep 24 04:42:15 2018 +0200

    listview: Change how binding is done
    
    We now don't let the functions create widgets for the item from the
    listmodel, instead we hand out a GtkListItem for them to add a widget
    to.
    
    GtkListItems are created in advance and can only be filled in by the
    binding code by gtk_container_add()ing a widget.
    However, they are GObjects, so they can provide properties that the
    binding code can make use of - either via notify signals or GBinding.

 gtk/gtklistitem.h               | 30 ++++++++++++++++++++++++++++--
 gtk/gtklistitemfactory.c        | 27 +++++++++++++--------------
 gtk/gtklistitemfactoryprivate.h |  4 ++--
 gtk/gtklistview.c               | 15 +++++++--------
 gtk/gtklistview.h               | 35 +++--------------------------------
 tests/testlistview-animating.c  | 40 ++++++++++++++++++++++++++++------------
 tests/testlistview.c            | 20 ++++++++------------
 7 files changed, 89 insertions(+), 82 deletions(-)
---
diff --git a/gtk/gtklistitem.h b/gtk/gtklistitem.h
index ed7f21c45f..dff9c889ee 100644
--- a/gtk/gtklistitem.h
+++ b/gtk/gtklistitem.h
@@ -28,7 +28,6 @@
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_LIST_ITEM         (gtk_list_item_get_type ())
 #define GTK_TYPE_LIST_ITEM         (gtk_list_item_get_type ())
 #define GTK_LIST_ITEM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_LIST_ITEM, GtkListItem))
 #define GTK_LIST_ITEM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_LIST_ITEM, GtkListItemClass))
@@ -39,9 +38,36 @@ G_BEGIN_DECLS
 typedef struct _GtkListItem GtkListItem;
 typedef struct _GtkListItemClass GtkListItemClass;
 
-GDK_AVAILABLE_IN_ALL
 GType           gtk_list_item_get_type                          (void) G_GNUC_CONST;
 
+/**
+ * GtkListItemSetupFunc:
+ * @item: the #GtkListItem to set up
+ * @user_data: (closure): user data
+ *
+ * Called whenever a new list item needs to be setup for managing a row in
+ * the list.
+ *
+ * At this point, the list item is not bound yet, so gtk_list_item_get_item()
+ * will return %NULL.
+ * The list item will later be bound to an item via the #GtkListItemBindFunc.
+ */
+typedef void (* GtkListItemSetupFunc) (GtkListItem *item, gpointer user_data);
+
+/**
+ * GtkListItemBindFunc:
+ * @item: the #GtkListItem to bind
+ * @user_data: (closure): user data
+ *
+ * Binds a#GtkListItem previously set up via a #GtkListItemSetupFunc to
+ * an @item.
+ *
+ * Rebinding a @item to different @items is supported as well as
+ * unbinding it by setting @item to %NULL.
+ */
+typedef void (* GtkListItemBindFunc) (GtkListItem *item,
+                                      gpointer   user_data);
+
 GDK_AVAILABLE_IN_ALL
 gpointer        gtk_list_item_get_item                          (GtkListItem            *self);
 GDK_AVAILABLE_IN_ALL
diff --git a/gtk/gtklistitemfactory.c b/gtk/gtklistitemfactory.c
index 684380f3b1..c8e60bc163 100644
--- a/gtk/gtklistitemfactory.c
+++ b/gtk/gtklistitemfactory.c
@@ -27,8 +27,8 @@ struct _GtkListItemFactory
 {
   GObject parent_instance;
 
-  GtkListCreateWidgetFunc create_func;
-  GtkListBindWidgetFunc bind_func;
+  GtkListItemSetupFunc setup_func;
+  GtkListItemBindFunc bind_func;
   gpointer user_data;
   GDestroyNotify user_destroy;
 };
@@ -65,20 +65,19 @@ gtk_list_item_factory_init (GtkListItemFactory *self)
 }
 
 GtkListItemFactory *
-gtk_list_item_factory_new (GtkListCreateWidgetFunc create_func,
-                           GtkListBindWidgetFunc   bind_func,
-                           gpointer                user_data,
-                           GDestroyNotify          user_destroy)
+gtk_list_item_factory_new (GtkListItemSetupFunc setup_func,
+                           GtkListItemBindFunc  bind_func,
+                           gpointer             user_data,
+                           GDestroyNotify       user_destroy)
 {
   GtkListItemFactory *self;
 
-  g_return_val_if_fail (create_func, NULL);
-  g_return_val_if_fail (bind_func, NULL);
+  g_return_val_if_fail (setup_func || bind_func, NULL);
   g_return_val_if_fail (user_data != NULL || user_destroy == NULL, NULL);
 
   self = g_object_new (GTK_TYPE_LIST_ITEM_FACTORY, NULL);
 
-  self->create_func = create_func;
+  self->setup_func = setup_func;
   self->bind_func = bind_func;
   self->user_data = user_data;
   self->user_destroy = user_destroy;
@@ -89,15 +88,14 @@ gtk_list_item_factory_new (GtkListCreateWidgetFunc create_func,
 GtkListItem *
 gtk_list_item_factory_create (GtkListItemFactory *self)
 {
-  GtkWidget *widget, *result;
+  GtkWidget *result;
 
   g_return_val_if_fail (GTK_IS_LIST_ITEM_FACTORY (self), NULL);
 
-  widget = self->create_func (self->user_data);
-
   result = gtk_list_item_new ("row");
 
-  gtk_list_item_set_child (GTK_LIST_ITEM (result), widget);
+  if (self->setup_func)
+    self->setup_func (GTK_LIST_ITEM (result), self->user_data);
 
   return GTK_LIST_ITEM (result);
 }
@@ -116,7 +114,8 @@ gtk_list_item_factory_bind (GtkListItemFactory *self,
   gtk_list_item_set_item (list_item, item);
   gtk_list_item_set_position (list_item, position);
 
-  self->bind_func (gtk_list_item_get_child (list_item), item, self->user_data);
+  if (self->bind_func)  
+    self->bind_func (list_item, self->user_data);
 
   g_object_thaw_notify (G_OBJECT (list_item));
 }
diff --git a/gtk/gtklistitemfactoryprivate.h b/gtk/gtklistitemfactoryprivate.h
index 21bc5b5586..779251344b 100644
--- a/gtk/gtklistitemfactoryprivate.h
+++ b/gtk/gtklistitemfactoryprivate.h
@@ -38,8 +38,8 @@ typedef struct _GtkListItemFactoryClass GtkListItemFactoryClass;
 
 GType                   gtk_list_item_factory_get_type          (void) G_GNUC_CONST;
 
-GtkListItemFactory *    gtk_list_item_factory_new               (GtkListCreateWidgetFunc create_func,
-                                                                 GtkListBindWidgetFunc   bind_func,
+GtkListItemFactory *    gtk_list_item_factory_new               (GtkListItemSetupFunc    setup_func,
+                                                                 GtkListItemBindFunc     bind_func,
                                                                  gpointer                user_data,
                                                                  GDestroyNotify          user_destroy);
 
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index 1539a2a530..36e710ab18 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -872,24 +872,23 @@ gtk_list_view_set_model (GtkListView *self,
 }
 
 void
-gtk_list_view_set_functions (GtkListView            *self,
-                             GtkListCreateWidgetFunc create_func,
-                             GtkListBindWidgetFunc   bind_func,
-                             gpointer                user_data,
-                             GDestroyNotify          user_destroy)
+gtk_list_view_set_functions (GtkListView          *self,
+                             GtkListItemSetupFunc  setup_func,
+                             GtkListItemBindFunc   bind_func,
+                             gpointer              user_data,
+                             GDestroyNotify        user_destroy)
 {
   GtkListItemFactory *factory;
   guint n_items;
 
   g_return_if_fail (GTK_IS_LIST_VIEW (self));
-  g_return_if_fail (create_func);
-  g_return_if_fail (bind_func);
+  g_return_if_fail (setup_func || bind_func);
   g_return_if_fail (user_data != NULL || user_destroy == NULL);
 
   n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
   gtk_list_view_remove_rows (self, NULL, 0, n_items);
 
-  factory = gtk_list_item_factory_new (create_func, bind_func, user_data, user_destroy);
+  factory = gtk_list_item_factory_new (setup_func, bind_func, user_data, user_destroy);
   gtk_list_item_manager_set_factory (self->item_manager, factory);
   g_object_unref (factory);
 
diff --git a/gtk/gtklistview.h b/gtk/gtklistview.h
index 541bf14874..4d1a0a5d77 100644
--- a/gtk/gtklistview.h
+++ b/gtk/gtklistview.h
@@ -25,39 +25,10 @@
 #endif
 
 #include <gtk/gtkwidget.h>
+#include <gtk/gtklistitem.h>
 
 G_BEGIN_DECLS
 
-/**
- * GtkListCreateWidgetFunc:
- * @user_data: (closure): user data
- *
- * Called whenever a new widget needs to be created for managing a row in
- * the list.
- *
- * The widget will later be bound to an item via the #GtkListBindWidgetFunc.
- *
- * Returns: (transfer full): a #GtkWidget
- */
-typedef GtkWidget * (* GtkListCreateWidgetFunc) (gpointer user_data);
-
-/**
- * GtkListBindWidgetFunc:
- * @widget: The #GtkWidget to bind
- * @item: (type GObject) (allow-none): item to bind or %NULL to unbind
- *     the widget.
- * @user_data: (closure): user data
- *
- * Binds a widget previously created via a #GtkListCreateWidgetFunc to
- * an @item.
- *
- * Rebinding a @widget to different @items is supported as well as
- * unbinding it by setting @item to %NULL.
- */
-typedef void (* GtkListBindWidgetFunc) (GtkWidget *widget,
-                                        gpointer   item,
-                                        gpointer   user_data);
-
 #define GTK_TYPE_LIST_VIEW         (gtk_list_view_get_type ())
 
 GDK_AVAILABLE_IN_ALL
@@ -73,8 +44,8 @@ void            gtk_list_view_set_model                         (GtkListView
                                                                  GListModel             *model);
 GDK_AVAILABLE_IN_ALL
 void            gtk_list_view_set_functions                     (GtkListView            *self,
-                                                                 GtkListCreateWidgetFunc create_func,
-                                                                 GtkListBindWidgetFunc   bind_func,
+                                                                 GtkListItemSetupFunc    setup_func,
+                                                                 GtkListItemBindFunc     bind_func,
                                                                  gpointer                user_data,
                                                                  GDestroyNotify          user_destroy);
 
diff --git a/tests/testlistview-animating.c b/tests/testlistview-animating.c
index 6124bbd906..07ba7d8e8d 100644
--- a/tests/testlistview-animating.c
+++ b/tests/testlistview-animating.c
@@ -8,30 +8,46 @@
 #define VARIANCE 200
 #endif
 
-static GtkWidget *
-create_widget (gpointer unused)
+static void
+update_label (GtkListItem *list_item,
+              GParamSpec  *pspec,
+              GtkLabel    *label)
 {
-  return gtk_label_new ("");
+  gpointer item;
+  char *s;
+
+  item = gtk_list_item_get_item (list_item);
+
+  if (item)
+    s = g_strdup_printf ("%u: %s",
+                         gtk_list_item_get_position (list_item),
+                         (const char *) g_object_get_data (item, "message"));
+  else
+    s = NULL;
+
+  gtk_label_set_text (label, s);
+
+  g_free (s);
 }
 
 static void
-bind_widget (GtkWidget *widget,
-             gpointer   item,
-             gpointer   unused)
+setup_list_item (GtkListItem *list_item,
+                 gpointer     unused)
 {
-  const char *message = g_object_get_data (item, "message");
+  GtkWidget *label = gtk_label_new ("");
 
-  gtk_label_set_text (GTK_LABEL (widget), message);
+  g_signal_connect (list_item, "notify", G_CALLBACK (update_label), label);
+  gtk_list_item_set_child (list_item, label);
 }
 
 static GtkWidget *
 create_widget_for_listbox (gpointer item,
                            gpointer unused)
 {
+  const char *message = g_object_get_data (item, "message");
   GtkWidget *widget;
 
-  widget = create_widget (unused);
-  bind_widget (widget, item, unused);
+  widget = gtk_label_new (message);
 
   return widget;
 }
@@ -139,8 +155,8 @@ main (int   argc,
 
   listview = gtk_list_view_new ();
   gtk_list_view_set_functions (GTK_LIST_VIEW (listview),
-                               create_widget,
-                               bind_widget,
+                               setup_list_item,
+                               NULL,
                                NULL, NULL);
   gtk_container_add (GTK_CONTAINER (sw), listview);
 
diff --git a/tests/testlistview.c b/tests/testlistview.c
index 5905ed53f6..27d82f8823 100644
--- a/tests/testlistview.c
+++ b/tests/testlistview.c
@@ -161,25 +161,21 @@ create_list_model_for_directory (gpointer file)
   return G_LIST_MODEL (sort);
 }
 
-static GtkWidget *
-create_widget (gpointer unused)
-{
-  return gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
-}
-
 static void
-bind_widget (GtkWidget *box,
-             gpointer   item,
+bind_widget (GtkListItem *list_item,
              gpointer   unused)
 {
-  GtkWidget *child;
+  GtkWidget *box, *child;
   GFileInfo *info;
   GFile *file;
   guint depth;
   GIcon *icon;
+  gpointer item;
+
+  item = gtk_list_item_get_item (list_item);
 
-  while (gtk_widget_get_first_child (box))
-    gtk_container_remove (GTK_CONTAINER (box), gtk_widget_get_first_child (box));
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+  gtk_list_item_set_child (list_item, box);
 
   depth = gtk_tree_list_row_get_depth (item);
   if (depth > 0)
@@ -317,7 +313,7 @@ main (int argc, char *argv[])
 
   listview = gtk_list_view_new ();
   gtk_list_view_set_functions (GTK_LIST_VIEW (listview),
-                               create_widget,
+                               NULL,
                                bind_widget,
                                NULL, NULL);
   gtk_container_add (GTK_CONTAINER (sw), listview);


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