mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-29 06:51:10 +00:00
Implemented height-for-width geometry management for menus
Now GtkMenu/GtkMenuItem request/allocate in height-for-width manner... to reduce the height of the menu one must explicitly set the requested minimum width of the menu to a greater value (using gtk_widget_set_size_request()).
This commit is contained in:
parent
9c26bd525f
commit
52e5f36dc3
418
gtk/gtkmenu.c
418
gtk/gtkmenu.c
@ -41,6 +41,7 @@
|
||||
#include "gtkhbox.h"
|
||||
#include "gtkvscrollbar.h"
|
||||
#include "gtksettings.h"
|
||||
#include "gtksizerequest.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
@ -79,6 +80,7 @@ struct _GtkMenuPrivate
|
||||
/* info used for the table */
|
||||
guint *heights;
|
||||
gint heights_length;
|
||||
gint requested_height;
|
||||
|
||||
gint monitor_num;
|
||||
|
||||
@ -86,6 +88,8 @@ struct _GtkMenuPrivate
|
||||
gint n_rows;
|
||||
gint n_columns;
|
||||
|
||||
guint accel_size;
|
||||
|
||||
gchar *title;
|
||||
|
||||
/* Arrow states */
|
||||
@ -169,8 +173,6 @@ static void gtk_menu_get_child_property(GtkContainer *container,
|
||||
static void gtk_menu_destroy (GtkObject *object);
|
||||
static void gtk_menu_realize (GtkWidget *widget);
|
||||
static void gtk_menu_unrealize (GtkWidget *widget);
|
||||
static void gtk_menu_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition);
|
||||
static void gtk_menu_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static void gtk_menu_paint (GtkWidget *widget,
|
||||
@ -258,6 +260,19 @@ static gboolean gtk_menu_real_can_activate_accel (GtkWidget *widget,
|
||||
static void _gtk_menu_refresh_accel_paths (GtkMenu *menu,
|
||||
gboolean group_changed);
|
||||
|
||||
static void gtk_menu_size_request_init (GtkSizeRequestIface *iface);
|
||||
static void gtk_menu_get_width (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
static void gtk_menu_get_height (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
static void gtk_menu_get_height_for_width (GtkSizeRequest *widget,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
|
||||
|
||||
static const gchar attach_data_key[] = "gtk-menu-attach-data";
|
||||
|
||||
static guint menu_signals[LAST_SIGNAL] = { 0 };
|
||||
@ -268,7 +283,9 @@ gtk_menu_get_private (GtkMenu *menu)
|
||||
return G_TYPE_INSTANCE_GET_PRIVATE (menu, GTK_TYPE_MENU, GtkMenuPrivate);
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE (GtkMenu, gtk_menu, GTK_TYPE_MENU_SHELL)
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkMenu, gtk_menu, GTK_TYPE_MENU_SHELL,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST,
|
||||
gtk_menu_size_request_init))
|
||||
|
||||
static void
|
||||
menu_queue_resize (GtkMenu *menu)
|
||||
@ -459,7 +476,6 @@ gtk_menu_class_init (GtkMenuClass *class)
|
||||
|
||||
widget_class->realize = gtk_menu_realize;
|
||||
widget_class->unrealize = gtk_menu_unrealize;
|
||||
widget_class->size_request = gtk_menu_size_request;
|
||||
widget_class->size_allocate = gtk_menu_size_allocate;
|
||||
widget_class->show = gtk_menu_show;
|
||||
widget_class->expose_event = gtk_menu_expose;
|
||||
@ -1625,7 +1641,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
GtkRequisition tmp_request;
|
||||
GtkAllocation tmp_allocation = { 0, };
|
||||
|
||||
gtk_widget_size_request (menu->toplevel, &tmp_request);
|
||||
gtk_size_request_get_size (GTK_SIZE_REQUEST (menu->toplevel), NULL, &tmp_request);
|
||||
|
||||
tmp_allocation.width = tmp_request.width;
|
||||
tmp_allocation.height = tmp_request.height;
|
||||
@ -2042,10 +2058,13 @@ gtk_menu_set_tearoff_hints (GtkMenu *menu,
|
||||
gint width)
|
||||
{
|
||||
GdkGeometry geometry_hints;
|
||||
|
||||
GtkMenuPrivate *priv;
|
||||
|
||||
if (!menu->tearoff_window)
|
||||
return;
|
||||
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
if (gtk_widget_get_visible (menu->tearoff_scrollbar))
|
||||
{
|
||||
gtk_widget_size_request (menu->tearoff_scrollbar, NULL);
|
||||
@ -2056,7 +2075,7 @@ gtk_menu_set_tearoff_hints (GtkMenu *menu,
|
||||
geometry_hints.max_width = width;
|
||||
|
||||
geometry_hints.min_height = 0;
|
||||
geometry_hints.max_height = GTK_WIDGET (menu)->requisition.height;
|
||||
geometry_hints.max_height = priv->requested_height;
|
||||
|
||||
gtk_window_set_geometry_hints (GTK_WINDOW (menu->tearoff_window),
|
||||
NULL,
|
||||
@ -2122,10 +2141,13 @@ void
|
||||
gtk_menu_set_tearoff_state (GtkMenu *menu,
|
||||
gboolean torn_off)
|
||||
{
|
||||
gint width, height;
|
||||
gint width, height;
|
||||
GtkMenuPrivate *priv;
|
||||
|
||||
g_return_if_fail (GTK_IS_MENU (menu));
|
||||
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
if (menu->torn_off != torn_off)
|
||||
{
|
||||
menu->torn_off = torn_off;
|
||||
@ -2170,7 +2192,7 @@ gtk_menu_set_tearoff_state (GtkMenu *menu,
|
||||
menu->tearoff_adjustment =
|
||||
GTK_ADJUSTMENT (gtk_adjustment_new (0,
|
||||
0,
|
||||
GTK_WIDGET (menu)->requisition.height,
|
||||
priv->requested_height,
|
||||
MENU_SCROLL_STEP2,
|
||||
height/2,
|
||||
height));
|
||||
@ -2371,6 +2393,7 @@ gtk_menu_realize (GtkWidget *widget)
|
||||
gint attributes_mask;
|
||||
gint border_width;
|
||||
GtkMenu *menu;
|
||||
GtkMenuPrivate *priv;
|
||||
GtkWidget *child;
|
||||
GList *children;
|
||||
guint vertical_padding;
|
||||
@ -2380,7 +2403,8 @@ gtk_menu_realize (GtkWidget *widget)
|
||||
g_return_if_fail (GTK_IS_MENU (widget));
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
|
||||
attributes.window_type = GDK_WINDOW_CHILD;
|
||||
@ -2424,7 +2448,7 @@ gtk_menu_realize (GtkWidget *widget)
|
||||
attributes.x = 0;
|
||||
attributes.y = 0;
|
||||
attributes.width = MAX (1, widget->allocation.width - (border_width + widget->style->xthickness + horizontal_padding) * 2);
|
||||
attributes.height = MAX (1, widget->requisition.height - (border_width + widget->style->ythickness + vertical_padding) * 2);
|
||||
attributes.height = MAX (1, priv->requested_height - (border_width + widget->style->ythickness + vertical_padding) * 2);
|
||||
|
||||
menu->bin_window = gdk_window_new (menu->view_window, &attributes, attributes_mask);
|
||||
gdk_window_set_user_data (menu->bin_window, menu);
|
||||
@ -2525,118 +2549,82 @@ gtk_menu_unrealize (GtkWidget *widget)
|
||||
GTK_WIDGET_CLASS (gtk_menu_parent_class)->unrealize (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition)
|
||||
{
|
||||
gint i;
|
||||
GtkMenu *menu;
|
||||
GtkMenuShell *menu_shell;
|
||||
GtkWidget *child;
|
||||
GList *children;
|
||||
guint max_toggle_size;
|
||||
guint max_accel_width;
|
||||
guint vertical_padding;
|
||||
guint horizontal_padding;
|
||||
guint border_width;
|
||||
GtkRequisition child_requisition;
|
||||
GtkMenuPrivate *priv;
|
||||
|
||||
g_return_if_fail (GTK_IS_MENU (widget));
|
||||
g_return_if_fail (requisition != NULL);
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
menu_shell = GTK_MENU_SHELL (widget);
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
requisition->width = 0;
|
||||
requisition->height = 0;
|
||||
|
||||
max_toggle_size = 0;
|
||||
max_accel_width = 0;
|
||||
|
||||
g_free (priv->heights);
|
||||
priv->heights = g_new0 (guint, gtk_menu_get_n_rows (menu));
|
||||
priv->heights_length = gtk_menu_get_n_rows (menu);
|
||||
|
||||
children = menu_shell->children;
|
||||
while (children)
|
||||
static gint
|
||||
calculate_line_heights (GtkMenu *menu,
|
||||
gint for_width,
|
||||
guint **ret_min_heights,
|
||||
guint **ret_nat_heights)
|
||||
{
|
||||
GtkMenuShell *menu_shell;
|
||||
GtkMenuPrivate *priv;
|
||||
GtkWidget *child, *widget;
|
||||
GList *children;
|
||||
guint horizontal_padding;
|
||||
guint border_width;
|
||||
guint n_columns;
|
||||
gint n_heights;
|
||||
guint *min_heights;
|
||||
guint *nat_heights;
|
||||
gint avail_width;
|
||||
|
||||
widget = GTK_WIDGET (menu);
|
||||
menu_shell = GTK_MENU_SHELL (widget);
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
min_heights = g_new0 (guint, gtk_menu_get_n_rows (menu));
|
||||
nat_heights = g_new0 (guint, gtk_menu_get_n_rows (menu));
|
||||
n_heights = gtk_menu_get_n_rows (menu);
|
||||
n_columns = gtk_menu_get_n_columns (menu);
|
||||
avail_width = for_width - (2 * menu->toggle_size + priv->accel_size) * n_columns;
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (menu),
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
|
||||
avail_width -= (border_width + horizontal_padding + widget->style->xthickness) * 2;
|
||||
|
||||
for (children = menu_shell->children; children; children = children->next)
|
||||
{
|
||||
gint part;
|
||||
gint toggle_size;
|
||||
gint l, r, t, b;
|
||||
gint child_min, child_nat;
|
||||
|
||||
child = children->data;
|
||||
children = children->next;
|
||||
|
||||
if (! gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
get_effective_child_attach (child, &l, &r, &t, &b);
|
||||
|
||||
/* It's important to size_request the child
|
||||
* before doing the toggle size request, in
|
||||
* case the toggle size request depends on the size
|
||||
* request of a child of the child (e.g. for ImageMenuItem)
|
||||
*/
|
||||
part = avail_width / (r - l);
|
||||
|
||||
GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
|
||||
gtk_widget_size_request (child, &child_requisition);
|
||||
gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (child), part,
|
||||
&child_min, &child_nat);
|
||||
|
||||
gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size);
|
||||
max_toggle_size = MAX (max_toggle_size, toggle_size);
|
||||
max_accel_width = MAX (max_accel_width,
|
||||
GTK_MENU_ITEM (child)->accelerator_width);
|
||||
gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size);
|
||||
|
||||
part = MAX (child_min, toggle_size) / (b - t);
|
||||
min_heights[t] = MAX (min_heights[t], part);
|
||||
|
||||
part = child_requisition.width / (r - l);
|
||||
requisition->width = MAX (requisition->width, part);
|
||||
part = MAX (child_nat, toggle_size) / (b - t);
|
||||
nat_heights[t] = MAX (nat_heights[t], part);
|
||||
|
||||
part = MAX (child_requisition.height, toggle_size) / (b - t);
|
||||
priv->heights[t] = MAX (priv->heights[t], part);
|
||||
}
|
||||
|
||||
/* If the menu doesn't include any images or check items
|
||||
* reserve the space so that all menus are consistent.
|
||||
* We only do this for 'ordinary' menus, not for combobox
|
||||
* menus or multi-column menus
|
||||
*/
|
||||
if (max_toggle_size == 0 &&
|
||||
gtk_menu_get_n_columns (menu) == 1 &&
|
||||
!priv->no_toggle_size)
|
||||
{
|
||||
guint toggle_spacing;
|
||||
guint indicator_size;
|
||||
if (ret_min_heights)
|
||||
*ret_min_heights = min_heights;
|
||||
else
|
||||
g_free (min_heights);
|
||||
|
||||
gtk_style_get (widget->style,
|
||||
GTK_TYPE_CHECK_MENU_ITEM,
|
||||
"toggle-spacing", &toggle_spacing,
|
||||
"indicator-size", &indicator_size,
|
||||
NULL);
|
||||
|
||||
max_toggle_size = indicator_size + toggle_spacing;
|
||||
}
|
||||
|
||||
for (i = 0; i < gtk_menu_get_n_rows (menu); i++)
|
||||
requisition->height += priv->heights[i];
|
||||
|
||||
requisition->width += 2 * max_toggle_size + max_accel_width;
|
||||
requisition->width *= gtk_menu_get_n_columns (menu);
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (menu),
|
||||
"vertical-padding", &vertical_padding,
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
|
||||
requisition->width += (border_width + horizontal_padding + widget->style->xthickness) * 2;
|
||||
requisition->height += (border_width + vertical_padding + widget->style->ythickness) * 2;
|
||||
if (ret_nat_heights)
|
||||
*ret_nat_heights = nat_heights;
|
||||
else
|
||||
g_free (nat_heights);
|
||||
|
||||
menu->toggle_size = max_toggle_size;
|
||||
|
||||
/* Don't resize the tearoff if it is not active, because it won't redraw (it is only a background pixmap).
|
||||
*/
|
||||
if (menu->tearoff_active)
|
||||
gtk_menu_set_tearoff_hints (menu, requisition->width);
|
||||
return n_heights;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2647,10 +2635,9 @@ gtk_menu_size_allocate (GtkWidget *widget,
|
||||
GtkMenuShell *menu_shell;
|
||||
GtkWidget *child;
|
||||
GtkAllocation child_allocation;
|
||||
GtkRequisition child_requisition;
|
||||
GtkMenuPrivate *priv;
|
||||
GList *children;
|
||||
gint x, y;
|
||||
gint x, y, i;
|
||||
gint width, height;
|
||||
guint border_width;
|
||||
guint vertical_padding;
|
||||
@ -2664,23 +2651,31 @@ gtk_menu_size_allocate (GtkWidget *widget,
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
widget->allocation = *allocation;
|
||||
gtk_widget_get_child_requisition (GTK_WIDGET (menu), &child_requisition);
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (menu),
|
||||
"vertical-padding", &vertical_padding,
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
|
||||
|
||||
g_free (priv->heights);
|
||||
priv->heights_length =
|
||||
calculate_line_heights (menu,
|
||||
allocation->width,
|
||||
&priv->heights,
|
||||
NULL);
|
||||
|
||||
/* refresh our cached height request */
|
||||
priv->requested_height = (border_width + vertical_padding + GTK_WIDGET (widget)->style->ythickness) * 2;
|
||||
for (i = 0; i < priv->heights_length; i++)
|
||||
priv->requested_height += priv->heights[i];
|
||||
|
||||
x = border_width + widget->style->xthickness + horizontal_padding;
|
||||
y = border_width + widget->style->ythickness + vertical_padding;
|
||||
|
||||
width = MAX (1, allocation->width - x * 2);
|
||||
height = MAX (1, allocation->height - y * 2);
|
||||
|
||||
child_requisition.width -= x * 2;
|
||||
child_requisition.height -= y * 2;
|
||||
|
||||
if (menu_shell->active)
|
||||
gtk_menu_scroll_to (menu, menu->scroll_offset);
|
||||
|
||||
@ -2769,7 +2764,7 @@ gtk_menu_size_allocate (GtkWidget *widget,
|
||||
|
||||
if (menu->tearoff_active)
|
||||
{
|
||||
if (allocation->height >= widget->requisition.height)
|
||||
if (allocation->height >= priv->requested_height)
|
||||
{
|
||||
if (gtk_widget_get_visible (menu->tearoff_scrollbar))
|
||||
{
|
||||
@ -2781,7 +2776,7 @@ gtk_menu_size_allocate (GtkWidget *widget,
|
||||
}
|
||||
else
|
||||
{
|
||||
menu->tearoff_adjustment->upper = widget->requisition.height;
|
||||
menu->tearoff_adjustment->upper = priv->requested_height;
|
||||
menu->tearoff_adjustment->page_size = allocation->height;
|
||||
|
||||
if (menu->tearoff_adjustment->value + menu->tearoff_adjustment->page_size >
|
||||
@ -3009,6 +3004,178 @@ gtk_menu_show (GtkWidget *widget)
|
||||
GTK_WIDGET_CLASS (gtk_menu_parent_class)->show (widget);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
gtk_menu_size_request_init (GtkSizeRequestIface *iface)
|
||||
{
|
||||
iface->get_width = gtk_menu_get_width;
|
||||
iface->get_height = gtk_menu_get_height;
|
||||
iface->get_height_for_width = gtk_menu_get_height_for_width;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_get_width (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
GtkMenuShell *menu_shell;
|
||||
GtkMenuPrivate *priv;
|
||||
GtkWidget *child;
|
||||
GList *children;
|
||||
guint max_toggle_size;
|
||||
guint max_accel_width;
|
||||
guint horizontal_padding;
|
||||
guint border_width;
|
||||
gint child_min, child_nat;
|
||||
gint min_width, nat_width;
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
menu_shell = GTK_MENU_SHELL (widget);
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
min_width = nat_width = 0;
|
||||
|
||||
max_toggle_size = 0;
|
||||
max_accel_width = 0;
|
||||
|
||||
children = menu_shell->children;
|
||||
while (children)
|
||||
{
|
||||
gint part;
|
||||
gint toggle_size;
|
||||
gint l, r, t, b;
|
||||
|
||||
child = children->data;
|
||||
children = children->next;
|
||||
|
||||
if (! gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
get_effective_child_attach (child, &l, &r, &t, &b);
|
||||
|
||||
/* It's important to size_request the child
|
||||
* before doing the toggle size request, in
|
||||
* case the toggle size request depends on the size
|
||||
* request of a child of the child (e.g. for ImageMenuItem)
|
||||
*/
|
||||
|
||||
GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
|
||||
gtk_size_request_get_width (GTK_SIZE_REQUEST (child), &child_min, &child_nat);
|
||||
|
||||
gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size);
|
||||
max_toggle_size = MAX (max_toggle_size, toggle_size);
|
||||
max_accel_width = MAX (max_accel_width,
|
||||
GTK_MENU_ITEM (child)->accelerator_width);
|
||||
|
||||
part = child_min / (r - l);
|
||||
min_width = MAX (min_width, part);
|
||||
|
||||
part = child_nat / (r - l);
|
||||
nat_width = MAX (nat_width, part);
|
||||
}
|
||||
|
||||
/* If the menu doesn't include any images or check items
|
||||
* reserve the space so that all menus are consistent.
|
||||
* We only do this for 'ordinary' menus, not for combobox
|
||||
* menus or multi-column menus
|
||||
*/
|
||||
if (max_toggle_size == 0 &&
|
||||
gtk_menu_get_n_columns (menu) == 1 &&
|
||||
!priv->no_toggle_size)
|
||||
{
|
||||
guint toggle_spacing;
|
||||
guint indicator_size;
|
||||
|
||||
gtk_style_get (GTK_WIDGET (widget)->style,
|
||||
GTK_TYPE_CHECK_MENU_ITEM,
|
||||
"toggle-spacing", &toggle_spacing,
|
||||
"indicator-size", &indicator_size,
|
||||
NULL);
|
||||
|
||||
max_toggle_size = indicator_size + toggle_spacing;
|
||||
}
|
||||
|
||||
min_width += 2 * max_toggle_size + max_accel_width;
|
||||
min_width *= gtk_menu_get_n_columns (menu);
|
||||
|
||||
nat_width += 2 * max_toggle_size + max_accel_width;
|
||||
nat_width *= gtk_menu_get_n_columns (menu);
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (menu),
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
|
||||
min_width += (border_width + horizontal_padding + GTK_WIDGET (widget)->style->xthickness) * 2;
|
||||
nat_width += (border_width + horizontal_padding + GTK_WIDGET (widget)->style->xthickness) * 2;
|
||||
|
||||
menu->toggle_size = max_toggle_size;
|
||||
priv->accel_size = max_accel_width;
|
||||
|
||||
if (minimum_size)
|
||||
*minimum_size = min_width;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = nat_width;
|
||||
|
||||
/* Don't resize the tearoff if it is not active, because it won't redraw (it is only a background pixmap).
|
||||
*/
|
||||
if (menu->tearoff_active)
|
||||
gtk_menu_set_tearoff_hints (menu, min_width);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_get_height (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
gint min_width;
|
||||
|
||||
/* Menus are height-for-width only, just return the height for the minimum width */
|
||||
gtk_size_request_get_width (widget, &min_width, NULL);
|
||||
gtk_size_request_get_height_for_width (widget, min_width, minimum_size, natural_size);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_get_height_for_width (GtkSizeRequest *widget,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
GtkMenu *menu = GTK_MENU (widget);
|
||||
guint *min_heights, *nat_heights;
|
||||
guint vertical_padding, border_width;
|
||||
gint n_heights, i;
|
||||
gint min_height, nat_height;
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (menu), "vertical-padding", &vertical_padding, NULL);
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
|
||||
|
||||
min_height = nat_height = (border_width + vertical_padding + GTK_WIDGET (widget)->style->ythickness) * 2;
|
||||
|
||||
n_heights =
|
||||
calculate_line_heights (menu, for_size, &min_heights, &nat_heights);
|
||||
|
||||
for (i = 0; i < n_heights; i++)
|
||||
{
|
||||
min_height += min_heights[i];
|
||||
nat_height += nat_heights[i];
|
||||
}
|
||||
|
||||
if (minimum_size)
|
||||
*minimum_size = min_height;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = nat_height;
|
||||
|
||||
g_free (min_heights);
|
||||
g_free (nat_heights);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_menu_button_scroll (GtkMenu *menu,
|
||||
GdkEventButton *event)
|
||||
@ -3471,9 +3638,11 @@ gtk_menu_scroll_by (GtkMenu *menu,
|
||||
gint view_width, view_height;
|
||||
gboolean double_arrows;
|
||||
GtkBorder arrow_border;
|
||||
GtkMenuPrivate *priv;
|
||||
|
||||
widget = GTK_WIDGET (menu);
|
||||
offset = menu->scroll_offset + step;
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
get_arrows_border (menu, &arrow_border);
|
||||
|
||||
@ -3495,7 +3664,7 @@ gtk_menu_scroll_by (GtkMenu *menu,
|
||||
gdk_drawable_get_size (widget->window, &view_width, &view_height);
|
||||
|
||||
if (menu->scroll_offset == 0 &&
|
||||
view_height >= widget->requisition.height)
|
||||
view_height >= priv->requested_height)
|
||||
return;
|
||||
|
||||
/* Don't scroll past the bottom if we weren't before: */
|
||||
@ -3508,9 +3677,9 @@ gtk_menu_scroll_by (GtkMenu *menu,
|
||||
if (double_arrows)
|
||||
view_height -= arrow_border.bottom;
|
||||
|
||||
if ((menu->scroll_offset + view_height <= widget->requisition.height) &&
|
||||
(offset + view_height > widget->requisition.height))
|
||||
offset = widget->requisition.height - view_height;
|
||||
if ((menu->scroll_offset + view_height <= priv->requested_height) &&
|
||||
(offset + view_height > priv->requested_height))
|
||||
offset = priv->requested_height - view_height;
|
||||
|
||||
if (offset != menu->scroll_offset)
|
||||
gtk_menu_scroll_to (menu, offset);
|
||||
@ -4308,12 +4477,10 @@ gtk_menu_position (GtkMenu *menu)
|
||||
gdk_display_get_device_state (gdk_screen_get_display (screen),
|
||||
pointer, &pointer_screen, &x, &y, NULL);
|
||||
|
||||
/* We need the requisition to figure out the right place to
|
||||
* popup the menu. In fact, we always need to ask here, since
|
||||
* if a size_request was queued while we weren't popped up,
|
||||
* the requisition won't have been recomputed yet.
|
||||
/* Get the minimum height for minimum width to figure out
|
||||
* the right place to popup the menu.
|
||||
*/
|
||||
gtk_widget_size_request (widget, &requisition);
|
||||
gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), &requisition, NULL);
|
||||
|
||||
if (pointer_screen != screen)
|
||||
{
|
||||
@ -4467,7 +4634,7 @@ gtk_menu_position (GtkMenu *menu)
|
||||
|
||||
if (private->initially_pushed_in)
|
||||
{
|
||||
menu_height = GTK_WIDGET (menu)->requisition.height;
|
||||
menu_height = requisition.height;
|
||||
|
||||
if (y + menu_height > monitor.y + monitor.height)
|
||||
{
|
||||
@ -4563,8 +4730,10 @@ gtk_menu_scroll_to (GtkMenu *menu,
|
||||
guint horizontal_padding;
|
||||
gboolean double_arrows;
|
||||
GtkBorder arrow_border;
|
||||
GtkMenuPrivate *priv;
|
||||
|
||||
widget = GTK_WIDGET (menu);
|
||||
priv = gtk_menu_get_private (menu);
|
||||
|
||||
if (menu->tearoff_active &&
|
||||
menu->tearoff_adjustment &&
|
||||
@ -4590,7 +4759,7 @@ gtk_menu_scroll_to (GtkMenu *menu,
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
|
||||
view_width -= (border_width + widget->style->xthickness + horizontal_padding) * 2;
|
||||
view_height -= (border_width + widget->style->ythickness + vertical_padding) * 2;
|
||||
menu_height = widget->requisition.height -
|
||||
menu_height = priv->requested_height -
|
||||
(border_width + widget->style->ythickness + vertical_padding) * 2;
|
||||
|
||||
x = border_width + widget->style->xthickness + horizontal_padding;
|
||||
@ -5244,8 +5413,11 @@ get_menu_height (GtkMenu *menu)
|
||||
{
|
||||
gint height;
|
||||
GtkWidget *widget = GTK_WIDGET (menu);
|
||||
GtkAllocation allocation;
|
||||
|
||||
height = widget->requisition.height;
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
height = allocation.height;
|
||||
height -= gtk_container_get_border_width (GTK_CONTAINER (widget) + widget->style->ythickness) * 2;
|
||||
|
||||
if (!menu->tearoff_active)
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkactivatable.h"
|
||||
#include "gtksizerequest.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
|
||||
@ -78,8 +79,6 @@ static void gtk_menu_item_get_property (GObject *object,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gtk_menu_item_destroy (GtkObject *object);
|
||||
static void gtk_menu_item_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition);
|
||||
static void gtk_menu_item_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static void gtk_menu_item_realize (GtkWidget *widget);
|
||||
@ -125,6 +124,17 @@ static void gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
|
||||
const gchar *label);
|
||||
static G_CONST_RETURN gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item);
|
||||
|
||||
static void gtk_menu_item_size_request_init (GtkSizeRequestIface *iface);
|
||||
static void gtk_menu_item_get_width (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
static void gtk_menu_item_get_height (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
static void gtk_menu_item_get_height_for_width (GtkSizeRequest *widget,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
|
||||
static void gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface);
|
||||
static void gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
|
||||
@ -157,7 +167,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_ITEM,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
|
||||
gtk_menu_item_buildable_interface_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
|
||||
gtk_menu_item_activatable_interface_init))
|
||||
gtk_menu_item_activatable_interface_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST,
|
||||
gtk_menu_item_size_request_init))
|
||||
|
||||
#define GET_PRIVATE(object) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_MENU_ITEM, GtkMenuItemPrivate))
|
||||
@ -177,7 +189,6 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
|
||||
|
||||
object_class->destroy = gtk_menu_item_destroy;
|
||||
|
||||
widget_class->size_request = gtk_menu_item_size_request;
|
||||
widget_class->size_allocate = gtk_menu_item_size_allocate;
|
||||
widget_class->expose_event = gtk_menu_item_expose;
|
||||
widget_class->realize = gtk_menu_item_realize;
|
||||
@ -557,6 +568,384 @@ gtk_menu_item_detacher (GtkWidget *widget,
|
||||
menu_item->submenu = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
get_arrow_size (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
gint *size)
|
||||
{
|
||||
PangoContext *context;
|
||||
PangoFontMetrics *metrics;
|
||||
gfloat arrow_scaling;
|
||||
|
||||
g_assert (size);
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"arrow-scaling", &arrow_scaling,
|
||||
NULL);
|
||||
|
||||
context = gtk_widget_get_pango_context (child);
|
||||
metrics = pango_context_get_metrics (context,
|
||||
child->style->font_desc,
|
||||
pango_context_get_language (context));
|
||||
|
||||
*size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
||||
pango_font_metrics_get_descent (metrics)));
|
||||
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
*size = *size * arrow_scaling;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_menu_item_accel_width_foreach (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
guint *width = data;
|
||||
|
||||
if (GTK_IS_ACCEL_LABEL (widget))
|
||||
{
|
||||
guint w;
|
||||
|
||||
w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
|
||||
*width = MAX (*width, w);
|
||||
}
|
||||
else if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_foreach (GTK_CONTAINER (widget),
|
||||
gtk_menu_item_accel_width_foreach,
|
||||
data);
|
||||
}
|
||||
|
||||
static gint
|
||||
get_minimum_width (GtkWidget *widget)
|
||||
{
|
||||
PangoContext *context;
|
||||
PangoFontMetrics *metrics;
|
||||
gint width;
|
||||
gint width_chars;
|
||||
|
||||
context = gtk_widget_get_pango_context (widget);
|
||||
metrics = pango_context_get_metrics (context,
|
||||
widget->style->font_desc,
|
||||
pango_context_get_language (context));
|
||||
|
||||
width = pango_font_metrics_get_approximate_char_width (metrics);
|
||||
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
gtk_widget_style_get (widget, "width-chars", &width_chars, NULL);
|
||||
|
||||
return PANGO_PIXELS (width_chars * width);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_item_size_request_init (GtkSizeRequestIface *iface)
|
||||
{
|
||||
iface->get_width = gtk_menu_item_get_width;
|
||||
iface->get_height = gtk_menu_item_get_height;
|
||||
iface->get_height_for_width = gtk_menu_item_get_height_for_width;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_item_get_width (GtkSizeRequest *request,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
GtkMenuItem *menu_item;
|
||||
GtkBin *bin;
|
||||
GtkWidget *child, *widget = GTK_WIDGET (request);
|
||||
guint accel_width;
|
||||
guint horizontal_padding;
|
||||
guint border_width;
|
||||
GtkPackDirection pack_dir;
|
||||
GtkPackDirection child_pack_dir;
|
||||
gint min_width, nat_width;
|
||||
|
||||
min_width = nat_width = 0;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
bin = GTK_BIN (widget);
|
||||
menu_item = GTK_MENU_ITEM (widget);
|
||||
|
||||
if (GTK_IS_MENU_BAR (widget->parent))
|
||||
{
|
||||
pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
}
|
||||
else
|
||||
{
|
||||
pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
child_pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
}
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
|
||||
|
||||
min_width = (border_width + widget->style->xthickness) * 2;
|
||||
|
||||
if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
|
||||
(child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
|
||||
min_width += 2 * horizontal_padding;
|
||||
|
||||
nat_width = min_width;
|
||||
|
||||
child = gtk_bin_get_child (bin);
|
||||
|
||||
if (child != NULL && gtk_widget_get_visible (child))
|
||||
{
|
||||
gint child_min, child_nat;
|
||||
|
||||
gtk_size_request_get_width (GTK_SIZE_REQUEST (child), &child_min, &child_nat);
|
||||
|
||||
if (menu_item->submenu && menu_item->show_submenu_indicator)
|
||||
{
|
||||
guint arrow_spacing;
|
||||
gint arrow_size;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"arrow-spacing", &arrow_spacing,
|
||||
NULL);
|
||||
|
||||
get_arrow_size (widget, child, &arrow_size);
|
||||
|
||||
min_width += arrow_size;
|
||||
min_width += arrow_spacing;
|
||||
|
||||
min_width = MAX (min_width, get_minimum_width (widget));
|
||||
|
||||
nat_width = min_width;
|
||||
}
|
||||
|
||||
|
||||
min_width += child_min;
|
||||
nat_width += child_nat;
|
||||
|
||||
|
||||
}
|
||||
|
||||
accel_width = 0;
|
||||
gtk_container_foreach (GTK_CONTAINER (menu_item),
|
||||
gtk_menu_item_accel_width_foreach,
|
||||
&accel_width);
|
||||
menu_item->accelerator_width = accel_width;
|
||||
|
||||
if (minimum_size)
|
||||
*minimum_size = min_width;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = nat_width;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_item_get_height (GtkSizeRequest *request,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
GtkMenuItem *menu_item;
|
||||
GtkBin *bin;
|
||||
GtkWidget *child, *widget = GTK_WIDGET (request);
|
||||
guint accel_width;
|
||||
guint horizontal_padding;
|
||||
guint border_width;
|
||||
GtkPackDirection pack_dir;
|
||||
GtkPackDirection child_pack_dir;
|
||||
gint min_height, nat_height;
|
||||
|
||||
min_height = nat_height = 0;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
bin = GTK_BIN (widget);
|
||||
menu_item = GTK_MENU_ITEM (widget);
|
||||
|
||||
if (GTK_IS_MENU_BAR (widget->parent))
|
||||
{
|
||||
pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
}
|
||||
else
|
||||
{
|
||||
pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
child_pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
}
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
|
||||
min_height = (border_width + widget->style->ythickness) * 2;
|
||||
|
||||
if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
|
||||
(child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
|
||||
min_height += 2 * horizontal_padding;
|
||||
|
||||
nat_height = min_height;
|
||||
|
||||
child = gtk_bin_get_child (bin);
|
||||
|
||||
if (child != NULL && gtk_widget_get_visible (child))
|
||||
{
|
||||
gint child_min, child_nat;
|
||||
|
||||
gtk_size_request_get_height (GTK_SIZE_REQUEST (child), &child_min, &child_nat);
|
||||
|
||||
min_height += child_min;
|
||||
nat_height += child_nat;
|
||||
|
||||
if (menu_item->submenu && menu_item->show_submenu_indicator)
|
||||
{
|
||||
gint arrow_size;
|
||||
|
||||
get_arrow_size (widget, child, &arrow_size);
|
||||
|
||||
min_height = MAX (min_height, arrow_size);
|
||||
nat_height = MAX (nat_height, arrow_size);
|
||||
}
|
||||
}
|
||||
else /* separator item */
|
||||
{
|
||||
gboolean wide_separators;
|
||||
gint separator_height;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"wide-separators", &wide_separators,
|
||||
"separator-height", &separator_height,
|
||||
NULL);
|
||||
|
||||
if (wide_separators)
|
||||
min_height += separator_height + widget->style->ythickness;
|
||||
else
|
||||
min_height += widget->style->ythickness * 2;
|
||||
|
||||
nat_height = min_height;
|
||||
}
|
||||
|
||||
accel_width = 0;
|
||||
gtk_container_foreach (GTK_CONTAINER (menu_item),
|
||||
gtk_menu_item_accel_width_foreach,
|
||||
&accel_width);
|
||||
menu_item->accelerator_width = accel_width;
|
||||
|
||||
if (minimum_size)
|
||||
*minimum_size = min_height;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = nat_height;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_item_get_height_for_width (GtkSizeRequest *request,
|
||||
gint for_size,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
GtkMenuItem *menu_item;
|
||||
GtkBin *bin;
|
||||
GtkWidget *child, *widget = GTK_WIDGET (request);
|
||||
guint horizontal_padding;
|
||||
guint border_width;
|
||||
GtkPackDirection pack_dir;
|
||||
GtkPackDirection child_pack_dir;
|
||||
gint min_height, nat_height;
|
||||
gint avail_size;
|
||||
|
||||
min_height = nat_height = 0;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
bin = GTK_BIN (widget);
|
||||
menu_item = GTK_MENU_ITEM (widget);
|
||||
|
||||
if (GTK_IS_MENU_BAR (widget->parent))
|
||||
{
|
||||
pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
}
|
||||
else
|
||||
{
|
||||
pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
child_pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
}
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
|
||||
min_height = (border_width + widget->style->ythickness) * 2;
|
||||
|
||||
avail_size = for_size;
|
||||
avail_size -= (border_width + widget->style->xthickness) * 2;
|
||||
|
||||
if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
|
||||
(child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
|
||||
min_height += 2 * horizontal_padding;
|
||||
|
||||
if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
|
||||
(child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
|
||||
avail_size -= 2 * horizontal_padding;
|
||||
|
||||
nat_height = min_height;
|
||||
|
||||
child = gtk_bin_get_child (bin);
|
||||
|
||||
if (child != NULL && gtk_widget_get_visible (child))
|
||||
{
|
||||
gint child_min, child_nat;
|
||||
gint arrow_size = 0;
|
||||
|
||||
if (menu_item->submenu && menu_item->show_submenu_indicator)
|
||||
{
|
||||
|
||||
guint arrow_spacing;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"arrow-spacing", &arrow_spacing,
|
||||
NULL);
|
||||
|
||||
get_arrow_size (widget, child, &arrow_size);
|
||||
|
||||
avail_size -= arrow_size;
|
||||
avail_size -= arrow_spacing;
|
||||
}
|
||||
|
||||
gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (child), avail_size, &child_min, &child_nat);
|
||||
|
||||
min_height += child_min;
|
||||
nat_height += child_nat;
|
||||
|
||||
if (menu_item->submenu && menu_item->show_submenu_indicator)
|
||||
{
|
||||
min_height = MAX (min_height, arrow_size);
|
||||
nat_height = MAX (nat_height, arrow_size);
|
||||
}
|
||||
}
|
||||
else /* separator item */
|
||||
{
|
||||
gboolean wide_separators;
|
||||
gint separator_height;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"wide-separators", &wide_separators,
|
||||
"separator-height", &separator_height,
|
||||
NULL);
|
||||
|
||||
if (wide_separators)
|
||||
min_height += separator_height + widget->style->ythickness;
|
||||
else
|
||||
min_height += widget->style->ythickness * 2;
|
||||
|
||||
nat_height = min_height;
|
||||
}
|
||||
|
||||
if (minimum_size)
|
||||
*minimum_size = min_height;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = nat_height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface)
|
||||
{
|
||||
@ -886,140 +1275,6 @@ gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
|
||||
g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_item_accel_width_foreach (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
guint *width = data;
|
||||
|
||||
if (GTK_IS_ACCEL_LABEL (widget))
|
||||
{
|
||||
guint w;
|
||||
|
||||
w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
|
||||
*width = MAX (*width, w);
|
||||
}
|
||||
else if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_foreach (GTK_CONTAINER (widget),
|
||||
gtk_menu_item_accel_width_foreach,
|
||||
data);
|
||||
}
|
||||
|
||||
static gint
|
||||
get_minimum_width (GtkWidget *widget)
|
||||
{
|
||||
PangoContext *context;
|
||||
PangoFontMetrics *metrics;
|
||||
gint width;
|
||||
gint width_chars;
|
||||
|
||||
context = gtk_widget_get_pango_context (widget);
|
||||
metrics = pango_context_get_metrics (context,
|
||||
widget->style->font_desc,
|
||||
pango_context_get_language (context));
|
||||
|
||||
width = pango_font_metrics_get_approximate_char_width (metrics);
|
||||
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
gtk_widget_style_get (widget, "width-chars", &width_chars, NULL);
|
||||
|
||||
return PANGO_PIXELS (width_chars * width);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_item_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition)
|
||||
{
|
||||
GtkMenuItem *menu_item;
|
||||
GtkBin *bin;
|
||||
GtkWidget *child;
|
||||
guint accel_width;
|
||||
guint horizontal_padding;
|
||||
guint border_width;
|
||||
GtkPackDirection pack_dir;
|
||||
GtkPackDirection child_pack_dir;
|
||||
|
||||
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
|
||||
g_return_if_fail (requisition != NULL);
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
bin = GTK_BIN (widget);
|
||||
menu_item = GTK_MENU_ITEM (widget);
|
||||
|
||||
if (GTK_IS_MENU_BAR (widget->parent))
|
||||
{
|
||||
pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
|
||||
}
|
||||
else
|
||||
{
|
||||
pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
child_pack_dir = GTK_PACK_DIRECTION_LTR;
|
||||
}
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
|
||||
requisition->width = (border_width + widget->style->xthickness) * 2;
|
||||
requisition->height = (border_width + widget->style->ythickness) * 2;
|
||||
|
||||
if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
|
||||
(child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
|
||||
requisition->width += 2 * horizontal_padding;
|
||||
else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
|
||||
(child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
|
||||
requisition->height += 2 * horizontal_padding;
|
||||
|
||||
child = gtk_bin_get_child (bin);
|
||||
|
||||
if (child != NULL && gtk_widget_get_visible (child))
|
||||
{
|
||||
GtkRequisition child_requisition;
|
||||
|
||||
gtk_widget_size_request (child, &child_requisition);
|
||||
|
||||
requisition->width += child_requisition.width;
|
||||
requisition->height += child_requisition.height;
|
||||
|
||||
if (menu_item->submenu && menu_item->show_submenu_indicator)
|
||||
{
|
||||
guint arrow_spacing;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"arrow-spacing", &arrow_spacing,
|
||||
NULL);
|
||||
|
||||
requisition->width += child_requisition.height;
|
||||
requisition->width += arrow_spacing;
|
||||
|
||||
requisition->width = MAX (requisition->width, get_minimum_width (widget));
|
||||
}
|
||||
}
|
||||
else /* separator item */
|
||||
{
|
||||
gboolean wide_separators;
|
||||
gint separator_height;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"wide-separators", &wide_separators,
|
||||
"separator-height", &separator_height,
|
||||
NULL);
|
||||
|
||||
if (wide_separators)
|
||||
requisition->height += separator_height + widget->style->ythickness;
|
||||
else
|
||||
requisition->height += widget->style->ythickness * 2;
|
||||
}
|
||||
|
||||
accel_width = 0;
|
||||
gtk_container_foreach (GTK_CONTAINER (menu_item),
|
||||
gtk_menu_item_accel_width_foreach,
|
||||
&accel_width);
|
||||
menu_item->accelerator_width = accel_width;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_item_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation)
|
||||
@ -1224,32 +1479,17 @@ gtk_menu_item_paint (GtkWidget *widget,
|
||||
{
|
||||
gint arrow_x, arrow_y;
|
||||
gint arrow_size;
|
||||
gint arrow_extent;
|
||||
guint horizontal_padding;
|
||||
gfloat arrow_scaling;
|
||||
GtkTextDirection direction;
|
||||
GtkArrowType arrow_type;
|
||||
PangoContext *context;
|
||||
PangoFontMetrics *metrics;
|
||||
|
||||
direction = gtk_widget_get_direction (widget);
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
"arrow-scaling", &arrow_scaling,
|
||||
NULL);
|
||||
|
||||
context = gtk_widget_get_pango_context (child);
|
||||
metrics = pango_context_get_metrics (context,
|
||||
child->style->font_desc,
|
||||
pango_context_get_language (context));
|
||||
|
||||
arrow_size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
||||
pango_font_metrics_get_descent (metrics)));
|
||||
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
arrow_extent = arrow_size * arrow_scaling;
|
||||
get_arrow_size (widget, child, &arrow_size);
|
||||
|
||||
shadow_type = GTK_SHADOW_OUT;
|
||||
if (state_type == GTK_STATE_PRELIGHT)
|
||||
@ -1257,7 +1497,7 @@ gtk_menu_item_paint (GtkWidget *widget,
|
||||
|
||||
if (direction == GTK_TEXT_DIR_LTR)
|
||||
{
|
||||
arrow_x = x + width - horizontal_padding - arrow_extent;
|
||||
arrow_x = x + width - horizontal_padding - arrow_size;
|
||||
arrow_type = GTK_ARROW_RIGHT;
|
||||
}
|
||||
else
|
||||
@ -1266,14 +1506,14 @@ gtk_menu_item_paint (GtkWidget *widget,
|
||||
arrow_type = GTK_ARROW_LEFT;
|
||||
}
|
||||
|
||||
arrow_y = y + (height - arrow_extent) / 2;
|
||||
arrow_y = y + (height - arrow_size) / 2;
|
||||
|
||||
gtk_paint_arrow (widget->style, widget->window,
|
||||
state_type, shadow_type,
|
||||
area, widget, "menuitem",
|
||||
arrow_type, TRUE,
|
||||
arrow_x, arrow_y,
|
||||
arrow_extent, arrow_extent);
|
||||
arrow_size, arrow_size);
|
||||
}
|
||||
else if (!child)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user