[gtk+/wip/cosimoc/menuitem-gadget: 23/29] checkmenuitem: use a gadget for the check indicator



commit 7896e86d1ec11f8aac26f7fc155b3751f25deae1
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Fri Dec 18 14:45:15 2015 -0800

    checkmenuitem: use a gadget for the check indicator
    
    This will make margins and other CSS properties work correctly on the
    indicator.

 gtk/gtkcheckmenuitem.c                   |  200 ++++++++++++++++++++----------
 gtk/gtkmenuitem.c                        |    6 +
 gtk/gtkmenuitemprivate.h                 |    1 +
 gtk/theme/Adwaita/_common.scss           |    2 +
 gtk/theme/Adwaita/gtk-contained-dark.css |    8 ++
 gtk/theme/Adwaita/gtk-contained.css      |    8 ++
 6 files changed, 158 insertions(+), 67 deletions(-)
---
diff --git a/gtk/gtkcheckmenuitem.c b/gtk/gtkcheckmenuitem.c
index 4ed3f5c..e0d947b 100644
--- a/gtk/gtkcheckmenuitem.c
+++ b/gtk/gtkcheckmenuitem.c
@@ -24,6 +24,7 @@
 
 #include "config.h"
 #include "gtkcheckmenuitem.h"
+#include "gtkcsscustomgadgetprivate.h"
 #include "gtkmenuitemprivate.h"
 #include "gtkaccellabel.h"
 #include "deprecated/gtkactivatable.h"
@@ -67,6 +68,7 @@
 struct _GtkCheckMenuItemPrivate
 {
   GtkCssNode *indicator_node;
+  GtkCssGadget *indicator_gadget;
 
   guint active             : 1;
   guint draw_as_radio      : 1;
@@ -123,6 +125,118 @@ G_DEFINE_TYPE_WITH_CODE (GtkCheckMenuItem, gtk_check_menu_item, GTK_TYPE_MENU_IT
                                                 gtk_check_menu_item_activatable_interface_init))
 G_GNUC_END_IGNORE_DEPRECATIONS;
 
+static gboolean
+gtk_check_menu_item_render_indicator (GtkCssGadget *gadget,
+                                      cairo_t      *cr,
+                                      int           x,
+                                      int           y,
+                                      int           width,
+                                      int           height,
+                                      gpointer      data)
+{
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM (widget);
+  GtkCheckMenuItemPrivate *priv = check_menu_item->priv;
+  GtkStyleContext *context;
+
+  if (!gtk_widget_is_drawable (widget))
+    return FALSE;
+
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_save_to_node (context, priv->indicator_node);
+
+  if (priv->draw_as_radio)
+    gtk_render_option (context, cr, x, y,
+                       width, height);
+  else
+    gtk_render_check (context, cr, x, y,
+                      width, height);
+
+  gtk_style_context_restore (context);
+
+  return FALSE;
+}
+
+static void
+gtk_check_menu_item_measure_indicator (GtkCssGadget   *gadget,
+                                       GtkOrientation  orientation,
+                                       int             size,
+                                       int            *minimum,
+                                       int            *natural,
+                                       int            *minimum_baseline,
+                                       int            *natural_baseline,
+                                       gpointer        data)
+{
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  guint indicator_size;
+
+  gtk_widget_style_get (widget,
+                        "indicator-size", &indicator_size,
+                        NULL);
+
+  *minimum = *natural = indicator_size;
+}
+
+static void
+gtk_check_menu_item_size_allocate (GtkWidget     *widget,
+                                   GtkAllocation *allocation)
+{
+  GtkAllocation clip, widget_clip;
+  GtkAllocation content_alloc, indicator_alloc;
+  GtkCssGadget *menu_item_gadget;
+  GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM (widget);
+  GtkCheckMenuItemPrivate *priv = check_menu_item->priv;
+  gint content_baseline, toggle_size;
+
+  GTK_WIDGET_CLASS (gtk_check_menu_item_parent_class)->size_allocate
+    (widget, allocation);
+
+  menu_item_gadget = _gtk_menu_item_get_gadget (GTK_MENU_ITEM (widget));
+  gtk_css_gadget_get_content_allocation (menu_item_gadget,
+                                         &content_alloc, &content_baseline);
+
+  gtk_css_gadget_get_preferred_size (priv->indicator_gadget,
+                                     GTK_ORIENTATION_HORIZONTAL,
+                                     -1,
+                                     &indicator_alloc.width, NULL,
+                                     NULL, NULL);
+  gtk_css_gadget_get_preferred_size (priv->indicator_gadget,
+                                     GTK_ORIENTATION_VERTICAL,
+                                     -1,
+                                     &indicator_alloc.height, NULL,
+                                     NULL, NULL);
+  toggle_size = GTK_MENU_ITEM (check_menu_item)->priv->toggle_size;
+
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+    indicator_alloc.x = content_alloc.x +
+      (toggle_size - indicator_alloc.width) / 2;
+  else
+    indicator_alloc.x = content_alloc.x + content_alloc.width - toggle_size +
+      (toggle_size - indicator_alloc.width) / 2;
+
+  indicator_alloc.y = content_alloc.y +
+    (content_alloc.height - indicator_alloc.height) / 2;
+
+  gtk_css_gadget_allocate (check_menu_item->priv->indicator_gadget,
+                           &indicator_alloc,
+                           content_baseline,
+                           &clip);
+
+  gtk_widget_get_clip (widget, &widget_clip);
+  gdk_rectangle_union (&widget_clip, &clip, &widget_clip);
+  gtk_widget_set_clip (widget, &widget_clip);
+}
+
+static void
+gtk_check_menu_item_finalize (GObject *object)
+{
+  GtkCheckMenuItemPrivate *priv = GTK_CHECK_MENU_ITEM (object)->priv;
+
+  g_clear_object (&priv->indicator_gadget);
+
+  G_OBJECT_CLASS (gtk_check_menu_item_parent_class)->finalize (object);
+}
+
 static void
 gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass)
 {
@@ -136,7 +250,9 @@ gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass)
   
   gobject_class->set_property = gtk_check_menu_item_set_property;
   gobject_class->get_property = gtk_check_menu_item_get_property;
+  gobject_class->finalize = gtk_check_menu_item_finalize;
 
+  widget_class->size_allocate = gtk_check_menu_item_size_allocate;
   widget_class->state_flags_changed = gtk_check_menu_item_state_flags_changed;
   widget_class->direction_changed = gtk_check_menu_item_direction_changed;
 
@@ -378,17 +494,16 @@ static void
 gtk_check_menu_item_toggle_size_request (GtkMenuItem *menu_item,
                                          gint        *requisition)
 {
-  guint toggle_spacing;
-  guint indicator_size;
-  
+  GtkCheckMenuItem *check_menu_item;
+
   g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (menu_item));
-  
-  gtk_widget_style_get (GTK_WIDGET (menu_item),
-                        "toggle-spacing", &toggle_spacing,
-                        "indicator-size", &indicator_size,
-                        NULL);
 
-  *requisition = indicator_size + toggle_spacing;
+  check_menu_item = GTK_CHECK_MENU_ITEM (menu_item);
+  gtk_css_gadget_get_preferred_size (check_menu_item->priv->indicator_gadget,
+                                     GTK_ORIENTATION_HORIZONTAL,
+                                     -1,
+                                     requisition, NULL,
+                                     NULL, NULL);
 }
 
 /**
@@ -551,6 +666,14 @@ gtk_check_menu_item_init (GtkCheckMenuItem *check_menu_item)
   gtk_css_node_set_state (priv->indicator_node, gtk_css_node_get_state (widget_node));
   g_signal_connect_object (priv->indicator_node, "style-changed", G_CALLBACK (node_style_changed_cb), 
check_menu_item, 0);
   g_object_unref (priv->indicator_node);
+
+  priv->indicator_gadget =
+    gtk_css_custom_gadget_new_for_node (priv->indicator_node,
+                                        GTK_WIDGET (check_menu_item),
+                                        gtk_check_menu_item_measure_indicator,
+                                        NULL,
+                                        gtk_check_menu_item_render_indicator,
+                                        NULL, NULL);
 }
 
 static gint
@@ -635,66 +758,9 @@ static void
 gtk_real_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item,
                                          cairo_t          *cr)
 {
-  GtkCheckMenuItemPrivate *priv = check_menu_item->priv;
-  GtkWidget *widget;
-  GtkAllocation allocation;
-  GtkStyleContext *context;
-  guint border_width;
-  guint offset;
-  guint toggle_size;
-  guint toggle_spacing;
-  guint indicator_size;
-  gint x, y;
-  GtkStateFlags state;
-  GtkBorder padding;
-
-  widget = GTK_WIDGET (check_menu_item);
-
-  if (!gtk_widget_is_drawable (widget))
-    return;
-
-  context = gtk_widget_get_style_context (widget);
-  state = gtk_widget_get_state_flags (widget);
-  gtk_style_context_get_padding (context, state, &padding);
-
-  gtk_widget_get_allocation (widget, &allocation);
-
-  gtk_widget_style_get (widget,
-                        "toggle-spacing", &toggle_spacing,
-                        "indicator-size", &indicator_size,
-                        NULL);
-
-  toggle_size = GTK_MENU_ITEM (check_menu_item)->priv->toggle_size;
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-  offset = border_width + padding.left + 2;
-
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
-    {
-      x = offset +
-        (toggle_size - toggle_spacing - indicator_size) / 2;
-    }
-  else
-    {
-      x = allocation.width -
-        offset - toggle_size + toggle_spacing +
-        (toggle_size - toggle_spacing - indicator_size) / 2;
-    }
-
-  y = (allocation.height - indicator_size) / 2;
-
-  gtk_style_context_save_to_node (context, priv->indicator_node);
-
-  if (priv->draw_as_radio)
-    gtk_render_option (context, cr, x, y,
-                       indicator_size, indicator_size);
-  else
-    gtk_render_check (context, cr, x, y,
-                      indicator_size, indicator_size);
-
-  gtk_style_context_restore (context);
+  gtk_css_gadget_draw (check_menu_item->priv->indicator_gadget, cr);
 }
 
-
 static void
 gtk_check_menu_item_get_property (GObject     *object,
                                   guint        prop_id,
diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c
index a7310f0..ba85251 100644
--- a/gtk/gtkmenuitem.c
+++ b/gtk/gtkmenuitem.c
@@ -1035,6 +1035,12 @@ gtk_menu_item_init (GtkMenuItem *menu_item)
                                                      NULL, NULL);
 }
 
+GtkCssGadget *
+_gtk_menu_item_get_gadget (GtkMenuItem *menu_item)
+{
+  return menu_item->priv->gadget;
+}
+
 /**
  * gtk_menu_item_new:
  *
diff --git a/gtk/gtkmenuitemprivate.h b/gtk/gtkmenuitemprivate.h
index 5f3a6da..0832951 100644
--- a/gtk/gtkmenuitemprivate.h
+++ b/gtk/gtkmenuitemprivate.h
@@ -54,6 +54,7 @@ struct _GtkMenuItemPrivate
   guint reserve_indicator      : 1;
 };
 
+GtkCssGadget * _gtk_menu_item_get_gadget     (GtkMenuItem   *menu_item);
 void     _gtk_menu_item_refresh_accel_path   (GtkMenuItem   *menu_item,
                                               const gchar   *prefix,
                                               GtkAccelGroup *accel_group,
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index f729ede..ac58e97 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -2101,6 +2101,8 @@ switch {
     color: mix($fg_color, $bg_color, 70%);
     -gtk-icon-source: -gtk-icontheme('#{$a}-symbolic');
     -gtk-icon-shadow: none;
+    &:dir(ltr) { margin-right: 7px; }
+    &:dir(rtl) { margin-left: 7px; }
     &:hover, &:insensitive {
       -gtk-icon-source: -gtk-icontheme('#{$a}-symbolic');
       -gtk-icon-shadow: none;
diff --git a/gtk/theme/Adwaita/gtk-contained-dark.css b/gtk/theme/Adwaita/gtk-contained-dark.css
index 2582335..7f45f55 100644
--- a/gtk/theme/Adwaita/gtk-contained-dark.css
+++ b/gtk/theme/Adwaita/gtk-contained-dark.css
@@ -2766,6 +2766,10 @@ menu menuitem check {
   color: #b8bab8;
   -gtk-icon-source: -gtk-icontheme("checkbox-symbolic");
   -gtk-icon-shadow: none; }
+  menu menuitem check:dir(ltr) {
+    margin-right: 7px; }
+  menu menuitem check:dir(rtl) {
+    margin-left: 7px; }
   menu menuitem check:hover, menu menuitem check:insensitive {
     -gtk-icon-source: -gtk-icontheme("checkbox-symbolic");
     -gtk-icon-shadow: none; }
@@ -2928,6 +2932,10 @@ menu menuitem radio {
   color: #b8bab8;
   -gtk-icon-source: -gtk-icontheme("radio-symbolic");
   -gtk-icon-shadow: none; }
+  menu menuitem radio:dir(ltr) {
+    margin-right: 7px; }
+  menu menuitem radio:dir(rtl) {
+    margin-left: 7px; }
   menu menuitem radio:hover, menu menuitem radio:insensitive {
     -gtk-icon-source: -gtk-icontheme("radio-symbolic");
     -gtk-icon-shadow: none; }
diff --git a/gtk/theme/Adwaita/gtk-contained.css b/gtk/theme/Adwaita/gtk-contained.css
index e67c23d..3ba47dc 100644
--- a/gtk/theme/Adwaita/gtk-contained.css
+++ b/gtk/theme/Adwaita/gtk-contained.css
@@ -2856,6 +2856,10 @@ menu menuitem check {
   color: #666a6b;
   -gtk-icon-source: -gtk-icontheme("checkbox-symbolic");
   -gtk-icon-shadow: none; }
+  menu menuitem check:dir(ltr) {
+    margin-right: 7px; }
+  menu menuitem check:dir(rtl) {
+    margin-left: 7px; }
   menu menuitem check:hover, menu menuitem check:insensitive {
     -gtk-icon-source: -gtk-icontheme("checkbox-symbolic");
     -gtk-icon-shadow: none; }
@@ -3090,6 +3094,10 @@ menu menuitem radio {
   color: #666a6b;
   -gtk-icon-source: -gtk-icontheme("radio-symbolic");
   -gtk-icon-shadow: none; }
+  menu menuitem radio:dir(ltr) {
+    margin-right: 7px; }
+  menu menuitem radio:dir(rtl) {
+    margin-left: 7px; }
   menu menuitem radio:hover, menu menuitem radio:insensitive {
     -gtk-icon-source: -gtk-icontheme("radio-symbolic");
     -gtk-icon-shadow: none; }


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