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.
This commit is contained in:
Benjamin Otte 2018-09-24 04:42:15 +02:00 committed by Matthias Clasen
parent fe14181d4e
commit e5add36a17
7 changed files with 90 additions and 82 deletions

View File

@ -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

View File

@ -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));
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);