mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
toolbar: Use a popover for overflow
We are phasing out menus. This is not quite complete, toolitems still create menuitems, which we translate on the fly.
This commit is contained in:
parent
1b271f3335
commit
b14b0efefe
160
gtk/gtktoolbar.c
160
gtk/gtktoolbar.c
@ -45,10 +45,14 @@
|
||||
#include "gtklabel.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkmenu.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkorientableprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtkmodelbutton.h"
|
||||
#include "gtkseparator.h"
|
||||
#include "gtkradiomenuitem.h"
|
||||
#include "gtkcheckmenuitem.h"
|
||||
#include "gtkradiobutton.h"
|
||||
#include "gtkradiotoolbutton.h"
|
||||
#include "gtkseparatormenuitem.h"
|
||||
@ -132,7 +136,8 @@ struct _GtkToolbarClass
|
||||
|
||||
struct _GtkToolbarPrivate
|
||||
{
|
||||
GtkMenu *menu;
|
||||
GtkWidget *menu;
|
||||
GtkWidget *menu_box;
|
||||
GtkSettings *settings;
|
||||
|
||||
GtkToolbarStyle style;
|
||||
@ -429,6 +434,7 @@ gtk_toolbar_class_init (GtkToolbarClass *klass)
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_TOOLBAR_STYLE);
|
||||
|
||||
/**
|
||||
* GtkToolbar::popup-context-menu:
|
||||
* @toolbar: the #GtkToolbar which emitted the signal
|
||||
@ -1108,77 +1114,97 @@ menu_deactivated (GtkWidget *menu,
|
||||
}
|
||||
|
||||
static void
|
||||
menu_detached (GtkWidget *widget,
|
||||
GtkMenu *menu)
|
||||
button_clicked (GtkWidget *button,
|
||||
GtkWidget *item)
|
||||
{
|
||||
GtkToolbar *toolbar = GTK_TOOLBAR (widget);
|
||||
GtkToolbarPrivate *priv = toolbar->priv;
|
||||
|
||||
priv->menu = NULL;
|
||||
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
|
||||
if (GTK_IS_TOOL_BUTTON (item))
|
||||
g_signal_emit_by_name (_gtk_tool_button_get_button (GTK_TOOL_BUTTON (item)), "clicked");
|
||||
}
|
||||
|
||||
static void
|
||||
rebuild_menu (GtkToolbar *toolbar)
|
||||
{
|
||||
GtkToolbarPrivate *priv = toolbar->priv;
|
||||
GList *list, *children;
|
||||
GList *list;
|
||||
|
||||
if (!priv->menu)
|
||||
{
|
||||
priv->menu = GTK_MENU (gtk_menu_new ());
|
||||
gtk_menu_attach_to_widget (priv->menu,
|
||||
GTK_WIDGET (toolbar),
|
||||
menu_detached);
|
||||
priv->menu = gtk_popover_menu_new (priv->arrow_button);
|
||||
priv->menu_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_popover_menu_add_submenu (GTK_POPOVER_MENU (priv->menu), priv->menu_box, "main");
|
||||
|
||||
g_signal_connect (priv->menu, "deactivate",
|
||||
g_signal_connect (priv->menu, "closed",
|
||||
G_CALLBACK (menu_deactivated), toolbar);
|
||||
}
|
||||
|
||||
gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
|
||||
|
||||
gtk_container_foreach (GTK_CONTAINER (priv->menu_box), remove_item, NULL);
|
||||
|
||||
for (list = priv->content; list != NULL; list = list->next)
|
||||
{
|
||||
ToolbarContent *content = list->data;
|
||||
|
||||
|
||||
if (toolbar_content_get_state (content) == OVERFLOWN &&
|
||||
!toolbar_content_is_placeholder (content))
|
||||
{
|
||||
GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
|
||||
|
||||
|
||||
if (menu_item)
|
||||
{
|
||||
GtkWidget *button, *widget;
|
||||
const char *text;
|
||||
GtkButtonRole role;
|
||||
gboolean active;
|
||||
|
||||
g_assert (GTK_IS_MENU_ITEM (menu_item));
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
|
||||
text = gtk_menu_item_get_label (GTK_MENU_ITEM (menu_item));
|
||||
if (text == NULL)
|
||||
{
|
||||
GtkWidget *box, *child;
|
||||
box = gtk_bin_get_child (GTK_BIN (menu_item));
|
||||
for (child = gtk_widget_get_first_child (box);
|
||||
child;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
if (GTK_IS_LABEL (child))
|
||||
{
|
||||
text = gtk_label_get_label (GTK_LABEL (child));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
|
||||
{
|
||||
gtk_container_add (GTK_CONTAINER (priv->menu_box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
|
||||
continue;
|
||||
}
|
||||
else if (GTK_IS_RADIO_MENU_ITEM (menu_item))
|
||||
role = GTK_BUTTON_ROLE_RADIO;
|
||||
else if (GTK_IS_CHECK_MENU_ITEM (menu_item))
|
||||
role = GTK_BUTTON_ROLE_CHECK;
|
||||
else
|
||||
role = GTK_BUTTON_ROLE_NORMAL;
|
||||
|
||||
if (GTK_IS_CHECK_MENU_ITEM (menu_item))
|
||||
active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_item));
|
||||
else
|
||||
active = FALSE;
|
||||
|
||||
button = gtk_model_button_new ();
|
||||
g_object_set (button,
|
||||
"text", text,
|
||||
"role", role,
|
||||
"active", active,
|
||||
NULL);
|
||||
widget = toolbar_content_get_widget (content);
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (button_clicked), widget);
|
||||
gtk_container_add (GTK_CONTAINER (priv->menu_box), button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove leading and trailing separator items */
|
||||
children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
|
||||
|
||||
list = children;
|
||||
while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
|
||||
{
|
||||
GtkWidget *child = list->data;
|
||||
|
||||
gtk_container_remove (GTK_CONTAINER (priv->menu), child);
|
||||
list = list->next;
|
||||
}
|
||||
g_list_free (children);
|
||||
|
||||
/* Regenerate the list of children so we don't try to remove items twice */
|
||||
children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
|
||||
|
||||
list = g_list_last (children);
|
||||
while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
|
||||
{
|
||||
GtkWidget *child = list->data;
|
||||
|
||||
gtk_container_remove (GTK_CONTAINER (priv->menu), child);
|
||||
list = list->prev;
|
||||
}
|
||||
g_list_free (children);
|
||||
|
||||
priv->need_rebuild = FALSE;
|
||||
}
|
||||
|
||||
@ -2124,52 +2150,10 @@ show_menu (GtkToolbar *toolbar,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkToolbarPrivate *priv = toolbar->priv;
|
||||
GtkRequisition minimum_size;
|
||||
|
||||
rebuild_menu (toolbar);
|
||||
|
||||
gtk_widget_show (GTK_WIDGET (priv->menu));
|
||||
|
||||
switch (priv->orientation)
|
||||
{
|
||||
case GTK_ORIENTATION_HORIZONTAL:
|
||||
gtk_widget_get_preferred_size (priv->arrow_button, &minimum_size, NULL);
|
||||
|
||||
g_object_set (priv->menu,
|
||||
"anchor-hints", (GDK_ANCHOR_FLIP_Y |
|
||||
GDK_ANCHOR_SLIDE |
|
||||
GDK_ANCHOR_RESIZE),
|
||||
"menu-type-hint", GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU,
|
||||
"rect-anchor-dx", -minimum_size.width,
|
||||
NULL);
|
||||
|
||||
gtk_menu_popup_at_widget (priv->menu,
|
||||
priv->arrow_button,
|
||||
GDK_GRAVITY_SOUTH_EAST,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
(GdkEvent *) event);
|
||||
|
||||
break;
|
||||
|
||||
case GTK_ORIENTATION_VERTICAL:
|
||||
g_object_set (priv->menu,
|
||||
"anchor-hints", (GDK_ANCHOR_FLIP_X |
|
||||
GDK_ANCHOR_SLIDE |
|
||||
GDK_ANCHOR_RESIZE),
|
||||
NULL);
|
||||
|
||||
gtk_menu_popup_at_widget (priv->menu,
|
||||
priv->arrow_button,
|
||||
GDK_GRAVITY_NORTH_EAST,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
(GdkEvent *) event);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
gtk_popover_popup (GTK_POPOVER (priv->menu));
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user