diff --git a/demos/gtk-demo/dropdown.c b/demos/gtk-demo/dropdown.c index dcd43203f5..75b2415167 100644 --- a/demos/gtk-demo/dropdown.c +++ b/demos/gtk-demo/dropdown.c @@ -65,18 +65,22 @@ strings_setup_item_single_line (GtkSignalListItemFactory *factory, GtkListItem *item) { GtkWidget *box, *image, *title; + GtkWidget *checkmark; box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); image = gtk_image_new (); title = gtk_label_new (""); gtk_label_set_xalign (GTK_LABEL (title), 0.0); + checkmark = gtk_image_new_from_icon_name ("object-select-symbolic"); gtk_box_append (GTK_BOX (box), image); gtk_box_append (GTK_BOX (box), title); + gtk_box_append (GTK_BOX (box), checkmark); g_object_set_data (G_OBJECT (item), "title", title); g_object_set_data (G_OBJECT (item), "image", image); + g_object_set_data (G_OBJECT (item), "checkmark", checkmark); gtk_list_item_set_child (item, box); } @@ -86,6 +90,7 @@ strings_setup_item_full (GtkSignalListItemFactory *factory, GtkListItem *item) { GtkWidget *box, *box2, *image, *title, *description; + GtkWidget *checkmark; image = gtk_image_new (); title = gtk_label_new (""); @@ -93,6 +98,7 @@ strings_setup_item_full (GtkSignalListItemFactory *factory, description = gtk_label_new (""); gtk_label_set_xalign (GTK_LABEL (description), 0.0); gtk_widget_add_css_class (description, "dim-label"); + checkmark = gtk_image_new_from_icon_name ("object-select-symbolic"); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); @@ -101,26 +107,48 @@ strings_setup_item_full (GtkSignalListItemFactory *factory, gtk_box_append (GTK_BOX (box), box2); gtk_box_append (GTK_BOX (box2), title); gtk_box_append (GTK_BOX (box2), description); + gtk_box_append (GTK_BOX (box), checkmark); g_object_set_data (G_OBJECT (item), "title", title); g_object_set_data (G_OBJECT (item), "image", image); g_object_set_data (G_OBJECT (item), "description", description); + g_object_set_data (G_OBJECT (item), "checkmark", checkmark); gtk_list_item_set_child (item, box); } static void -strings_bind_item (GtkSignalListItemFactory *factory, - GtkListItem *item) +selected_item_changed (GtkDropDown *dropdown, + GParamSpec *pspec, + GtkListItem *item) { + GtkWidget *checkmark; + + checkmark = g_object_get_data (G_OBJECT (item), "checkmark"); + + if (gtk_drop_down_get_selected_item (dropdown) == gtk_list_item_get_item (item)) + gtk_widget_set_opacity (checkmark, 1.0); + else + gtk_widget_set_opacity (checkmark, 0.0); +} + +static void +strings_bind_item (GtkSignalListItemFactory *factory, + GtkListItem *item, + gpointer data) +{ + GtkDropDown *dropdown = data; GtkWidget *image, *title, *description; + GtkWidget *checkmark; StringHolder *holder; + GtkWidget *popup; holder = gtk_list_item_get_item (item); title = g_object_get_data (G_OBJECT (item), "title"); image = g_object_get_data (G_OBJECT (item), "image"); description = g_object_get_data (G_OBJECT (item), "description"); + checkmark = g_object_get_data (G_OBJECT (item), "checkmark"); gtk_label_set_label (GTK_LABEL (title), holder->title); if (image) @@ -133,19 +161,43 @@ strings_bind_item (GtkSignalListItemFactory *factory, gtk_label_set_label (GTK_LABEL (description), holder->description); gtk_widget_set_visible (description , holder->description != NULL); } + + popup = gtk_widget_get_ancestor (title, GTK_TYPE_POPOVER); + if (popup && gtk_widget_is_ancestor (popup, GTK_WIDGET (dropdown))) + { + gtk_widget_show (checkmark); + g_signal_connect (dropdown, "notify::selected-item", + G_CALLBACK (selected_item_changed), item); + selected_item_changed (dropdown, NULL, item); + } + else + { + gtk_widget_hide (checkmark); + } +} + +static void +strings_unbind_item (GtkSignalListItemFactory *factory, + GtkListItem *list_item, + gpointer data) +{ + GtkDropDown *dropdown = data; + + g_signal_handlers_disconnect_by_func (dropdown, selected_item_changed, list_item); } static GtkListItemFactory * -strings_factory_new (gboolean full) +strings_factory_new (gpointer data, gboolean full) { GtkListItemFactory *factory; factory = gtk_signal_list_item_factory_new (); if (full) - g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_full), NULL); + g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_full), data); else - g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_single_line), NULL); - g_signal_connect (factory, "bind", G_CALLBACK (strings_bind_item), NULL); + g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_single_line), data); + g_signal_connect (factory, "bind", G_CALLBACK (strings_bind_item), data); + g_signal_connect (factory, "unbind", G_CALLBACK (strings_unbind_item), data); return factory; } @@ -186,19 +238,22 @@ drop_down_new_from_strings (const char *const *titles, g_return_val_if_fail (descriptions == NULL || g_strv_length ((char **)icons) == g_strv_length ((char **)descriptions), NULL); model = strings_model_new (titles, icons, descriptions); - factory = strings_factory_new (FALSE); + widget = g_object_new (GTK_TYPE_DROP_DOWN, + "model", model, + NULL); + g_object_unref (model); + + factory = strings_factory_new (widget, FALSE); if (icons != NULL || descriptions != NULL) - list_factory = strings_factory_new (TRUE); + list_factory = strings_factory_new (widget, TRUE); else list_factory = NULL; - widget = g_object_new (GTK_TYPE_DROP_DOWN, - "model", model, - "factory", factory, - "list-factory", list_factory, - NULL); + g_object_set (widget, + "factory", factory, + "list-factory", list_factory, + NULL); - g_object_unref (model); g_object_unref (factory); if (list_factory) g_object_unref (list_factory); diff --git a/gtk/gtkdropdown.c b/gtk/gtkdropdown.c index 80dc7a1ae6..32e5c21c08 100644 --- a/gtk/gtkdropdown.c +++ b/gtk/gtkdropdown.c @@ -44,6 +44,7 @@ #include "gtkbuildable.h" #include "gtkbuilderprivate.h" #include "gtkstringlist.h" +#include "gtkbox.h" /** * SECTION:gtkdropdown @@ -537,11 +538,34 @@ setup_item (GtkSignalListItemFactory *factory, GtkListItem *list_item, gpointer data) { + GtkWidget *box; GtkWidget *label; + GtkWidget *icon; + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); label = gtk_label_new (NULL); gtk_label_set_xalign (GTK_LABEL (label), 0.0); - gtk_list_item_set_child (list_item, label); + gtk_box_append (GTK_BOX (box), label); + icon = gtk_image_new_from_icon_name ("object-select-symbolic"); + gtk_box_append (GTK_BOX (box), icon); + gtk_list_item_set_child (list_item, box); +} + +static void +selected_item_changed (GtkDropDown *self, + GParamSpec *pspec, + GtkListItem *list_item) +{ + GtkWidget *box; + GtkWidget *icon; + + box = gtk_list_item_get_child (list_item); + icon = gtk_widget_get_last_child (box); + + if (gtk_drop_down_get_selected_item (self) == gtk_list_item_get_item (list_item)) + gtk_widget_set_opacity (icon, 1.0); + else + gtk_widget_set_opacity (icon, 0.0); } static void @@ -551,11 +575,15 @@ bind_item (GtkSignalListItemFactory *factory, { GtkDropDown *self = data; gpointer item; + GtkWidget *box; GtkWidget *label; + GtkWidget *icon; GValue value = G_VALUE_INIT; item = gtk_list_item_get_item (list_item); - label = gtk_list_item_get_child (list_item); + box = gtk_list_item_get_child (list_item); + label = gtk_widget_get_first_child (box); + icon = gtk_widget_get_last_child (box); if (self->expression && gtk_expression_evaluate (self->expression, item, &value)) @@ -574,6 +602,28 @@ bind_item (GtkSignalListItemFactory *factory, { g_critical ("Either GtkDropDown:factory or GtkDropDown:expression must be set"); } + + if (gtk_widget_get_ancestor (box, GTK_TYPE_POPOVER) == self->popup) + { + gtk_widget_show (icon); + g_signal_connect (self, "notify::selected-item", + G_CALLBACK (selected_item_changed), list_item); + selected_item_changed (self, NULL, list_item); + } + else + { + gtk_widget_hide (icon); + } +} + +static void +unbind_item (GtkSignalListItemFactory *factory, + GtkListItem *list_item, + gpointer data) +{ + GtkDropDown *self = data; + + g_signal_handlers_disconnect_by_func (self, selected_item_changed, list_item); } static void @@ -585,6 +635,7 @@ set_default_factory (GtkDropDown *self) g_signal_connect (factory, "setup", G_CALLBACK (setup_item), self); g_signal_connect (factory, "bind", G_CALLBACK (bind_item), self); + g_signal_connect (factory, "unbind", G_CALLBACK (unbind_item), self); gtk_drop_down_set_factory (self, factory); diff --git a/gtk/ui/gtkdropdown.ui b/gtk/ui/gtkdropdown.ui index 5623663553..e2dbdaf4d1 100644 --- a/gtk/ui/gtkdropdown.ui +++ b/gtk/ui/gtkdropdown.ui @@ -59,6 +59,8 @@ 0 + 6 + 6 Search…