diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index beb6b2df87..3479a557b2 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -393,6 +393,20 @@ gtk_single_selection_get_type
+gtklistitemfactory +GtkListItemFactory +GtkListItemFactory + +GTK_LIST_ITEM_FACTORY +GTK_LIST_ITEM_FACTORY_CLASS +GTK_LIST_ITEM_FACTORY_GET_CLASS +GTK_IS_LIST_ITEM_FACTORY +GTK_IS_LIST_ITEM_FACTORY_CLASS +GTK_TYPE_LIST_ITEM_FACTORY + +gtk_list_item_factory_get_type +
+ gtklistview GtkListView GtkListView diff --git a/docs/reference/gtk/gtk4.types.in b/docs/reference/gtk/gtk4.types.in index 6ada01a6b7..30292ea74a 100644 --- a/docs/reference/gtk/gtk4.types.in +++ b/docs/reference/gtk/gtk4.types.in @@ -119,6 +119,7 @@ gtk_label_get_type gtk_layout_child_get_type gtk_layout_manager_get_type gtk_link_button_get_type +gtk_list_item_factory_get_type gtk_list_store_get_type gtk_list_box_get_type gtk_list_box_row_get_type diff --git a/docs/reference/gtk/meson.build b/docs/reference/gtk/meson.build index 07536264eb..bc28cbc7ed 100644 --- a/docs/reference/gtk/meson.build +++ b/docs/reference/gtk/meson.build @@ -132,6 +132,7 @@ private_headers = [ 'gtkimmoduleprivate.h', 'gtkkineticscrollingprivate.h', 'gtklabelprivate.h', + 'gtklistitemfactoryprivate.h', 'gtklockbuttonprivate.h', 'gtkmagnifierprivate.h', 'gtkmediafileprivate.h', diff --git a/gtk/gtklistitemfactory.c b/gtk/gtklistitemfactory.c new file mode 100644 index 0000000000..7519bc01bb --- /dev/null +++ b/gtk/gtklistitemfactory.c @@ -0,0 +1,153 @@ +/* + * Copyright © 2018 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 . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gtklistitemfactoryprivate.h" + +/** + * SECTION:gtklistitemfactory + * @Title: GtkListItemFactory + * @Short_description: Mapping list items to widgets + * + * #GtkListItemFactory is one of the core concepts of handling list widgets. + * It is the object tasked with creating widgets for items taken from a + * #GListModel when the views need them and updating them as the items + * displayed by the view change. + * + * A view is usually only able to display anything after both a factory + * and a model have been set on the view. So it is important that you do + * not skip this step when setting up your first view. + * + * Because views do not display the whole list at once but only a few + * items, they only need to maintain a few widgets at a time. They will + * instruct the #GtkListItemFactory to create these widgets and bind them + * to the items that are currently displayed. + * As the list model changes or the user scrolls to the list, the items will + * change and the view will instruct the factory to bind the widgets to those + * new items. + * + * The actual widgets used for displaying those widgets is provided by you. + * + * When the factory needs widgets created, it will create a #GtkListItem and + * hand it to your code to set up a widget for. This list item will provide + * various properties with information about what item to display and provide + * you with some opportunities to configure its behavior. See the #GtkListItem + * documentation for further details. + * + * Various implementations of #GtkListItemFactory exist to allow you different + * ways to provide those widgets. The most common implementations are + * #GtkBuilderListItemFactory which takes a #GtkBuilder .ui file and then creates + * and manages widgets everything automatically from the information in that file + * and #GtkSignalListItemFactory which allows you to connect to signals with your + * own code and retain full control over how the widgets are setup and managed. + * + * A #GtkListItemFactory is supposed to be final - that means its behavior should + * not change and the first widget created from it should behave the same way as + * the last widget created from it. + * If you intend to do changes to the behavior, it is recommended that you create + * a new #GtkListItemFactory which will allow the views to recreate its widgets. + * + * Once you have chosen your factory and created it, you need to set it on the + * view widget you want to use it with, such as via gtk_list_view_set_factory(). + * Reusing factories across different views is allowed, but very uncommon. + */ + +struct _GtkListItemFactory +{ + GObject parent_instance; + + GtkListCreateWidgetFunc create_func; + GtkListBindWidgetFunc bind_func; + gpointer user_data; + GDestroyNotify user_destroy; +}; + +struct _GtkListItemFactoryClass +{ + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (GtkListItemFactory, gtk_list_item_factory, G_TYPE_OBJECT) + +static void +gtk_list_item_factory_finalize (GObject *object) +{ + GtkListItemFactory *self = GTK_LIST_ITEM_FACTORY (object); + + if (self->user_destroy) + self->user_destroy (self->user_data); + + G_OBJECT_CLASS (gtk_list_item_factory_parent_class)->finalize (object); +} + +static void +gtk_list_item_factory_class_init (GtkListItemFactoryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gtk_list_item_factory_finalize; +} + +static void +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) +{ + GtkListItemFactory *self; + + g_return_val_if_fail (create_func, NULL); + g_return_val_if_fail (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->bind_func = bind_func; + self->user_data = user_data; + self->user_destroy = user_destroy; + + return self; +} + +GtkWidget * +gtk_list_item_factory_create (GtkListItemFactory *self) +{ + g_return_val_if_fail (GTK_IS_LIST_ITEM_FACTORY (self), NULL); + + return self->create_func (self->user_data); +} + +void +gtk_list_item_factory_bind (GtkListItemFactory *self, + GtkWidget *widget, + gpointer item) +{ + g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + self->bind_func (widget, item, self->user_data); +} + diff --git a/gtk/gtklistitemfactoryprivate.h b/gtk/gtklistitemfactoryprivate.h new file mode 100644 index 0000000000..28ae55b4aa --- /dev/null +++ b/gtk/gtklistitemfactoryprivate.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2018 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 . + * + * Authors: Benjamin Otte + */ + + +#ifndef __GTK_LIST_ITEM_FACTORY_H__ +#define __GTK_LIST_ITEM_FACTORY_H__ + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_LIST_ITEM_FACTORY (gtk_list_item_factory_get_type ()) +#define GTK_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_LIST_ITEM_FACTORY, GtkListItemFactory)) +#define GTK_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_LIST_ITEM_FACTORY, GtkListItemFactoryClass)) +#define GTK_IS_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_LIST_ITEM_FACTORY)) +#define GTK_IS_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_LIST_ITEM_FACTORY)) +#define GTK_LIST_ITEM_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_LIST_ITEM_FACTORY, GtkListItemFactoryClass)) + +typedef struct _GtkListItemFactory GtkListItemFactory; +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, + gpointer user_data, + GDestroyNotify user_destroy); + +GtkWidget * gtk_list_item_factory_create (GtkListItemFactory *self); + +void gtk_list_item_factory_bind (GtkListItemFactory *self, + GtkWidget *widget, + gpointer item); + + +G_END_DECLS + +#endif /* __GTK_LIST_ITEM_FACTORY_H__ */ diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c index d5f2ca3841..b8a5337d8a 100644 --- a/gtk/gtklistview.c +++ b/gtk/gtklistview.c @@ -22,7 +22,7 @@ #include "gtklistview.h" #include "gtkintl.h" -#include "gtkprivate.h" +#include "gtklistitemfactoryprivate.h" /** * SECTION:gtklistview @@ -38,6 +38,7 @@ struct _GtkListView GtkWidget parent_instance; GListModel *model; + GtkListItemFactory *item_factory; }; enum @@ -116,6 +117,8 @@ gtk_list_view_dispose (GObject *object) gtk_list_view_clear_model (self); + g_clear_object (&self->item_factory); + G_OBJECT_CLASS (gtk_list_view_parent_class)->dispose (object); } @@ -258,3 +261,20 @@ gtk_list_view_set_model (GtkListView *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); } +void +gtk_list_view_set_functions (GtkListView *self, + GtkListCreateWidgetFunc create_func, + GtkListBindWidgetFunc bind_func, + gpointer user_data, + GDestroyNotify user_destroy) +{ + 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 (user_data != NULL || user_destroy == NULL); + + g_clear_object (&self->item_factory); + + self->item_factory = gtk_list_item_factory_new (create_func, bind_func, user_data, user_destroy); +} + diff --git a/gtk/gtklistview.h b/gtk/gtklistview.h index 9329e21d75..541bf14874 100644 --- a/gtk/gtklistview.h +++ b/gtk/gtklistview.h @@ -28,6 +28,36 @@ 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 @@ -41,7 +71,12 @@ GListModel * gtk_list_view_get_model (GtkListView GDK_AVAILABLE_IN_ALL void gtk_list_view_set_model (GtkListView *self, GListModel *model); - +GDK_AVAILABLE_IN_ALL +void gtk_list_view_set_functions (GtkListView *self, + GtkListCreateWidgetFunc create_func, + GtkListBindWidgetFunc bind_func, + gpointer user_data, + GDestroyNotify user_destroy); G_END_DECLS diff --git a/gtk/meson.build b/gtk/meson.build index 8b221d7c3d..c1cb68daf4 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -271,6 +271,7 @@ gtk_public_sources = files([ 'gtklevelbar.c', 'gtklinkbutton.c', 'gtklistbox.c', + 'gtklistitemfactory.c', 'gtklistlistmodel.c', 'gtkliststore.c', 'gtklistview.c',