[gtk+/popover-menu-buttons2] Add support for extra widgets to model-based popovers
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/popover-menu-buttons2] Add support for extra widgets to model-based popovers
- Date: Sat, 18 Jul 2015 00:26:47 +0000 (UTC)
commit a9f6601368538f1008479d615d20da5195b8b385
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Apr 16 16:01:56 2014 -0700
Add support for extra widgets to model-based popovers
This allows to insert custom widgetry in the middle of model-based
popovers.
https://bugzilla.gnome.org/show_bug.cgi?id=727477
gtk/gtkmenutrackeritem.c | 6 +++
gtk/gtkmenutrackeritem.h | 2 +
gtk/gtkpopover.c | 45 ++++++++++++++++++++
gtk/gtkpopover.h | 9 ++++
tests/popover.ui | 17 ++++++++
tests/testpopover.c | 103 ++++++++++++++++++++++++++++++++++++++++++++-
6 files changed, 179 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkmenutrackeritem.c b/gtk/gtkmenutrackeritem.c
index 8477a6b..2ed6010 100644
--- a/gtk/gtkmenutrackeritem.c
+++ b/gtk/gtkmenutrackeritem.c
@@ -901,3 +901,9 @@ _gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self)
{
return self->hidden_when != HIDDEN_NEVER;
}
+
+GMenuItem *
+gtk_menu_tracker_item_get_item (GtkMenuTrackerItem *self)
+{
+ return self->item;
+}
diff --git a/gtk/gtkmenutrackeritem.h b/gtk/gtkmenutrackeritem.h
index 2d9ff16..eebbccf 100644
--- a/gtk/gtkmenutrackeritem.h
+++ b/gtk/gtkmenutrackeritem.h
@@ -87,4 +87,6 @@ void gtk_menu_tracker_item_request_submenu_shown (GtkMenu
gboolean gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self);
+GMenuItem *gtk_menu_tracker_item_get_item (GtkMenuTrackerItem *self);
+
#endif
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index d9ce632..cb9e6b8 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -1895,6 +1895,11 @@ gtk_popover_get_modal (GtkPopover *popover)
return popover->priv->modal;
}
+typedef struct {
+ GtkModelWidgetCallback *callback;
+ gpointer data;
+} TrackerData;
+
static void
gtk_popover_tracker_remove_func (gint position,
gpointer user_data)
@@ -1995,6 +2000,9 @@ gtk_popover_tracker_insert_func (GtkMenuTrackerItem *item,
GtkWidget *stack;
GtkWidget *widget;
GtkSizeGroup *group;
+ TrackerData *data;
+
+ data = (TrackerData*)g_object_get_data (G_OBJECT (box), "trackerdata");
stack = gtk_widget_get_ancestor (box, GTK_TYPE_STACK);
group = g_object_get_data (G_OBJECT (stack), "size-group");
@@ -2045,6 +2053,7 @@ gtk_popover_tracker_insert_func (GtkMenuTrackerItem *item,
GtkWidget *child;
GtkWidget *button;
GtkWidget *content;
+ TrackerData *tracker_data;
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
g_object_set (child, "margin", 10, NULL);
@@ -2084,12 +2093,33 @@ gtk_popover_tracker_insert_func (GtkMenuTrackerItem *item,
gtk_widget_set_halign (content, GTK_ALIGN_FILL);
gtk_widget_show (content);
gtk_container_add (GTK_CONTAINER (child), content);
+ tracker_data = g_new0 (TrackerData, 1);
+ tracker_data->callback = data->callback;
+ tracker_data->data = data->data;
+ g_object_set_data_full (G_OBJECT (content), "trackerdata", tracker_data, g_free);
+
tracker = gtk_menu_tracker_new_for_item_submenu (item, gtk_popover_tracker_insert_func,
gtk_popover_tracker_remove_func, content);
g_object_set_data_full (G_OBJECT (widget), "submenutracker", tracker,
(GDestroyNotify)gtk_menu_tracker_free);
gtk_widget_show (widget);
}
+ else if (gtk_menu_tracker_item_get_special (item))
+ {
+ const gchar *special;
+
+ special = gtk_menu_tracker_item_get_special (item);
+ if (data->callback)
+ widget = data->callback (gtk_menu_tracker_item_get_item (item), data->data);
+ else
+ widget = NULL;
+
+ if (!widget)
+ {
+ g_warning ("No extra widget with id '%s' provided", special);
+ return;
+ }
+ }
else
{
widget = gtk_model_button_new ();
@@ -2158,12 +2188,23 @@ gtk_popover_bind_model (GtkPopover *popover,
GMenuModel *model,
const gchar *action_namespace)
{
+ gtk_popover_bind_model_with_extra_widgets (popover, model, action_namespace, NULL, NULL);
+}
+
+void
+gtk_popover_bind_model_with_extra_widgets (GtkPopover *popover,
+ GMenuModel *model,
+ const gchar *action_namespace,
+ GtkModelWidgetCallback *callback,
+ gpointer data)
+{
GtkActionMuxer *muxer;
GtkWidget *child;
GtkWidget *stack;
GtkWidget *box;
GtkPopoverPrivate *priv;
GtkSizeGroup *group;
+ TrackerData *tracker_data;
g_return_if_fail (GTK_IS_POPOVER (popover));
g_return_if_fail (model == NULL || G_IS_MENU_MODEL (model));
@@ -2197,6 +2238,10 @@ gtk_popover_bind_model (GtkPopover *popover,
g_signal_connect (popover, "unmap", G_CALLBACK (back_to_main), NULL);
g_signal_connect (popover, "map", G_CALLBACK (back_to_main), NULL);
+ tracker_data = g_new0 (TrackerData, 1);
+ tracker_data->callback = callback;
+ tracker_data->data = data;
+ g_object_set_data_full (G_OBJECT (box), "trackerdata", tracker_data, g_free);
priv->tracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (muxer),
model,
TRUE,
diff --git a/gtk/gtkpopover.h b/gtk/gtkpopover.h
index d4baf82..59ecaac 100644
--- a/gtk/gtkpopover.h
+++ b/gtk/gtkpopover.h
@@ -97,6 +97,15 @@ void gtk_popover_bind_model (GtkPopover *popover,
GMenuModel *model,
const gchar *action_namespace);
+typedef GtkWidget * (GtkModelWidgetCallback) (GMenuItem *item, gpointer data);
+
+GDK_AVAILABLE_IN_3_14
+void gtk_popover_bind_model_with_extra_widgets (GtkPopover *popover,
+ GMenuModel *model,
+ const gchar *action_namespace,
+ GtkModelWidgetCallback *callback,
+ gpointer user_data);
+
G_END_DECLS
#endif /* __GTK_POPOVER_H__ */
diff --git a/tests/popover.ui b/tests/popover.ui
index 74ffdb9..3df020a 100644
--- a/tests/popover.ui
+++ b/tests/popover.ui
@@ -2,6 +2,18 @@
<menu id="menu">
<section>
<item>
+ <attribute name="x-gtk-private-special">custom</attribute>
+ <attribute name="label">Grid</attribute>
+ <attribute name="action">top.set-view</attribute>
+ </item>
+ <item>
+ <attribute name="x-gtk-private-special">custom</attribute>
+ <attribute name="label">Zoom</attribute>
+ <attribute name="action">zoom</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
<attribute name="label">No action</attribute>
<attribute name="action">action1</attribute>
</item>
@@ -83,6 +95,11 @@
<attribute name="label">Item 7</attribute>
<attribute name="action">top.action7</attribute>
</item>
+ <item>
+ <attribute name="x-gtk-private-special">custom</attribute>
+ <attribute name="label">Cut Copy Paste</attribute>
+ <attribute name="action">cutcopypaste</attribute>
+ </item>
<submenu>
<attribute name="label">Subsubmenu</attribute>
<attribute name="icon">preferences-desktop-font</attribute>
diff --git a/tests/testpopover.c b/tests/testpopover.c
index f602daa..d06f3ad 100644
--- a/tests/testpopover.c
+++ b/tests/testpopover.c
@@ -19,9 +19,102 @@ static GActionEntry entries[] = {
{ "action7", activate, NULL, NULL, NULL },
{ "action8", activate, NULL, NULL, NULL },
{ "action9", activate, NULL, NULL, NULL },
- { "action10", activate, NULL, NULL, NULL }
+ { "action10", activate, NULL, NULL, NULL },
+ { "set-view", NULL, "s", "'list'", NULL },
+ { "cut", activate, NULL, NULL, NULL },
+ { "copy", activate, NULL, NULL, NULL },
+ { "paste", activate, NULL, NULL, NULL }
};
+static GtkWidget *
+pick_extra (GMenuItem *item, gpointer data)
+{
+ const gchar *id = NULL;
+ const gchar *action = NULL;
+
+ g_menu_item_get_attribute (item, "x-gtk-private-special", "&s", &id);
+ g_menu_item_get_attribute (item, "action", "&s", &action);
+
+ if (g_strcmp0 (id, "custom") == 0)
+ {
+ if (g_strcmp0 (action, "top.set-view") == 0)
+ {
+ GtkWidget *box, *button, *image;
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
+
+ button = gtk_toggle_button_new ();
+ gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "top.set-view::list");
+ image = gtk_image_new_from_icon_name ("view-list-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_widget_set_hexpand (button, TRUE);
+ gtk_widget_set_halign (button, GTK_ALIGN_FILL);
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ button = gtk_toggle_button_new ();
+ gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "top.set-view::grid");
+ image = gtk_image_new_from_icon_name ("view-grid-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_widget_set_hexpand (button, TRUE);
+ gtk_widget_set_halign (button, GTK_ALIGN_FILL);
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ gtk_widget_show_all (box);
+ return box;
+ }
+ else if (g_strcmp0 (action, "zoom") == 0)
+ {
+ GtkWidget *scale;
+
+ scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 10, 1);
+ gtk_range_set_value (GTK_RANGE (scale), 5);
+
+ gtk_widget_set_margin_top (scale, 6);
+ gtk_widget_set_margin_bottom (scale, 6);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_set_has_origin (GTK_SCALE (scale), TRUE);
+ gtk_scale_add_mark (GTK_SCALE (scale), 0, GTK_POS_BOTTOM, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), 5, GTK_POS_BOTTOM, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), 10, GTK_POS_BOTTOM, NULL);
+ gtk_style_context_remove_class (gtk_widget_get_style_context (scale),
GTK_STYLE_CLASS_SCALE_HAS_MARKS_BELOW);
+
+ gtk_widget_show (scale);
+ return scale;
+ }
+ else if (g_strcmp0 (action, "cutcopypaste") == 0)
+ {
+ GtkWidget *box, *button;
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_set_margin_top (box, 6);
+ gtk_widget_set_margin_bottom (box, 6);
+ gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
+
+ button = gtk_button_new_from_icon_name ("edit-cut-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "top.cut");
+ gtk_widget_set_hexpand (button, TRUE);
+ gtk_widget_set_halign (button, GTK_ALIGN_FILL);
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ button = gtk_button_new_from_icon_name ("edit-copy-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "top.copy");
+ gtk_widget_set_hexpand (button, TRUE);
+ gtk_widget_set_halign (button, GTK_ALIGN_FILL);
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ button = gtk_button_new_from_icon_name ("edit-paste-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "top.paste");
+ gtk_widget_set_hexpand (button, TRUE);
+ gtk_widget_set_halign (button, GTK_ALIGN_FILL);
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ gtk_widget_show_all (box);
+ return box;
+ }
+ }
+
+ return NULL;
+}
+
int main (int argc, char *argv[])
{
GtkWidget *win;
@@ -38,7 +131,6 @@ int main (int argc, char *argv[])
GtkWidget *align;
gtk_init (&argc, &argv);
-
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (win), 400, 600);
actions = g_simple_action_group_new ();
@@ -62,10 +154,16 @@ int main (int argc, char *argv[])
model = (GMenuModel *)gtk_builder_get_object (builder, "menu");
button = gtk_menu_button_new ();
+#if 0
gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), model);
gtk_menu_button_set_use_popover (GTK_MENU_BUTTON (button), TRUE);
popover = GTK_WIDGET (gtk_menu_button_get_popover (GTK_MENU_BUTTON (button)));
+#else
+ popover = gtk_popover_new (NULL);
+ gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), popover);
+ gtk_popover_bind_model_with_extra_widgets (GTK_POPOVER (popover), model, NULL, pick_extra, NULL);
+#endif
g_object_set (button, "margin", 10, NULL);
gtk_widget_set_halign (button, GTK_ALIGN_END);
@@ -125,7 +223,6 @@ int main (int argc, char *argv[])
gtk_grid_attach (GTK_GRID (grid), label , 1, 5, 1, 1);
gtk_grid_attach (GTK_GRID (grid), combo, 2, 5, 1, 1);
-
gtk_widget_show_all (win);
gtk_main ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]