[gtk/popover-menu-custom-child: 106/108] popovermenu: Allow custom items
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/popover-menu-custom-child: 106/108] popovermenu: Allow custom items
- Date: Tue, 27 Oct 2020 02:44:22 +0000 (UTC)
commit 8157abe591059116cbea1a8ad7007fdd061ab0ba
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Oct 20 14:26:45 2020 -0400
popovermenu: Allow custom items
Add a way to add children at certain places in
the generated menu for both GtkPopoverMenu and
GtkPopoverMenuBar.
New apis:
gtk_popover_menu_add_child
gtk_popover_menu_remove_child
gtk_popover_menu_bar_add_child
gtk_popover_menu_bar_remove_child
Fixes: #3260
docs/reference/gtk/gtk4-sections.txt | 4 ++
gtk/gtkmenusectionbox.c | 76 +++++++++++++++++++++++++++++++++++-
gtk/gtkmenusectionboxprivate.h | 7 ++++
gtk/gtkmenutrackeritem.c | 10 +++++
gtk/gtkmenutrackeritemprivate.h | 2 +
gtk/gtkpopovermenu.c | 49 +++++++++++++++++++++++
gtk/gtkpopovermenu.h | 8 ++++
gtk/gtkpopovermenubar.c | 70 +++++++++++++++++++++++++++++++++
gtk/gtkpopovermenubar.h | 8 ++++
9 files changed, 233 insertions(+), 1 deletion(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index a0e123947b..b6f7cf2d25 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -6177,6 +6177,8 @@ gtk_popover_menu_new_from_model
gtk_popover_menu_new_from_model_full
gtk_popover_menu_set_menu_model
gtk_popover_menu_get_menu_model
+gtk_popover_menu_add_child
+gtk_popover_menu_remove_child
<SUBSECTION Standard>
GTK_TYPE_POPOVER_MENU
@@ -6195,6 +6197,8 @@ GtkPopoverMenuBar
gtk_popover_menu_bar_new_from_model
gtk_popover_menu_bar_set_menu_model
gtk_popover_menu_bar_get_menu_model
+gtk_popover_menu_bar_add_child
+gtk_popover_menu_bar_remove_child
<SUBSECTION Standard>
GTK_TYPE_POPOVER_MENU_BAR
diff --git a/gtk/gtkmenusectionbox.c b/gtk/gtkmenusectionbox.c
index 08f5ca1288..9f988d98f5 100644
--- a/gtk/gtkmenusectionbox.c
+++ b/gtk/gtkmenusectionbox.c
@@ -32,6 +32,8 @@
#include "gtkpopovermenuprivate.h"
#include "gtkorientable.h"
#include "gtkbuiltiniconprivate.h"
+#include "gtkgizmoprivate.h"
+#include "gtkbinlayout.h"
typedef GtkBoxClass GtkMenuSectionBoxClass;
@@ -50,6 +52,7 @@ struct _GtkMenuSectionBox
int depth;
GtkPopoverMenuFlags flags;
GtkSizeGroup *indicators;
+ GHashTable *custom_slots;
};
typedef struct
@@ -341,6 +344,22 @@ gtk_menu_section_box_insert_func (GtkMenuTrackerItem *item,
g_free (name);
}
}
+ else if (gtk_menu_tracker_item_get_custom (item))
+ {
+ const char *id = gtk_menu_tracker_item_get_custom (item);
+
+ widget = gtk_gizmo_new ("widget", NULL, NULL, NULL, NULL, NULL, NULL);
+ gtk_widget_set_layout_manager (widget, gtk_bin_layout_new ());
+
+ if (g_hash_table_lookup (box->custom_slots, id))
+ g_warning ("Duplicate custom ID: %s", id);
+ else
+ {
+ char *slot_id = g_strdup (id);
+ g_object_set_data_full (G_OBJECT (widget), "slot-id", slot_id, g_free);
+ g_hash_table_insert (box->custom_slots, slot_id, widget);
+ }
+ }
else
{
widget = g_object_new (GTK_TYPE_MODEL_BUTTON,
@@ -458,6 +477,7 @@ gtk_menu_section_box_dispose (GObject *object)
}
g_clear_object (&box->indicators);
+ g_clear_pointer (&box->custom_slots, g_hash_table_unref);
G_OBJECT_CLASS (gtk_menu_section_box_parent_class)->dispose (object);
}
@@ -499,8 +519,9 @@ gtk_menu_section_box_new_toplevel (GtkPopoverMenu *popover,
{
GtkMenuSectionBox *box;
- box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
+ box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
box->indicators = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ box->custom_slots = g_hash_table_new (g_str_hash, g_str_equal);
box->flags = flags;
gtk_popover_menu_add_submenu (popover, GTK_WIDGET (box), "main");
@@ -524,6 +545,7 @@ gtk_menu_section_box_new_submenu (GtkMenuTrackerItem *item,
box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
box->indicators = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ box->custom_slots = g_hash_table_ref (toplevel->custom_slots);
box->flags = toplevel->flags;
button = g_object_new (GTK_TYPE_MODEL_BUTTON,
@@ -562,6 +584,7 @@ gtk_menu_section_box_new_section (GtkMenuTrackerItem *item,
box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
box->indicators = g_object_ref (parent->indicators);
+ box->custom_slots = g_hash_table_ref (parent->toplevel->custom_slots);
box->toplevel = parent->toplevel;
box->depth = parent->depth + 1;
box->flags = parent->flags;
@@ -661,3 +684,54 @@ gtk_menu_section_box_new_section (GtkMenuTrackerItem *item,
return GTK_WIDGET (box);
}
+
+gboolean
+gtk_menu_section_box_add_custom (GtkPopoverMenu *popover,
+ GtkWidget *child,
+ const char *id)
+{
+ GtkWidget *stack;
+ GtkMenuSectionBox *box;
+ GtkWidget *slot;
+
+ stack = gtk_popover_get_child (GTK_POPOVER (popover));
+ box = GTK_MENU_SECTION_BOX (gtk_stack_get_child_by_name (GTK_STACK (stack), "main"));
+
+ slot = (GtkWidget *)g_hash_table_lookup (box->custom_slots, id);
+
+ if (slot == NULL)
+ return FALSE;
+
+ if (gtk_widget_get_first_child (slot))
+ return FALSE;
+
+ gtk_widget_insert_before (child, slot, NULL);
+ return TRUE;
+}
+
+gboolean
+gtk_menu_section_box_remove_custom (GtkPopoverMenu *popover,
+ GtkWidget *child)
+{
+ GtkWidget *stack;
+ GtkMenuSectionBox *box;
+ GtkWidget *parent;
+ const char *id;
+ GtkWidget *slot;
+
+ stack = gtk_popover_get_child (GTK_POPOVER (popover));
+ box = GTK_MENU_SECTION_BOX (gtk_stack_get_child_by_name (GTK_STACK (stack), "main"));
+ parent = gtk_widget_get_parent (child);
+
+ id = (const char *) g_object_get_data (G_OBJECT (parent), "slot-id");
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ slot = (GtkWidget *)g_hash_table_lookup (box->custom_slots, id);
+
+ if (slot != parent)
+ return FALSE;
+
+ gtk_widget_unparent (child);
+
+ return TRUE;
+}
diff --git a/gtk/gtkmenusectionboxprivate.h b/gtk/gtkmenusectionboxprivate.h
index 05d6bd294e..232d62ee0c 100644
--- a/gtk/gtkmenusectionboxprivate.h
+++ b/gtk/gtkmenusectionboxprivate.h
@@ -45,6 +45,13 @@ void gtk_menu_section_box_new_toplevel (GtkPopo
GMenuModel *model,
GtkPopoverMenuFlags flags);
+gboolean gtk_menu_section_box_add_custom (GtkPopoverMenu *popover,
+ GtkWidget *child,
+ const char *id);
+
+gboolean gtk_menu_section_box_remove_custom (GtkPopoverMenu *popover,
+ GtkWidget *child);
+
G_END_DECLS
#endif /* __GTK_MENU_SECTION_BOX_PRIVATE_H__ */
diff --git a/gtk/gtkmenutrackeritem.c b/gtk/gtkmenutrackeritem.c
index f88009c7d3..93536df960 100644
--- a/gtk/gtkmenutrackeritem.c
+++ b/gtk/gtkmenutrackeritem.c
@@ -715,6 +715,16 @@ gtk_menu_tracker_item_get_special (GtkMenuTrackerItem *self)
return special;
}
+const char *
+gtk_menu_tracker_item_get_custom (GtkMenuTrackerItem *self)
+{
+ const char *custom = NULL;
+
+ g_menu_item_get_attribute (self->item, "custom", "&s", &custom);
+
+ return custom;
+}
+
const char *
gtk_menu_tracker_item_get_display_hint (GtkMenuTrackerItem *self)
{
diff --git a/gtk/gtkmenutrackeritemprivate.h b/gtk/gtkmenutrackeritemprivate.h
index a3c9164053..6ebbc3764c 100644
--- a/gtk/gtkmenutrackeritemprivate.h
+++ b/gtk/gtkmenutrackeritemprivate.h
@@ -51,6 +51,8 @@ GtkMenuTrackerItem * _gtk_menu_tracker_item_new (GtkActi
const char * gtk_menu_tracker_item_get_special (GtkMenuTrackerItem *self);
+const char * gtk_menu_tracker_item_get_custom (GtkMenuTrackerItem *self);
+
const char * gtk_menu_tracker_item_get_display_hint (GtkMenuTrackerItem *self);
const char * gtk_menu_tracker_item_get_text_direction (GtkMenuTrackerItem *self);
diff --git a/gtk/gtkpopovermenu.c b/gtk/gtkpopovermenu.c
index dab6635530..4c33b0011d 100644
--- a/gtk/gtkpopovermenu.c
+++ b/gtk/gtkpopovermenu.c
@@ -98,6 +98,8 @@
* - "hidden-when": a string used to determine when the item will be hidden.
* Possible values include "action-disabled", "action-missing", "macos-menubar".
* This is mainly useful for exported menus, see gtk_application_set_menubar().
+ * - "custom": a string used to match against the ID of a custom child added
+ * with gtk_popover_menu_add_child() or gtk_popover_menu_bar_add_child().
*
* The following attributes are used when constructing sections:
* - "label": a user-visible string to use as section heading
@@ -733,3 +735,50 @@ gtk_popover_menu_get_menu_model (GtkPopoverMenu *popover)
return popover->model;
}
+
+/**
+ * gtk_popover_menu_add_child:
+ * @popover: a #GtkPopoverMenu
+ * @child: the #GtkWidget to add
+ * @id: the ID to insert @child at
+ *
+ * Adds a custom widget to a generated menu.
+ *
+ * For this to work, the menu model of @popover must have an
+ * item with a `custom` attribute that matches @id.
+ *
+ * Returns: %TRUE if @id was found and the widget added
+ */
+gboolean
+gtk_popover_menu_add_child (GtkPopoverMenu *popover,
+ GtkWidget *child,
+ const char *id)
+{
+
+ g_return_val_if_fail (GTK_IS_POPOVER_MENU (popover), FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ return gtk_menu_section_box_add_custom (popover, child, id);
+}
+
+/**
+ * gtk_popover_menu_remove_child:
+ * @popover: a #GtkPopoverMenu
+ * @child: the #GtkWidget to remove
+ *
+ * Removes a widget that has previously been added with
+ * gtk_popover_menu_add_child().
+ *
+ * Returns: %TRUE if the widget was removed
+ */
+gboolean
+gtk_popover_menu_remove_child (GtkPopoverMenu *popover,
+ GtkWidget *child)
+{
+
+ g_return_val_if_fail (GTK_IS_POPOVER_MENU (popover), FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
+
+ return gtk_menu_section_box_remove_custom (popover, child);
+}
diff --git a/gtk/gtkpopovermenu.h b/gtk/gtkpopovermenu.h
index f9f8457b27..2973102be1 100644
--- a/gtk/gtkpopovermenu.h
+++ b/gtk/gtkpopovermenu.h
@@ -61,6 +61,14 @@ void gtk_popover_menu_set_menu_model (GtkPopoverMenu *popover,
GDK_AVAILABLE_IN_ALL
GMenuModel *gtk_popover_menu_get_menu_model (GtkPopoverMenu *popover);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_popover_menu_add_child (GtkPopoverMenu *popover,
+ GtkWidget *child,
+ const char *id);
+
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_popover_menu_remove_child (GtkPopoverMenu *popover,
+ GtkWidget *child);
G_END_DECLS
diff --git a/gtk/gtkpopovermenubar.c b/gtk/gtkpopovermenubar.c
index 1401c998eb..0d5658c224 100644
--- a/gtk/gtkpopovermenubar.c
+++ b/gtk/gtkpopovermenubar.c
@@ -733,3 +733,73 @@ gtk_popover_menu_bar_select_first (GtkPopoverMenuBar *bar)
item = GTK_POPOVER_MENU_BAR_ITEM (gtk_widget_get_first_child (GTK_WIDGET (bar)));
set_active_item (bar, item, TRUE);
}
+
+/**
+ * gtk_popover_menu_bar_add_child:
+ * @bar: a #GtkPopoverMenuBar
+ * @child: the #GtkWidget to add
+ * @id: the ID to insert @child at
+ *
+ * Adds a custom widget to a generated menubar.
+ *
+ * For this to work, the menu model of @bar must have an
+ * item with a `custom` attribute that matches @id.
+ *
+ * Returns: %TRUE if @id was found and the widget added
+ */
+gboolean
+gtk_popover_menu_bar_add_child (GtkPopoverMenuBar *bar,
+ GtkWidget *child,
+ const char *id)
+{
+ GtkWidget *item;
+
+ g_return_val_if_fail (GTK_IS_POPOVER_MENU_BAR (bar), FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ for (item = gtk_widget_get_first_child (GTK_WIDGET (bar));
+ item;
+ item = gtk_widget_get_next_sibling (item))
+ {
+ GtkPopover *popover = GTK_POPOVER_MENU_BAR_ITEM (item)->popover;
+
+ if (gtk_popover_menu_add_child (GTK_POPOVER_MENU (popover), child, id))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gtk_popover_menu_bar_remove_child:
+ * @bar: a #GtkPopoverMenuBar
+ * @child: the #GtkWidget to remove
+ *
+ * Removes a widget that has previously been added with
+ * gtk_popover_menu_bar_add_child().
+ *
+ * Returns: %TRUE if the widget was removed
+ */
+gboolean
+gtk_popover_menu_bar_remove_child (GtkPopoverMenuBar *bar,
+ GtkWidget *child)
+{
+ GtkWidget *item;
+
+ g_return_val_if_fail (GTK_IS_POPOVER_MENU_BAR (bar), FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
+
+ for (item = gtk_widget_get_first_child (GTK_WIDGET (bar));
+ item;
+ item = gtk_widget_get_next_sibling (item))
+ {
+ GtkPopover *popover = GTK_POPOVER_MENU_BAR_ITEM (item)->popover;
+
+ if (gtk_popover_menu_remove_child (GTK_POPOVER_MENU (popover), child))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/gtk/gtkpopovermenubar.h b/gtk/gtkpopovermenubar.h
index 7fa1253128..08126f9d63 100644
--- a/gtk/gtkpopovermenubar.h
+++ b/gtk/gtkpopovermenubar.h
@@ -47,6 +47,14 @@ void gtk_popover_menu_bar_set_menu_model (GtkPopoverMenuBar *bar,
GDK_AVAILABLE_IN_ALL
GMenuModel * gtk_popover_menu_bar_get_menu_model (GtkPopoverMenuBar *bar);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_popover_menu_bar_add_child (GtkPopoverMenuBar *bar,
+ GtkWidget *child,
+ const char *id);
+
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_popover_menu_bar_remove_child (GtkPopoverMenuBar *bar,
+ GtkWidget *child);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]