[gtk+/wip/cosimoc/menuitem-gadget: 1/8] menuitem: convert arrow rendering to GtkCssGadget



commit 8317ebbe51a347b68032770172c47d37a9d34f41
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Thu Dec 17 21:41:40 2015 -0800

    menuitem: convert arrow rendering to GtkCssGadget
    
    This also deprecates the arrow-spacing style property, which can be now
    replaced with a simple margin.

 gtk/gtkmenuitem.c                        |  178 ++++++++++++++++++++----------
 gtk/gtkmenuitemprivate.h                 |    1 +
 gtk/theme/Adwaita/_common.scss           |   10 ++-
 gtk/theme/Adwaita/gtk-contained-dark.css |    6 +-
 gtk/theme/Adwaita/gtk-contained.css      |    6 +-
 gtk/theme/HighContrast/_common.scss      |    6 +
 gtk/theme/HighContrast/gtk.css           |    6 +
 7 files changed, 149 insertions(+), 64 deletions(-)
---
diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c
index 0d19be6..f37ee9e 100644
--- a/gtk/gtkmenuitem.c
+++ b/gtk/gtkmenuitem.c
@@ -27,6 +27,7 @@
 #include <string.h>
 
 #include "gtkaccellabel.h"
+#include "gtkcontainerprivate.h"
 #include "gtkcsscustomgadgetprivate.h"
 #include "gtkmain.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;
 }
 
+static gboolean
+gtk_menu_item_render_arrow (GtkCssGadget *gadget,
+                            cairo_t      *cr,
+                            int           x,
+                            int           y,
+                            int           width,
+                            int           height,
+                            gpointer      data)
+{
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
+  GtkMenuItemPrivate *priv = menu_item->priv;
+  GtkStyleContext *context;
+  GtkTextDirection direction;
+  gdouble angle;
+
+  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
-get_arrow_size (GtkWidget *widget,
-                GtkWidget *child,
-                gint      *size,
-                gint      *spacing)
+gtk_menu_item_measure_arrow (GtkCssGadget   *gadget,
+                             GtkOrientation  orientation,
+                             int             for_size,
+                             int            *minimum,
+                             int            *natural,
+                             int            *minimum_baseline,
+                             int            *natural_baseline,
+                             gpointer        data)
 {
-  PangoContext     *context;
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  PangoContext *context;
   PangoFontMetrics *metrics;
-  gfloat            arrow_scaling;
-  gint              arrow_spacing;
-
-  g_assert (size);
+  gfloat arrow_scaling;
+  gint size;
 
   gtk_widget_style_get (widget,
                         "arrow-scaling", &arrow_scaling,
-                        "arrow-spacing", &arrow_spacing,
                         NULL);
 
-  if (spacing != NULL)
-    *spacing = arrow_spacing;
-
-  context = gtk_widget_get_pango_context (child);
+  context = gtk_widget_get_pango_context (widget);
 
   metrics = pango_context_get_metrics (context,
                                        pango_context_get_font_description (context),
                                        pango_context_get_language (context));
 
-  *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
-                         pango_font_metrics_get_descent (metrics)));
+  size = arrow_scaling *
+    (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
+                   pango_font_metrics_get_descent (metrics)));
 
   pango_font_metrics_unref (metrics);
 
-  *size = *size * arrow_scaling;
+  *minimum = *natural = size;
 }
 
 static gboolean
@@ -333,32 +366,7 @@ gtk_menu_item_render (GtkCssGadget *gadget,
 
   if (priv->submenu && !GTK_IS_MENU_BAR (parent))
     {
-      gint arrow_x, arrow_y;
-      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);
+      gtk_css_gadget_draw (priv->arrow_gadget, cr);
     }
   else if (!child)
     {
@@ -404,6 +412,7 @@ gtk_menu_item_allocate (GtkCssGadget        *gadget,
   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
   GtkMenuItemPrivate *priv = menu_item->priv;
   GtkAllocation child_allocation;
+  GtkAllocation arrow_clip = { 0 };
   GtkTextDirection direction;
   GtkPackDirection child_pack_dir;
   GtkWidget *child;
@@ -445,19 +454,46 @@ gtk_menu_item_allocate (GtkCssGadget        *gadget,
 
       if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
        {
-         gint arrow_spacing, arrow_size;
+          GtkAllocation arrow_alloc;
+
+          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);
 
-         get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
+          if (direction == GTK_TEXT_DIR_LTR)
+            {
+              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;
 
-         if (direction == GTK_TEXT_DIR_RTL)
-           child_allocation.x += arrow_size + arrow_spacing;
-         child_allocation.width -= arrow_size + arrow_spacing;
+          gtk_css_gadget_allocate (priv->arrow_gadget,
+                                   &arrow_alloc,
+                                   baseline,
+                                   &arrow_clip);
        }
 
-      if (child_allocation.width < 1)
-        child_allocation.width = 1;
+      child_allocation.width = MAX (1, child_allocation.width);
 
       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))
@@ -529,14 +565,17 @@ gtk_menu_item_real_get_width (GtkWidget *widget,
 
       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_spacing;
           nat_width = min_width;
         }
 
@@ -579,14 +618,18 @@ gtk_menu_item_real_get_height (GtkWidget *widget,
   if (child != NULL && gtk_widget_get_visible (child))
     {
       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)
-        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)
         {
-          avail_size -= (arrow_size + arrow_spacing);
+          avail_size -= arrow_size;
           gtk_widget_get_preferred_height_for_width (child,
                                                      avail_size,
                                                      &child_min,
@@ -935,6 +978,14 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
                                                              5,
                                                              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,
                                            g_param_spec_int ("arrow-spacing",
                                                              "Arrow Spacing",
@@ -942,7 +993,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
                                                              0,
                                                              G_MAXINT,
                                                              10,
-                                                             GTK_PARAM_READABLE));
+                                                             GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
 
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_float ("arrow-scaling",
@@ -1078,6 +1129,7 @@ gtk_menu_item_dispose (GObject *object)
       priv->action = NULL;
     }
 
+  g_clear_object (&priv->arrow_gadget);
   g_clear_object (&priv->gadget);
 
   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);
       priv->arrow_node = NULL;
     }
+
+  g_clear_object (&priv->arrow_gadget);
 }
 
 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));
               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);
 
               g_object_unref (priv->arrow_node);
diff --git a/gtk/gtkmenuitemprivate.h b/gtk/gtkmenuitemprivate.h
index f8069cd..5f3a6da 100644
--- a/gtk/gtkmenuitemprivate.h
+++ b/gtk/gtkmenuitemprivate.h
@@ -42,6 +42,7 @@ struct _GtkMenuItemPrivate
   GtkActionHelper *action_helper;
 
   GtkCssGadget *gadget;
+  GtkCssGadget *arrow_gadget;
   GtkCssNode *arrow_node;
 
   guint submenu_placement      : 1;
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index 1032e3c..a70aa1a 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -1514,8 +1514,14 @@ menu,
       background-color: transparent;
     }
     //submenu indicators
-    & arrow { -gtk-icon-source: -gtk-icontheme('pan-end-symbolic'); }
-    & arrow:dir(rtl) {-gtk-icon-source:-gtk-icontheme('pan-end-symbolic-rtl'); }
+    & arrow {
+      -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
     @extend %undecorated_button;
diff --git a/gtk/theme/Adwaita/gtk-contained-dark.css b/gtk/theme/Adwaita/gtk-contained-dark.css
index b304fde..839682b 100644
--- a/gtk/theme/Adwaita/gtk-contained-dark.css
+++ b/gtk/theme/Adwaita/gtk-contained-dark.css
@@ -2119,10 +2119,12 @@ menu,
       background-color: transparent; }
     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) {
-      -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 {
     border-style: none;
diff --git a/gtk/theme/Adwaita/gtk-contained.css b/gtk/theme/Adwaita/gtk-contained.css
index 0902716..db985f4 100644
--- a/gtk/theme/Adwaita/gtk-contained.css
+++ b/gtk/theme/Adwaita/gtk-contained.css
@@ -2125,10 +2125,12 @@ menu,
       background-color: transparent; }
     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) {
-      -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 {
     border-style: none;
diff --git a/gtk/theme/HighContrast/_common.scss b/gtk/theme/HighContrast/_common.scss
index 9e243cb..fa2aece 100644
--- a/gtk/theme/HighContrast/_common.scss
+++ b/gtk/theme/HighContrast/_common.scss
@@ -1176,6 +1176,12 @@ menu,
 
   menuitem {
     min-width: 40px;
+    & arrow {
+      margin-left: 10px;
+    }
+    & arrow:dir(rtl) {
+      margin-right: 10px;
+    }
   }
 }
 
diff --git a/gtk/theme/HighContrast/gtk.css b/gtk/theme/HighContrast/gtk.css
index 7744f91..10fa379 100644
--- a/gtk/theme/HighContrast/gtk.css
+++ b/gtk/theme/HighContrast/gtk.css
@@ -1304,6 +1304,12 @@ menu,
   menu menuitem,
   .menu menuitem {
     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   *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]