listitem: Add gtk_list_item_get_position()

Also refactor the whole list item management yet again.

Now, list item APIs doesn't have bind/unbind functions anymore, but only
property setters.

The item factory is the only one doing the binding.
As before, the item manager manages when items need to be bound.
This commit is contained in:
Benjamin Otte 2018-09-24 04:01:37 +02:00 committed by Matthias Clasen
parent 378a573cf4
commit fe14181d4e
9 changed files with 130 additions and 18 deletions

View File

@ -397,6 +397,7 @@ gtk_single_selection_get_type
<TITLE>GtkListItem</TITLE>
GtkListItem
gtk_list_item_get_item
gtk_list_item_get_position
gtk_list_item_get_child
gtk_list_item_set_child
<SUBSECTION Standard>

View File

@ -54,6 +54,7 @@ struct _GtkListItem
GObject *item;
GtkWidget *child;
guint position;
};
struct _GtkListItemClass
@ -66,6 +67,7 @@ enum
PROP_0,
PROP_CHILD,
PROP_ITEM,
PROP_POSITION,
N_PROPS
};
@ -103,6 +105,10 @@ gtk_list_item_get_property (GObject *object,
g_value_set_object (value, self->item);
break;
case PROP_POSITION:
g_value_set_uint (value, self->position);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -163,6 +169,18 @@ gtk_list_item_class_init (GtkListItemClass *klass)
G_TYPE_OBJECT,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GtkListItem:position:
*
* Position of the item
*/
properties[PROP_POSITION] =
g_param_spec_uint ("position",
P_("Position"),
P_("Position of the item"),
0, G_MAXUINT, GTK_INVALID_LIST_POSITION,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
/* This gets overwritten by gtk_list_item_new() but better safe than sorry */
@ -189,10 +207,10 @@ gtk_list_item_new (const char *css_name)
* gtk_list_item_get_item:
* @self: a #GtkListItem
*
* Gets the item that is currently displayed or model that @self is
* Gets the item that is currently displayed in model that @self is
* currently bound to or %NULL if @self is unbound.
*
* Returns: (nullable) (transfer none) (type GObject): The model in use
* Returns: (nullable) (transfer none) (type GObject): The item displayed
**/
gpointer
gtk_list_item_get_item (GtkListItem *self)
@ -252,28 +270,50 @@ gtk_list_item_set_child (GtkListItem *self,
}
void
gtk_list_item_bind (GtkListItem *self,
gpointer item)
gtk_list_item_set_item (GtkListItem *self,
gpointer item)
{
g_return_if_fail (GTK_IS_LIST_ITEM (self));
g_return_if_fail (G_IS_OBJECT (item));
/* Must unbind before rebinding */
g_return_if_fail (self->item == NULL);
g_return_if_fail (item == NULL || G_IS_OBJECT (item));
self->item = g_object_ref (item);
if (self->item == item)
return;
g_clear_object (&self->item);
if (item)
self->item = g_object_ref (item);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
}
/**
* gtk_list_item_get_position:
* @self: a #GtkListItem
*
* Gets the position in the model that @self currently displays.
* If @self is unbound, 0 is returned.
*
* Returns: The position of this item
**/
guint
gtk_list_item_get_position (GtkListItem *self)
{
g_return_val_if_fail (GTK_IS_LIST_ITEM (self), 0);
return self->position;
}
void
gtk_list_item_unbind (GtkListItem *self)
gtk_list_item_set_position (GtkListItem *self,
guint position)
{
g_return_if_fail (GTK_IS_LIST_ITEM (self));
/* Must be bound */
g_return_if_fail (self->item != NULL);
g_clear_object (&self->item);
if (self->position == position)
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
self->position = position;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_POSITION]);
}

View File

@ -44,6 +44,8 @@ GType gtk_list_item_get_type (void) G_GNUC_CO
GDK_AVAILABLE_IN_ALL
gpointer gtk_list_item_get_item (GtkListItem *self);
GDK_AVAILABLE_IN_ALL
guint gtk_list_item_get_position (GtkListItem *self);
GDK_AVAILABLE_IN_ALL
void gtk_list_item_set_child (GtkListItem *self,

View File

@ -153,14 +153,31 @@ gtk_list_item_factory_create (GtkListItemFactory *self)
void
gtk_list_item_factory_bind (GtkListItemFactory *self,
GtkListItem *list_item,
guint position,
gpointer item)
{
g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
gtk_list_item_bind (list_item, item);
g_object_freeze_notify (G_OBJECT (list_item));
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);
g_object_thaw_notify (G_OBJECT (list_item));
}
void
gtk_list_item_factory_update (GtkListItemFactory *self,
GtkListItem *list_item,
guint position)
{
g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
gtk_list_item_set_position (list_item, position);
}
void
@ -170,5 +187,10 @@ gtk_list_item_factory_unbind (GtkListItemFactory *self,
g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
gtk_list_item_unbind (list_item);
g_object_freeze_notify (G_OBJECT (list_item));
gtk_list_item_set_item (list_item, NULL);
gtk_list_item_set_position (list_item, 0);
g_object_thaw_notify (G_OBJECT (list_item));
}

View File

@ -47,7 +47,11 @@ GtkListItem * gtk_list_item_factory_create (GtkListItemFact
void gtk_list_item_factory_bind (GtkListItemFactory *self,
GtkListItem *list_item,
guint position,
gpointer item);
void gtk_list_item_factory_update (GtkListItemFactory *self,
GtkListItem *list_item,
guint position);
void gtk_list_item_factory_unbind (GtkListItemFactory *self,
GtkListItem *list_item);

View File

@ -236,7 +236,7 @@ gtk_list_item_manager_acquire_list_item (GtkListItemManager *self,
result = gtk_list_item_factory_create (self->factory);
item = g_list_model_get_item (self->model, position);
gtk_list_item_factory_bind (self->factory, result, item);
gtk_list_item_factory_bind (self->factory, result, position, item);
g_object_unref (item);
gtk_widget_insert_before (GTK_WIDGET (result), self->widget, next_sibling);
@ -274,6 +274,7 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager *self,
item = g_list_model_get_item (self->model, position);
if (g_hash_table_steal_extended (change->items, item, NULL, (gpointer *) &result))
{
gtk_list_item_factory_update (self->factory, result, position);
gtk_widget_insert_before (GTK_WIDGET (result), self->widget, next_sibling);
/* XXX: Should we let the listview do this? */
gtk_widget_queue_resize (GTK_WIDGET (result));
@ -287,6 +288,26 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager *self,
return GTK_WIDGET (result);
}
/**
* gtk_list_item_manager_update_list_item:
* @self: a #GtkListItemManager
* @item: a #GtkListItem that has been acquired
* @position: the new position of that list item
*
* Updates the position of the given @item. This function must be called whenever
* the position of an item changes, like when new items are added before it.
**/
void
gtk_list_item_manager_update_list_item (GtkListItemManager *self,
GtkWidget *item,
guint position)
{
g_return_if_fail (GTK_IS_LIST_ITEM_MANAGER (self));
g_return_if_fail (GTK_IS_LIST_ITEM (item));
gtk_list_item_factory_update (self->factory, GTK_LIST_ITEM (item), position);
}
/*
* gtk_list_item_manager_release_list_item:
* @self: a #GtkListItemManager

View File

@ -63,6 +63,9 @@ GtkWidget * gtk_list_item_manager_try_reacquire_list_item
GtkListItemManagerChange *change,
guint position,
GtkWidget *next_sibling);
void gtk_list_item_manager_update_list_item (GtkListItemManager *self,
GtkWidget *item,
guint position);
void gtk_list_item_manager_release_list_item (GtkListItemManager *self,
GtkListItemManagerChange *change,
GtkWidget *widget);

View File

@ -26,9 +26,10 @@ G_BEGIN_DECLS
GtkWidget * gtk_list_item_new (const char *css_name);
void gtk_list_item_bind (GtkListItem *self,
void gtk_list_item_set_item (GtkListItem *self,
gpointer item);
void gtk_list_item_unbind (GtkListItem *self);
void gtk_list_item_set_position (GtkListItem *self,
guint position);
G_END_DECLS

View File

@ -509,6 +509,22 @@ gtk_list_view_add_rows (GtkListView *self,
gtk_widget_queue_resize (GTK_WIDGET (self));
}
static void
gtk_list_view_update_rows (GtkListView *self,
guint position)
{
ListRow *row;
for (row = gtk_list_view_get_row (self, position, NULL);
row;
row = gtk_rb_tree_node_get_next (row))
{
gtk_list_item_manager_update_list_item (self->item_manager, row->widget, position);
position++;
}
}
static void
gtk_list_view_model_items_changed_cb (GListModel *model,
guint position,
@ -522,6 +538,8 @@ gtk_list_view_model_items_changed_cb (GListModel *model,
gtk_list_view_remove_rows (self, change, position, removed);
gtk_list_view_add_rows (self, change, position, added);
if (removed != added)
gtk_list_view_update_rows (self, position + added);
gtk_list_item_manager_end_change (self->item_manager, change);
}