forked from AuroraMiddleware/gtk
gtklistbox: add bind_model()
gtk_list_box_bind_model() binds a GListModel to a GtkListBox. This is a first step towards having GListModel support in Gtk. It's not useful for large models, because GtkListBox always creates all widgets for all rows.
This commit is contained in:
parent
9141eeb60e
commit
d825249b42
@ -550,6 +550,8 @@ gtk_list_box_set_header_func
|
|||||||
gtk_list_box_set_sort_func
|
gtk_list_box_set_sort_func
|
||||||
gtk_list_box_drag_highlight_row
|
gtk_list_box_drag_highlight_row
|
||||||
gtk_list_box_drag_unhighlight_row
|
gtk_list_box_drag_unhighlight_row
|
||||||
|
GtkListBoxCreateWidgetFunc
|
||||||
|
gtk_list_box_bind_model
|
||||||
|
|
||||||
gtk_list_box_row_new
|
gtk_list_box_row_new
|
||||||
gtk_list_box_row_changed
|
gtk_list_box_row_changed
|
||||||
|
112
gtk/gtklistbox.c
112
gtk/gtklistbox.c
@ -99,6 +99,11 @@ typedef struct
|
|||||||
|
|
||||||
int n_visible_rows;
|
int n_visible_rows;
|
||||||
gboolean in_widget;
|
gboolean in_widget;
|
||||||
|
|
||||||
|
GListModel *bound_model;
|
||||||
|
GtkListBoxCreateWidgetFunc create_widget_func;
|
||||||
|
gpointer create_widget_func_data;
|
||||||
|
GDestroyNotify create_widget_func_data_destroy;
|
||||||
} GtkListBoxPrivate;
|
} GtkListBoxPrivate;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -260,6 +265,12 @@ static void gtk_list_box_update_row_styles (GtkListBox *box);
|
|||||||
static void gtk_list_box_update_row_style (GtkListBox *box,
|
static void gtk_list_box_update_row_style (GtkListBox *box,
|
||||||
GtkListBoxRow *row);
|
GtkListBoxRow *row);
|
||||||
|
|
||||||
|
static void gtk_list_box_bound_model_changed (GListModel *list,
|
||||||
|
guint position,
|
||||||
|
guint removed,
|
||||||
|
guint added,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
|
static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
static GParamSpec *row_properties[LAST_ROW_PROPERTY] = { NULL, };
|
static GParamSpec *row_properties[LAST_ROW_PROPERTY] = { NULL, };
|
||||||
@ -374,6 +385,15 @@ gtk_list_box_finalize (GObject *obj)
|
|||||||
g_sequence_free (priv->children);
|
g_sequence_free (priv->children);
|
||||||
g_hash_table_unref (priv->header_hash);
|
g_hash_table_unref (priv->header_hash);
|
||||||
|
|
||||||
|
if (priv->bound_model)
|
||||||
|
{
|
||||||
|
if (priv->create_widget_func_data_destroy)
|
||||||
|
priv->create_widget_func_data_destroy (priv->create_widget_func_data);
|
||||||
|
|
||||||
|
g_signal_handlers_disconnect_by_func (priv->bound_model, gtk_list_box_bound_model_changed, obj);
|
||||||
|
g_clear_object (&priv->bound_model);
|
||||||
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_list_box_parent_class)->finalize (obj);
|
G_OBJECT_CLASS (gtk_list_box_parent_class)->finalize (obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3561,3 +3581,95 @@ gtk_list_box_buildable_interface_init (GtkBuildableIface *iface)
|
|||||||
{
|
{
|
||||||
iface->add_child = gtk_list_box_buildable_add_child;
|
iface->add_child = gtk_list_box_buildable_add_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_list_box_bound_model_changed (GListModel *list,
|
||||||
|
guint position,
|
||||||
|
guint removed,
|
||||||
|
guint added,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkListBox *box = user_data;
|
||||||
|
GtkListBoxPrivate *priv = BOX_PRIV (user_data);
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
while (removed--)
|
||||||
|
{
|
||||||
|
GtkListBoxRow *row;
|
||||||
|
|
||||||
|
row = gtk_list_box_get_row_at_index (box, position);
|
||||||
|
gtk_widget_destroy (GTK_WIDGET (row));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < added; i++)
|
||||||
|
{
|
||||||
|
GObject *item;
|
||||||
|
GtkWidget *widget;
|
||||||
|
|
||||||
|
item = g_list_model_get_item (list, position + i);
|
||||||
|
widget = priv->create_widget_func (item, priv->create_widget_func_data);
|
||||||
|
gtk_widget_show_all (widget);
|
||||||
|
gtk_list_box_insert (box, widget, position + i);
|
||||||
|
|
||||||
|
g_object_unref (item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_list_box_bind_model:
|
||||||
|
* @box: a #GtkListBox
|
||||||
|
* @model: (allow-none): the #GListModel to be bound to @box
|
||||||
|
* @create_widget_func: a function that creates widgets for items
|
||||||
|
* @user_data: user data passed to @create_widget_func
|
||||||
|
* @user_data_free_func: function for freeing @user_data
|
||||||
|
*
|
||||||
|
* Binds @model to @box.
|
||||||
|
*
|
||||||
|
* If @box was already bound to a model, that previous binding is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* The contents of @box are cleared and then filled with widgets that
|
||||||
|
* represent items from @model. @box is updated whenever @model changes.
|
||||||
|
* If @model is %NULL, @box is left empty.
|
||||||
|
*
|
||||||
|
* It is undefined to add or remove widgets directly (for example, with
|
||||||
|
* gtk_list_box_insert() or gtk_container_add()) while @box is bound to a
|
||||||
|
* model.
|
||||||
|
*
|
||||||
|
* Since: 3.16
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gtk_list_box_bind_model (GtkListBox *box,
|
||||||
|
GListModel *model,
|
||||||
|
GtkListBoxCreateWidgetFunc create_widget_func,
|
||||||
|
gpointer user_data,
|
||||||
|
GDestroyNotify user_data_free_func)
|
||||||
|
{
|
||||||
|
GtkListBoxPrivate *priv = BOX_PRIV (box);
|
||||||
|
|
||||||
|
g_return_if_fail (GTK_IS_LIST_BOX (box));
|
||||||
|
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||||
|
g_return_if_fail (model == NULL || create_widget_func != NULL);
|
||||||
|
|
||||||
|
if (priv->bound_model)
|
||||||
|
{
|
||||||
|
if (priv->create_widget_func_data_destroy)
|
||||||
|
priv->create_widget_func_data_destroy (priv->create_widget_func_data);
|
||||||
|
|
||||||
|
g_signal_handlers_disconnect_by_func (priv->bound_model, gtk_list_box_bound_model_changed, box);
|
||||||
|
g_clear_object (&priv->bound_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_list_box_forall_internal (GTK_CONTAINER (box), FALSE, (GtkCallback) gtk_widget_destroy, NULL);
|
||||||
|
|
||||||
|
if (model == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->bound_model = g_object_ref (model);
|
||||||
|
priv->create_widget_func = create_widget_func;
|
||||||
|
priv->create_widget_func_data = user_data;
|
||||||
|
priv->create_widget_func_data_destroy = user_data_free_func;
|
||||||
|
|
||||||
|
g_signal_connect (priv->bound_model, "items-changed", G_CALLBACK (gtk_list_box_bound_model_changed), box);
|
||||||
|
gtk_list_box_bound_model_changed (model, 0, 0, g_list_model_get_n_items (model), box);
|
||||||
|
}
|
||||||
|
@ -169,6 +169,20 @@ typedef void (*GtkListBoxUpdateHeaderFunc) (GtkListBoxRow *row,
|
|||||||
GtkListBoxRow *before,
|
GtkListBoxRow *before,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GtkListBoxCreateWidgetFunc:
|
||||||
|
* @item: the item from the model for which to create a widget for
|
||||||
|
*
|
||||||
|
* Called for list boxes that are bound to a #GListModel with
|
||||||
|
* gtk_list_box_bind_model() for each item that gets added to the model.
|
||||||
|
*
|
||||||
|
* Returns: a #GtkWidget that represents @item
|
||||||
|
*
|
||||||
|
* Since: 3.16
|
||||||
|
*/
|
||||||
|
typedef GtkWidget * (*GtkListBoxCreateWidgetFunc) (gpointer item,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
GDK_AVAILABLE_IN_3_10
|
GDK_AVAILABLE_IN_3_10
|
||||||
GType gtk_list_box_row_get_type (void) G_GNUC_CONST;
|
GType gtk_list_box_row_get_type (void) G_GNUC_CONST;
|
||||||
GDK_AVAILABLE_IN_3_10
|
GDK_AVAILABLE_IN_3_10
|
||||||
@ -286,6 +300,12 @@ GDK_AVAILABLE_IN_3_10
|
|||||||
GtkWidget* gtk_list_box_new (void);
|
GtkWidget* gtk_list_box_new (void);
|
||||||
|
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_3_16
|
||||||
|
void gtk_list_box_bind_model (GtkListBox *box,
|
||||||
|
GListModel *model,
|
||||||
|
GtkListBoxCreateWidgetFunc create_widget_func,
|
||||||
|
gpointer user_data,
|
||||||
|
GDestroyNotify user_data_free_func);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user