forked from AuroraMiddleware/gtk
menuitem: convert arrow rendering to GtkCssGadget
This also deprecates the arrow-spacing style property, which can be now replaced with a simple margin.
This commit is contained in:
parent
f49a5bf116
commit
2d5d7d8cf2
@ -27,6 +27,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "gtkaccellabel.h"
|
#include "gtkaccellabel.h"
|
||||||
|
#include "gtkcontainerprivate.h"
|
||||||
#include "gtkcsscustomgadgetprivate.h"
|
#include "gtkcsscustomgadgetprivate.h"
|
||||||
#include "gtkmain.h"
|
#include "gtkmain.h"
|
||||||
#include "gtkmarshalers.h"
|
#include "gtkmarshalers.h"
|
||||||
@ -276,39 +277,71 @@ gtk_menu_item_actionable_interface_init (GtkActionableInterface *iface)
|
|||||||
iface->get_action_target_value = gtk_menu_item_get_action_target_value;
|
iface->get_action_target_value = gtk_menu_item_get_action_target_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
get_arrow_size (GtkWidget *widget,
|
gtk_menu_item_render_arrow (GtkCssGadget *gadget,
|
||||||
GtkWidget *child,
|
cairo_t *cr,
|
||||||
gint *size,
|
int x,
|
||||||
gint *spacing)
|
int y,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
gpointer data)
|
||||||
{
|
{
|
||||||
PangoContext *context;
|
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||||
PangoFontMetrics *metrics;
|
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
|
||||||
gfloat arrow_scaling;
|
GtkMenuItemPrivate *priv = menu_item->priv;
|
||||||
gint arrow_spacing;
|
GtkStyleContext *context;
|
||||||
|
GtkTextDirection direction;
|
||||||
|
gdouble angle;
|
||||||
|
|
||||||
g_assert (size);
|
context = gtk_widget_get_style_context (widget);
|
||||||
|
gtk_style_context_save_to_node (context, priv->arrow_node);
|
||||||
|
direction = gtk_widget_get_direction (widget);
|
||||||
|
|
||||||
|
if (direction == GTK_TEXT_DIR_LTR)
|
||||||
|
angle = G_PI / 2;
|
||||||
|
else
|
||||||
|
angle = (3 * G_PI) / 2;
|
||||||
|
|
||||||
|
gtk_render_arrow (context, cr, angle, x, y, width);
|
||||||
|
|
||||||
|
gtk_style_context_restore (context);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_menu_item_measure_arrow (GtkCssGadget *gadget,
|
||||||
|
GtkOrientation orientation,
|
||||||
|
int for_size,
|
||||||
|
int *minimum,
|
||||||
|
int *natural,
|
||||||
|
int *minimum_baseline,
|
||||||
|
int *natural_baseline,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||||
|
PangoContext *context;
|
||||||
|
PangoFontMetrics *metrics;
|
||||||
|
gfloat arrow_scaling;
|
||||||
|
gint size;
|
||||||
|
|
||||||
gtk_widget_style_get (widget,
|
gtk_widget_style_get (widget,
|
||||||
"arrow-scaling", &arrow_scaling,
|
"arrow-scaling", &arrow_scaling,
|
||||||
"arrow-spacing", &arrow_spacing,
|
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (spacing != NULL)
|
context = gtk_widget_get_pango_context (widget);
|
||||||
*spacing = arrow_spacing;
|
|
||||||
|
|
||||||
context = gtk_widget_get_pango_context (child);
|
|
||||||
|
|
||||||
metrics = pango_context_get_metrics (context,
|
metrics = pango_context_get_metrics (context,
|
||||||
pango_context_get_font_description (context),
|
pango_context_get_font_description (context),
|
||||||
pango_context_get_language (context));
|
pango_context_get_language (context));
|
||||||
|
|
||||||
*size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
size = arrow_scaling *
|
||||||
pango_font_metrics_get_descent (metrics)));
|
(PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
||||||
|
pango_font_metrics_get_descent (metrics)));
|
||||||
|
|
||||||
pango_font_metrics_unref (metrics);
|
pango_font_metrics_unref (metrics);
|
||||||
|
|
||||||
*size = *size * arrow_scaling;
|
*minimum = *natural = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -333,32 +366,7 @@ gtk_menu_item_render (GtkCssGadget *gadget,
|
|||||||
|
|
||||||
if (priv->submenu && !GTK_IS_MENU_BAR (parent))
|
if (priv->submenu && !GTK_IS_MENU_BAR (parent))
|
||||||
{
|
{
|
||||||
gint arrow_x, arrow_y;
|
gtk_css_gadget_draw (priv->arrow_gadget, cr);
|
||||||
gint arrow_size;
|
|
||||||
GtkTextDirection direction;
|
|
||||||
gdouble angle;
|
|
||||||
|
|
||||||
gtk_style_context_save_to_node (context, priv->arrow_node);
|
|
||||||
|
|
||||||
direction = gtk_widget_get_direction (widget);
|
|
||||||
get_arrow_size (widget, child, &arrow_size, NULL);
|
|
||||||
|
|
||||||
if (direction == GTK_TEXT_DIR_LTR)
|
|
||||||
{
|
|
||||||
arrow_x = width - arrow_size;
|
|
||||||
angle = G_PI / 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arrow_x = 0;
|
|
||||||
angle = (3 * G_PI) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
arrow_y = (height - arrow_size) / 2;
|
|
||||||
|
|
||||||
gtk_render_arrow (context, cr, angle, arrow_x, arrow_y, arrow_size);
|
|
||||||
|
|
||||||
gtk_style_context_restore (context);
|
|
||||||
}
|
}
|
||||||
else if (!child)
|
else if (!child)
|
||||||
{
|
{
|
||||||
@ -404,6 +412,7 @@ gtk_menu_item_allocate (GtkCssGadget *gadget,
|
|||||||
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
|
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
|
||||||
GtkMenuItemPrivate *priv = menu_item->priv;
|
GtkMenuItemPrivate *priv = menu_item->priv;
|
||||||
GtkAllocation child_allocation;
|
GtkAllocation child_allocation;
|
||||||
|
GtkAllocation arrow_clip = { 0 };
|
||||||
GtkTextDirection direction;
|
GtkTextDirection direction;
|
||||||
GtkPackDirection child_pack_dir;
|
GtkPackDirection child_pack_dir;
|
||||||
GtkWidget *child;
|
GtkWidget *child;
|
||||||
@ -445,19 +454,46 @@ gtk_menu_item_allocate (GtkCssGadget *gadget,
|
|||||||
|
|
||||||
if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
|
if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
|
||||||
{
|
{
|
||||||
gint arrow_spacing, arrow_size;
|
GtkAllocation arrow_alloc;
|
||||||
|
|
||||||
get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
|
gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
|
||||||
|
GTK_ORIENTATION_HORIZONTAL,
|
||||||
|
-1,
|
||||||
|
&arrow_alloc.width, NULL,
|
||||||
|
NULL, NULL);
|
||||||
|
gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
|
||||||
|
GTK_ORIENTATION_VERTICAL,
|
||||||
|
-1,
|
||||||
|
&arrow_alloc.height, NULL,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
if (direction == GTK_TEXT_DIR_RTL)
|
if (direction == GTK_TEXT_DIR_LTR)
|
||||||
child_allocation.x += arrow_size + arrow_spacing;
|
{
|
||||||
child_allocation.width -= arrow_size + arrow_spacing;
|
arrow_alloc.x = child_allocation.x +
|
||||||
|
child_allocation.width - arrow_alloc.width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arrow_alloc.x = 0;
|
||||||
|
child_allocation.x += arrow_alloc.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
child_allocation.width -= arrow_alloc.width;
|
||||||
|
arrow_alloc.y = child_allocation.y +
|
||||||
|
(child_allocation.height - arrow_alloc.height) / 2;
|
||||||
|
|
||||||
|
gtk_css_gadget_allocate (priv->arrow_gadget,
|
||||||
|
&arrow_alloc,
|
||||||
|
baseline,
|
||||||
|
&arrow_clip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_allocation.width < 1)
|
child_allocation.width = MAX (1, child_allocation.width);
|
||||||
child_allocation.width = 1;
|
|
||||||
|
|
||||||
gtk_widget_size_allocate (child, &child_allocation);
|
gtk_widget_size_allocate (child, &child_allocation);
|
||||||
|
|
||||||
|
gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip);
|
||||||
|
gdk_rectangle_union (out_clip, &arrow_clip, out_clip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gtk_widget_get_realized (widget))
|
if (gtk_widget_get_realized (widget))
|
||||||
@ -529,14 +565,17 @@ gtk_menu_item_real_get_width (GtkWidget *widget,
|
|||||||
|
|
||||||
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
|
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
|
||||||
|
|
||||||
if ((menu_item->priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
|
if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
|
||||||
{
|
{
|
||||||
gint arrow_spacing, arrow_size;
|
gint arrow_size;
|
||||||
|
|
||||||
get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
|
gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
|
||||||
|
GTK_ORIENTATION_HORIZONTAL,
|
||||||
|
-1,
|
||||||
|
&arrow_size, NULL,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
min_width += arrow_size;
|
min_width += arrow_size;
|
||||||
min_width += arrow_spacing;
|
|
||||||
nat_width = min_width;
|
nat_width = min_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,14 +618,18 @@ gtk_menu_item_real_get_height (GtkWidget *widget,
|
|||||||
if (child != NULL && gtk_widget_get_visible (child))
|
if (child != NULL && gtk_widget_get_visible (child))
|
||||||
{
|
{
|
||||||
gint child_min, child_nat;
|
gint child_min, child_nat;
|
||||||
gint arrow_size = 0, arrow_spacing = 0;
|
gint arrow_size = 0;
|
||||||
|
|
||||||
if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
|
if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
|
||||||
get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
|
gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
|
||||||
|
GTK_ORIENTATION_VERTICAL,
|
||||||
|
-1,
|
||||||
|
&arrow_size, NULL,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
if (for_size != -1)
|
if (for_size != -1)
|
||||||
{
|
{
|
||||||
avail_size -= (arrow_size + arrow_spacing);
|
avail_size -= arrow_size;
|
||||||
gtk_widget_get_preferred_height_for_width (child,
|
gtk_widget_get_preferred_height_for_width (child,
|
||||||
avail_size,
|
avail_size,
|
||||||
&child_min,
|
&child_min,
|
||||||
@ -935,6 +978,14 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
|
|||||||
5,
|
5,
|
||||||
GTK_PARAM_READABLE));
|
GTK_PARAM_READABLE));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GtkMenuItem:arrow-spacing:
|
||||||
|
*
|
||||||
|
* Spacing between menu item label and submenu arrow.
|
||||||
|
*
|
||||||
|
* Deprecated: 3.20: use the standard margin CSS property on the arrow node;
|
||||||
|
* the value of this style property is ignored.
|
||||||
|
*/
|
||||||
gtk_widget_class_install_style_property (widget_class,
|
gtk_widget_class_install_style_property (widget_class,
|
||||||
g_param_spec_int ("arrow-spacing",
|
g_param_spec_int ("arrow-spacing",
|
||||||
"Arrow Spacing",
|
"Arrow Spacing",
|
||||||
@ -942,7 +993,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
|
|||||||
0,
|
0,
|
||||||
G_MAXINT,
|
G_MAXINT,
|
||||||
10,
|
10,
|
||||||
GTK_PARAM_READABLE));
|
GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
|
||||||
|
|
||||||
gtk_widget_class_install_style_property (widget_class,
|
gtk_widget_class_install_style_property (widget_class,
|
||||||
g_param_spec_float ("arrow-scaling",
|
g_param_spec_float ("arrow-scaling",
|
||||||
@ -1078,6 +1129,7 @@ gtk_menu_item_dispose (GObject *object)
|
|||||||
priv->action = NULL;
|
priv->action = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_object (&priv->arrow_gadget);
|
||||||
g_clear_object (&priv->gadget);
|
g_clear_object (&priv->gadget);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object);
|
G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object);
|
||||||
@ -1214,6 +1266,8 @@ gtk_menu_item_detacher (GtkWidget *widget,
|
|||||||
gtk_css_node_set_parent (priv->arrow_node, NULL);
|
gtk_css_node_set_parent (priv->arrow_node, NULL);
|
||||||
priv->arrow_node = NULL;
|
priv->arrow_node = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_object (&priv->arrow_gadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1571,6 +1625,14 @@ gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
|
|||||||
gtk_css_node_set_state (priv->arrow_node, gtk_css_node_get_state (widget_node));
|
gtk_css_node_set_state (priv->arrow_node, gtk_css_node_get_state (widget_node));
|
||||||
g_signal_connect_object (priv->arrow_node, "style-changed", G_CALLBACK (node_style_changed_cb), menu_item, 0);
|
g_signal_connect_object (priv->arrow_node, "style-changed", G_CALLBACK (node_style_changed_cb), menu_item, 0);
|
||||||
|
|
||||||
|
priv->arrow_gadget =
|
||||||
|
gtk_css_custom_gadget_new_for_node (priv->arrow_node,
|
||||||
|
GTK_WIDGET (menu_item),
|
||||||
|
gtk_menu_item_measure_arrow,
|
||||||
|
NULL,
|
||||||
|
gtk_menu_item_render_arrow,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
update_node_classes (menu_item);
|
update_node_classes (menu_item);
|
||||||
|
|
||||||
g_object_unref (priv->arrow_node);
|
g_object_unref (priv->arrow_node);
|
||||||
|
@ -42,6 +42,7 @@ struct _GtkMenuItemPrivate
|
|||||||
GtkActionHelper *action_helper;
|
GtkActionHelper *action_helper;
|
||||||
|
|
||||||
GtkCssGadget *gadget;
|
GtkCssGadget *gadget;
|
||||||
|
GtkCssGadget *arrow_gadget;
|
||||||
GtkCssNode *arrow_node;
|
GtkCssNode *arrow_node;
|
||||||
|
|
||||||
guint submenu_placement : 1;
|
guint submenu_placement : 1;
|
||||||
|
@ -1514,8 +1514,14 @@ menu,
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
//submenu indicators
|
//submenu indicators
|
||||||
& arrow { -gtk-icon-source: -gtk-icontheme('pan-end-symbolic'); }
|
& arrow {
|
||||||
& arrow:dir(rtl) {-gtk-icon-source:-gtk-icontheme('pan-end-symbolic-rtl'); }
|
-gtk-icon-source: -gtk-icontheme('pan-end-symbolic');
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
& arrow:dir(rtl) {
|
||||||
|
-gtk-icon-source:-gtk-icontheme('pan-end-symbolic-rtl');
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
& arrow { // overlow buttons
|
& arrow { // overlow buttons
|
||||||
@extend %undecorated_button;
|
@extend %undecorated_button;
|
||||||
|
@ -2125,10 +2125,12 @@ menu,
|
|||||||
background-color: transparent; }
|
background-color: transparent; }
|
||||||
menu menuitem arrow,
|
menu menuitem arrow,
|
||||||
.menu menuitem arrow {
|
.menu menuitem arrow {
|
||||||
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); }
|
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic");
|
||||||
|
margin-left: 10px; }
|
||||||
menu menuitem arrow:dir(rtl),
|
menu menuitem arrow:dir(rtl),
|
||||||
.menu menuitem arrow:dir(rtl) {
|
.menu menuitem arrow:dir(rtl) {
|
||||||
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); }
|
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl");
|
||||||
|
margin-right: 10px; }
|
||||||
menu arrow,
|
menu arrow,
|
||||||
.menu arrow {
|
.menu arrow {
|
||||||
border-style: none;
|
border-style: none;
|
||||||
|
@ -2131,10 +2131,12 @@ menu,
|
|||||||
background-color: transparent; }
|
background-color: transparent; }
|
||||||
menu menuitem arrow,
|
menu menuitem arrow,
|
||||||
.menu menuitem arrow {
|
.menu menuitem arrow {
|
||||||
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); }
|
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic");
|
||||||
|
margin-left: 10px; }
|
||||||
menu menuitem arrow:dir(rtl),
|
menu menuitem arrow:dir(rtl),
|
||||||
.menu menuitem arrow:dir(rtl) {
|
.menu menuitem arrow:dir(rtl) {
|
||||||
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); }
|
-gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl");
|
||||||
|
margin-right: 10px; }
|
||||||
menu arrow,
|
menu arrow,
|
||||||
.menu arrow {
|
.menu arrow {
|
||||||
border-style: none;
|
border-style: none;
|
||||||
|
@ -1176,6 +1176,12 @@ menu,
|
|||||||
|
|
||||||
menuitem {
|
menuitem {
|
||||||
min-width: 40px;
|
min-width: 40px;
|
||||||
|
& arrow {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
& arrow:dir(rtl) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,6 +1304,12 @@ menu,
|
|||||||
menu menuitem,
|
menu menuitem,
|
||||||
.menu menuitem {
|
.menu menuitem {
|
||||||
min-width: 40px; }
|
min-width: 40px; }
|
||||||
|
menu menuitem arrow,
|
||||||
|
.menu menuitem arrow {
|
||||||
|
margin-left: 10px; }
|
||||||
|
menu menuitem arrow:dir(rtl),
|
||||||
|
.menu menuitem arrow:dir(rtl) {
|
||||||
|
margin-right: 10px; }
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
* Popovers *
|
* Popovers *
|
||||||
|
Loading…
Reference in New Issue
Block a user