app, menus: now support the child menu of the GimpDockbook menu.

I only translated the undo menu into GtkBuilder's .ui format for now.
The only missing part is that the icon is now shown.

Note that in various parts, I don't rely anymore on a bogus menu action (i.e.
"undo-popup" action in this case) which does nothing but has an associated label
and icon. I simply add the label and icon as submenu attribute directly in the
.ui file, which is translatable and whose strings should be parsed by gettext.

Eventually I'll just get rid of all the various "*-popup" or "*-menu" bogus
actions.
This commit is contained in:
Jehan 2023-02-27 18:49:45 +01:00
parent 1b48792089
commit b1f022f144
10 changed files with 66 additions and 95 deletions

View File

@ -353,6 +353,7 @@ gimp_display_shell_quick_mask_button_press (GtkWidget *widget,
gimp_ui_manager_ui_popup_at_widget (manager, gimp_ui_manager_ui_popup_at_widget (manager,
"/quick-mask-popup", "/quick-mask-popup",
NULL, NULL,
widget, widget,
GDK_GRAVITY_EAST, GDK_GRAVITY_EAST,
GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_SOUTH_WEST,

View File

@ -989,6 +989,7 @@ gimp_display_shell_popup_menu (GtkWidget *widget)
gimp_ui_manager_ui_popup_at_widget (shell->popup_manager, gimp_ui_manager_ui_popup_at_widget (shell->popup_manager,
"/image-menubar", "/image-menubar",
NULL, NULL,
shell->origin, shell->origin,
GDK_GRAVITY_EAST, GDK_GRAVITY_EAST,
GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_NORTH_WEST,

View File

@ -551,8 +551,6 @@ gimp_dockbook_show_menu (GimpDockbook *dockbook)
GimpUIManager *dialog_ui_manager; GimpUIManager *dialog_ui_manager;
const gchar *dialog_ui_path; const gchar *dialog_ui_path;
gpointer dialog_popup_data; gpointer dialog_popup_data;
GtkWidget *parent_menu_widget;
GimpAction *parent_menu_action;
GimpDockable *dockable; GimpDockable *dockable;
gint page_num; gint page_num;
@ -561,16 +559,6 @@ gimp_dockbook_show_menu (GimpDockbook *dockbook)
if (! dockbook_ui_manager) if (! dockbook_ui_manager)
return FALSE; return FALSE;
parent_menu_widget =
gimp_ui_manager_get_widget (dockbook_ui_manager,
"/dockable-popup/dockable-menu");
parent_menu_action =
gimp_ui_manager_get_action (dockbook_ui_manager,
"/dockable-popup/dockable-menu");
if (! parent_menu_widget || ! parent_menu_action)
return FALSE;
page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook)); page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook));
dockable = GIMP_DOCKABLE (gtk_notebook_get_nth_page (GTK_NOTEBOOK (dockbook), dockable = GIMP_DOCKABLE (gtk_notebook_get_nth_page (GTK_NOTEBOOK (dockbook),
page_num)); page_num));
@ -582,69 +570,6 @@ gimp_dockbook_show_menu (GimpDockbook *dockbook)
&dialog_ui_path, &dialog_ui_path,
&dialog_popup_data); &dialog_popup_data);
if (dialog_ui_manager && dialog_ui_path)
{
GtkWidget *child_menu_widget;
GimpAction *child_menu_action;
gchar *label;
child_menu_widget =
gimp_ui_manager_get_widget (dialog_ui_manager, dialog_ui_path);
if (! child_menu_widget)
{
g_warning ("%s: UI manager '%s' has no widget at path '%s'",
G_STRFUNC, dialog_ui_manager->name, dialog_ui_path);
return FALSE;
}
child_menu_action =
gimp_ui_manager_get_action (dialog_ui_manager,
dialog_ui_path);
if (! child_menu_action)
{
g_warning ("%s: UI manager '%s' has no action at path '%s'",
G_STRFUNC, dialog_ui_manager->name, dialog_ui_path);
return FALSE;
}
g_object_get (child_menu_action,
"label", &label,
NULL);
g_object_set (parent_menu_action,
"label", label,
"icon-name", gimp_dockable_get_icon_name (dockable),
"visible", TRUE,
NULL);
g_free (label);
if (! GTK_IS_MENU (child_menu_widget))
{
g_warning ("%s: child_menu_widget (%p) is not a GtkMenu",
G_STRFUNC, child_menu_widget);
return FALSE;
}
{
GtkWidget *image = gimp_dockable_get_icon (dockable,
GTK_ICON_SIZE_MENU);
gimp_menu_item_set_image (GTK_MENU_ITEM (parent_menu_widget), image, NULL);
gtk_widget_show (image);
}
gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent_menu_widget),
child_menu_widget);
gimp_ui_manager_update (dialog_ui_manager, dialog_popup_data);
}
else
{
g_object_set (parent_menu_action, "visible", FALSE, NULL);
}
/* an action callback may destroy both dockable and dockbook, so /* an action callback may destroy both dockable and dockbook, so
* reference them for gimp_dockbook_menu_end() * reference them for gimp_dockbook_menu_end()
*/ */
@ -653,10 +578,10 @@ gimp_dockbook_show_menu (GimpDockbook *dockbook)
g_object_ref (dockbook), g_object_ref (dockbook),
g_object_unref); g_object_unref);
gimp_ui_manager_update (dockbook_ui_manager, dockable);
gimp_ui_manager_ui_popup_at_widget (dockbook_ui_manager, gimp_ui_manager_ui_popup_at_widget (dockbook_ui_manager,
"/dockable-popup", "/dockable-popup",
dialog_ui_manager,
dialog_ui_path,
dockbook->p->menu_button, dockbook->p->menu_button,
GDK_GRAVITY_WEST, GDK_GRAVITY_WEST,
GDK_GRAVITY_NORTH_EAST, GDK_GRAVITY_NORTH_EAST,
@ -670,23 +595,6 @@ gimp_dockbook_show_menu (GimpDockbook *dockbook)
static void static void
gimp_dockbook_menu_end (GimpDockable *dockable) gimp_dockbook_menu_end (GimpDockable *dockable)
{ {
GimpUIManager *dialog_ui_manager;
const gchar *dialog_ui_path;
gpointer dialog_popup_data;
dialog_ui_manager = gimp_dockable_get_menu (dockable,
&dialog_ui_path,
&dialog_popup_data);
if (dialog_ui_manager && dialog_ui_path)
{
GtkWidget *child_menu_widget =
gimp_ui_manager_get_widget (dialog_ui_manager, dialog_ui_path);
if (child_menu_widget)
gtk_menu_detach (GTK_MENU (child_menu_widget));
}
/* release gimp_dockbook_show_menu()'s references */ /* release gimp_dockbook_show_menu()'s references */
g_object_set_data (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY, NULL); g_object_set_data (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY, NULL);
g_object_unref (dockable); g_object_unref (dockable);

View File

@ -157,6 +157,33 @@ gimp_menu_shell_fill (GimpMenuShell *shell,
} }
} }
void
gimp_menu_shell_merge (GimpMenuShell *shell,
GimpMenuShell *shell2,
gboolean top)
{
GList *children;
GList *iter;
children = gtk_container_get_children (GTK_CONTAINER (shell2));
iter = top ? g_list_last (children) : children;
for (; iter; iter = top ? iter->prev : iter->next)
{
GtkWidget *item = iter->data;
g_object_ref (item);
gtk_container_remove (GTK_CONTAINER (shell2), item);
if (top)
gtk_menu_shell_prepend (GTK_MENU_SHELL (shell), item);
else
gtk_menu_shell_append (GTK_MENU_SHELL (shell), item);
g_object_unref (item);
}
g_list_free (children);
gtk_widget_destroy (GTK_WIDGET (shell2));
}
/* Protected functions. */ /* Protected functions. */

View File

@ -49,6 +49,9 @@ GType gimp_menu_shell_get_type (void) G_GNUC_CONST;
void gimp_menu_shell_fill (GimpMenuShell *shell, void gimp_menu_shell_fill (GimpMenuShell *shell,
GMenuModel *model, GMenuModel *model,
const gchar *update_signal); const gchar *update_signal);
void gimp_menu_shell_merge (GimpMenuShell *shell,
GimpMenuShell *shell2,
gboolean top);
/* Protected functions. */ /* Protected functions. */

View File

@ -383,7 +383,7 @@ gimp_tool_options_editor_menu_popup (GimpToolOptionsEditor *editor,
gimp_editor_get_popup_data (gimp_editor)); gimp_editor_get_popup_data (gimp_editor));
gimp_ui_manager_ui_popup_at_widget (gimp_editor_get_ui_manager (gimp_editor), gimp_ui_manager_ui_popup_at_widget (gimp_editor_get_ui_manager (gimp_editor),
path, path, NULL, NULL,
button, button,
GDK_GRAVITY_WEST, GDK_GRAVITY_WEST,
GDK_GRAVITY_NORTH_EAST, GDK_GRAVITY_NORTH_EAST,

View File

@ -723,6 +723,8 @@ gimp_ui_manager_ui_register (GimpUIManager *manager,
void void
gimp_ui_manager_ui_popup_at_widget (GimpUIManager *manager, gimp_ui_manager_ui_popup_at_widget (GimpUIManager *manager,
const gchar *ui_path, const gchar *ui_path,
GimpUIManager *child_ui_manager,
const gchar *child_ui_path,
GtkWidget *widget, GtkWidget *widget,
GdkGravity widget_anchor, GdkGravity widget_anchor,
GdkGravity menu_anchor, GdkGravity menu_anchor,
@ -745,6 +747,19 @@ gimp_ui_manager_ui_popup_at_widget (GimpUIManager *manager,
if (! menu) if (! menu)
return; return;
if (child_ui_manager != NULL && child_ui_path != NULL)
{
GMenuModel *child_model;
GtkWidget *child_menu;
/* TODO GMenu: the "icon" attribute set in the .ui file should be visible. */
child_model = gimp_ui_manager_get_model (child_ui_manager, child_ui_path);
child_menu = gimp_menu_new (child_ui_manager);
gimp_menu_shell_fill (GIMP_MENU_SHELL (child_menu), child_model, NULL);
gimp_menu_shell_merge (GIMP_MENU_SHELL (menu), GIMP_MENU_SHELL (child_menu), TRUE);
}
if (popdown_func && popdown_data) if (popdown_func && popdown_data)
{ {
g_object_set_data_full (G_OBJECT (manager), "popdown-data", g_object_set_data_full (G_OBJECT (manager), "popdown-data",

View File

@ -155,6 +155,8 @@ void gimp_ui_manager_ui_register (GimpUIManager *manager,
void gimp_ui_manager_ui_popup_at_widget void gimp_ui_manager_ui_popup_at_widget
(GimpUIManager *manager, (GimpUIManager *manager,
const gchar *ui_path, const gchar *ui_path,
GimpUIManager *child_ui_manager,
const gchar *child_ui_path,
GtkWidget *widget, GtkWidget *widget,
GdkGravity widget_anchor, GdkGravity widget_anchor,
GdkGravity menu_anchor, GdkGravity menu_anchor,

View File

@ -56,6 +56,7 @@ ui_menus_files = files(
'patterns-menu.ui', 'patterns-menu.ui',
'quick-mask-menu.ui', 'quick-mask-menu.ui',
'templates-menu.ui', 'templates-menu.ui',
'undo-menu.ui',
'vectors-menu.ui', 'vectors-menu.ui',
) )

13
menus/undo-menu.ui Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<interface>
<menu id="/undo-popup">
<submenu>
<attribute name="label" translatable="yes" context="edit-action">Undo History Menu</attribute>
<attribute name="icon">edit-undo</attribute>
<item><attribute name="action">app.edit-undo</attribute></item>
<item><attribute name="action">app.edit-redo</attribute></item>
<item><attribute name="action">app.edit-undo-clear</attribute></item>
</submenu>
</menu>
</interface>