From b3fb80c60825813f9cdea24831404a885eb6fba2 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 29 Sep 2018 22:34:43 +0200 Subject: [PATCH] listview: Add selection properties to ListItem This just brings the infrastructure into place, we're not using the properties yet. --- docs/reference/gtk/gtk4-sections.txt | 3 + gtk/gtklistitem.c | 128 +++++++++++++++++++++++++++ gtk/gtklistitem.h | 8 ++ gtk/gtklistitemfactory.c | 13 ++- gtk/gtklistitemfactoryprivate.h | 6 +- gtk/gtklistitemmanager.c | 8 +- gtk/gtklistitemprivate.h | 2 + 7 files changed, 160 insertions(+), 8 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index c11db12cae..6c7e109204 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -400,6 +400,9 @@ gtk_list_item_get_item gtk_list_item_get_position gtk_list_item_get_child gtk_list_item_set_child +gtk_list_item_get_selected +gtk_list_item_get_selectable +gtk_list_item_set_selectable GTK_LIST_ITEM GTK_LIST_ITEM_CLASS diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c index ac4fda6737..a11b8b3cc8 100644 --- a/gtk/gtklistitem.c +++ b/gtk/gtklistitem.c @@ -55,6 +55,9 @@ struct _GtkListItem GObject *item; GtkWidget *child; guint position; + + guint selectable : 1; + guint selected : 1; }; struct _GtkListItemClass @@ -68,6 +71,8 @@ enum PROP_CHILD, PROP_ITEM, PROP_POSITION, + PROP_SELECTABLE, + PROP_SELECTED, N_PROPS }; @@ -109,6 +114,14 @@ gtk_list_item_get_property (GObject *object, g_value_set_uint (value, self->position); break; + case PROP_SELECTABLE: + g_value_set_boolean (value, self->selectable); + break; + + case PROP_SELECTED: + g_value_set_boolean (value, self->selected); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -129,6 +142,10 @@ gtk_list_item_set_property (GObject *object, gtk_list_item_set_child (self, g_value_get_object (value)); break; + case PROP_SELECTABLE: + gtk_list_item_set_selectable (self, g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -181,6 +198,30 @@ gtk_list_item_class_init (GtkListItemClass *klass) 0, G_MAXUINT, GTK_INVALID_LIST_POSITION, G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * GtkListItem:selectable: + * + * If the item can be selected by the user + */ + properties[PROP_SELECTABLE] = + g_param_spec_boolean ("selectable", + P_("Selectable"), + P_("If the item can be selected by the user"), + TRUE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GtkListItem:selected: + * + * If the item is currently selected + */ + properties[PROP_SELECTED] = + g_param_spec_boolean ("selected", + P_("Selected"), + P_("If the item is currently selected"), + FALSE, + 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 */ @@ -191,6 +232,7 @@ gtk_list_item_class_init (GtkListItemClass *klass) static void gtk_list_item_init (GtkListItem *self) { + self->selectable = TRUE; } GtkWidget * @@ -317,3 +359,89 @@ gtk_list_item_set_position (GtkListItem *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_POSITION]); } +/** + * gtk_list_item_get_selected: + * @self: a #GtkListItem + * + * Checks if the item is displayed as selected. The selected state is + * maintained by the container and its list model and cannot be set + * otherwise. + * + * Returns: %TRUE if the item is selected. + **/ +gboolean +gtk_list_item_get_selected (GtkListItem *self) +{ + g_return_val_if_fail (GTK_IS_LIST_ITEM (self), FALSE); + + return self->selected; +} + +void +gtk_list_item_set_selected (GtkListItem *self, + gboolean selected) +{ + g_return_if_fail (GTK_IS_LIST_ITEM (self)); + + if (self->selected == selected) + return; + + self->selected = selected; + + if (selected) + gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED, FALSE); + else + gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]); +} + +/** + * gtk_list_item_get_selectable: + * @self: a #GtkListItem + * + * Checks if a list item has been set to be selectable via + * gtk_list_item_set_selectable(). + * + * Do not confuse this function with gtk_list_item_get_selected(). + * + * Returns: %TRUE if the item is selectable + **/ +gboolean +gtk_list_item_get_selectable (GtkListItem *self) +{ + g_return_val_if_fail (GTK_IS_LIST_ITEM (self), FALSE); + + return self->selectable; +} + +/** + * gtk_list_item_set_selectable: + * @self: a #GtkListItem + * @selectable: if the item should be selectable + * + * Sets @self to be selectable. If an item is selectable, clicking + * on the item or using the keyboard will try to select or unselect + * the item. If this succeeds is up to the model to determine, as + * it is managing the selected state. + * + * Note that this means that making an item non-selectable has no + * influence on the selected state at all. A non-selectable item + * may still be selected. + * + * By default, list items are selectable. When rebinding them to + * a new item, they will also be reset to be selectable by GTK. + **/ +void +gtk_list_item_set_selectable (GtkListItem *self, + gboolean selectable) +{ + g_return_if_fail (GTK_IS_LIST_ITEM (self)); + + if (self->selectable == selectable) + return; + + self->selectable = selectable; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTABLE]); +} diff --git a/gtk/gtklistitem.h b/gtk/gtklistitem.h index e26c57ba4d..65d0dcdb68 100644 --- a/gtk/gtklistitem.h +++ b/gtk/gtklistitem.h @@ -73,6 +73,14 @@ 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 +gboolean gtk_list_item_get_selected (GtkListItem *self); +GDK_AVAILABLE_IN_ALL +gboolean gtk_list_item_get_selectable (GtkListItem *self); +GDK_AVAILABLE_IN_ALL +void gtk_list_item_set_selectable (GtkListItem *self, + gboolean selectable); + GDK_AVAILABLE_IN_ALL void gtk_list_item_set_child (GtkListItem *self, diff --git a/gtk/gtklistitemfactory.c b/gtk/gtklistitemfactory.c index e102e25df3..7a508aed45 100644 --- a/gtk/gtklistitemfactory.c +++ b/gtk/gtklistitemfactory.c @@ -152,7 +152,8 @@ void gtk_list_item_factory_bind (GtkListItemFactory *self, GtkListItem *list_item, guint position, - gpointer item) + gpointer item, + gboolean selected) { g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self)); g_return_if_fail (GTK_IS_LIST_ITEM (list_item)); @@ -161,6 +162,7 @@ gtk_list_item_factory_bind (GtkListItemFactory *self, gtk_list_item_set_item (list_item, item); gtk_list_item_set_position (list_item, position); + gtk_list_item_set_selected (list_item, selected); if (self->bind_func) self->bind_func (list_item, self->user_data); @@ -171,12 +173,18 @@ gtk_list_item_factory_bind (GtkListItemFactory *self, void gtk_list_item_factory_update (GtkListItemFactory *self, GtkListItem *list_item, - guint position) + guint position, + gboolean selected) { g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self)); g_return_if_fail (GTK_IS_LIST_ITEM (list_item)); + g_object_freeze_notify (G_OBJECT (list_item)); + gtk_list_item_set_position (list_item, position); + gtk_list_item_set_selected (list_item, selected); + + g_object_thaw_notify (G_OBJECT (list_item)); } void @@ -190,6 +198,7 @@ gtk_list_item_factory_unbind (GtkListItemFactory *self, gtk_list_item_set_item (list_item, NULL); gtk_list_item_set_position (list_item, 0); + gtk_list_item_set_selected (list_item, FALSE); g_object_thaw_notify (G_OBJECT (list_item)); } diff --git a/gtk/gtklistitemfactoryprivate.h b/gtk/gtklistitemfactoryprivate.h index 779251344b..3e815fa131 100644 --- a/gtk/gtklistitemfactoryprivate.h +++ b/gtk/gtklistitemfactoryprivate.h @@ -48,10 +48,12 @@ GtkListItem * gtk_list_item_factory_create (GtkListItemFact void gtk_list_item_factory_bind (GtkListItemFactory *self, GtkListItem *list_item, guint position, - gpointer item); + gpointer item, + gboolean selected); void gtk_list_item_factory_update (GtkListItemFactory *self, GtkListItem *list_item, - guint position); + guint position, + gboolean selected); void gtk_list_item_factory_unbind (GtkListItemFactory *self, GtkListItem *list_item); diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c index 62888f366a..1e74c8d8e1 100644 --- a/gtk/gtklistitemmanager.c +++ b/gtk/gtklistitemmanager.c @@ -262,7 +262,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, position, item); + gtk_list_item_factory_bind (self->factory, result, position, item, FALSE); g_object_unref (item); gtk_widget_insert_after (GTK_WIDGET (result), self->widget, prev_sibling); @@ -300,7 +300,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_list_item_factory_update (self->factory, result, position, FALSE); gtk_widget_insert_after (GTK_WIDGET (result), self->widget, prev_sibling); /* XXX: Should we let the listview do this? */ gtk_widget_queue_resize (GTK_WIDGET (result)); @@ -336,7 +336,7 @@ gtk_list_item_manager_move_list_item (GtkListItemManager *self, gpointer item; item = g_list_model_get_item (self->model, position); - gtk_list_item_factory_bind (self->factory, GTK_LIST_ITEM (list_item), position, item); + gtk_list_item_factory_bind (self->factory, GTK_LIST_ITEM (list_item), position, item, FALSE); gtk_widget_insert_after (list_item, _gtk_widget_get_parent (list_item), prev_sibling); g_object_unref (item); } @@ -358,7 +358,7 @@ gtk_list_item_manager_update_list_item (GtkListItemManager *self, 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_factory_update (self->factory, GTK_LIST_ITEM (item), position, FALSE); } /* diff --git a/gtk/gtklistitemprivate.h b/gtk/gtklistitemprivate.h index f238685c76..08ed82f162 100644 --- a/gtk/gtklistitemprivate.h +++ b/gtk/gtklistitemprivate.h @@ -30,6 +30,8 @@ void gtk_list_item_set_item (GtkListItem gpointer item); void gtk_list_item_set_position (GtkListItem *self, guint position); +void gtk_list_item_set_selected (GtkListItem *self, + gboolean selected); G_END_DECLS