From e5add36a17cb64e6b300830f037d373bb8c0e031 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 24 Sep 2018 04:42:15 +0200 Subject: [PATCH] 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 | 29 +++++++++++++++++++++++- gtk/gtklistitemfactory.c | 27 +++++++++++----------- gtk/gtklistitemfactoryprivate.h | 4 ++-- gtk/gtklistview.c | 15 ++++++------- gtk/gtklistview.h | 35 +++-------------------------- tests/testlistview-animating.c | 40 +++++++++++++++++++++++---------- tests/testlistview.c | 22 ++++++++---------- 7 files changed, 90 insertions(+), 82 deletions(-) diff --git a/gtk/gtklistitem.h b/gtk/gtklistitem.h index ed7f21c45f..e26c57ba4d 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)) @@ -42,6 +41,34 @@ 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 d95752b21c..e102e25df3 100644 --- a/gtk/gtklistitemfactory.c +++ b/gtk/gtklistitemfactory.c @@ -75,8 +75,8 @@ struct _GtkListItemFactory { GObject parent_instance; - GtkListCreateWidgetFunc create_func; - GtkListBindWidgetFunc bind_func; + GtkListItemSetupFunc setup_func; + GtkListItemBindFunc bind_func; gpointer user_data; GDestroyNotify user_destroy; }; @@ -113,20 +113,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; @@ -137,15 +136,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); } @@ -164,7 +162,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 +#include 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 a750945d44..3a0b08dfab 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 +setup_list_item (GtkListItem *list_item, + gpointer unused) { - return gtk_label_new (""); + GtkWidget *label = gtk_label_new (""); + + gtk_list_item_set_child (list_item, label); } static void -bind_widget (GtkWidget *widget, - gpointer item, - gpointer unused) +bind_list_item (GtkListItem *list_item, + gpointer unused) { - const char *message = g_object_get_data (item, "message"); + GtkWidget *label; + gpointer item; + char *s; - gtk_label_set_text (GTK_LABEL (widget), message); + 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; + + label = gtk_list_item_get_child (list_item); + gtk_label_set_text (GTK_LABEL (label), s); + + g_free (s); } 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; } @@ -131,8 +147,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, + bind_list_item, NULL, NULL); gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview); diff --git a/tests/testlistview.c b/tests/testlistview.c index 1668fe2a18..6ccea18728 100644 --- a/tests/testlistview.c +++ b/tests/testlistview.c @@ -138,25 +138,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, - gpointer unused) +bind_widget (GtkListItem *list_item, + gpointer unused) { - GtkWidget *child; + GtkWidget *box, *child; GFileInfo *info; GFile *file; guint depth; GIcon *icon; + gpointer item; - while (gtk_widget_get_first_child (box)) - gtk_box_remove (GTK_BOX (box), gtk_widget_get_first_child (box)); + item = gtk_list_item_get_item (list_item); + + 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) @@ -300,7 +296,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_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);