[gtk+/wip/matthiasc/gadget] expander: Convert to gadgets



commit 0de4081b5415fc532f66c337585fc4fcb76dc00a
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Dec 8 10:04:03 2015 -0500

    expander: Convert to gadgets
    
    As part of the conversion, add another CSS node for the title
    area including the arrow and the label.

 gtk/gtkexpander.c |  845 +++++++++++++++++++++++++++++++----------------------
 1 files changed, 493 insertions(+), 352 deletions(-)
---
diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c
index c75aafd..4921fd8 100644
--- a/gtk/gtkexpander.c
+++ b/gtk/gtkexpander.c
@@ -92,11 +92,15 @@
  *
  * |[<!-- language="plain" -->
  * expander
- * ╰── arrow
+ * ├── title
+ * │   ├── arrow
+ * │   ╰── label widget
+ * ╰── child
  * ]|
  *
- * GtkExpander has two css nodes, the main node with the name expander and a subnode
- * named slider. Neither of them is using any style classes.
+ * GtkExpander has three CSS nodes, the main node with the name expander,
+ * a subnode with name title and node below it with name arrow. Neither of
+ * them is using any style classes.
  */
 
 #include "config.h"
@@ -115,8 +119,9 @@
 #include "gtkdnd.h"
 #include "a11y/gtkexpanderaccessible.h"
 #include "gtkstylecontextprivate.h"
-#include "gtkcssstylepropertyprivate.h"
+#include "gtkcsscustomgadgetprivate.h"
 #include "gtkwidgetprivate.h"
+#include "gtkcontainerprivate.h"
 
 
 #define DEFAULT_EXPANDER_SIZE 10
@@ -141,18 +146,20 @@ struct _GtkExpanderPrivate
   GtkWidget        *label_widget;
   GdkWindow        *event_window;
 
-  GtkCssNode       *arrow_node;
+  GtkCssGadget     *gadget;
+  GtkCssGadget     *title_gadget;
+  GtkCssGadget     *arrow_gadget;
 
   GtkGesture       *multipress_gesture;
   gint              spacing;
 
   guint             expand_timer;
 
-  guint             expanded : 1;
-  guint             use_underline : 1;
-  guint             use_markup : 1;
-  guint             prelight : 1;
-  guint             label_fill : 1;
+  guint             expanded        : 1;
+  guint             use_underline   : 1;
+  guint             use_markup      : 1;
+  guint             prelight        : 1;
+  guint             label_fill      : 1;
   guint             resize_toplevel : 1;
 };
 
@@ -227,6 +234,10 @@ static void  gtk_expander_get_preferred_width_for_height  (GtkWidget           *
                                                            gint                 width,
                                                            gint                *minimum_height,
                                                            gint                *natural_height);
+static void gtk_expander_state_flags_changed (GtkWidget        *widget,
+                                              GtkStateFlags     previous_state);
+static void gtk_expander_direction_changed   (GtkWidget        *widget,
+                                              GtkTextDirection  previous_direction);
 
 /* Gestures */
 static void     gesture_multipress_released_cb (GtkGestureMultiPress *gesture,
@@ -235,6 +246,64 @@ static void     gesture_multipress_released_cb (GtkGestureMultiPress *gesture,
                                                 gdouble               y,
                                                 GtkExpander          *expander);
 
+/* Gadgets */
+static void     gtk_expander_get_content_size      (GtkCssGadget        *gadget,
+                                          GtkOrientation       orientation,
+                                          gint                 for_size,
+                                          gint                *minimum_size,
+                                          gint                *natural_size,
+                                          gint                *minimum_baseline,
+                                          gint                *natural_baseline,
+                                          gpointer             data);
+static void     gtk_expander_allocate      (GtkCssGadget        *gadget,
+                                          const GtkAllocation *allocation,
+                                          int                  baseline,
+                                          GtkAllocation       *out_clip,
+                                          gpointer             data);
+static gboolean gtk_expander_draw_contents (GtkCssGadget        *gadget,
+                                          cairo_t             *cr,
+                                          int                  x,
+                                          int                  y,
+                                          int                  width,
+                                          int                  height,
+                                          gpointer             data);
+static void     gtk_expander_get_title_size      (GtkCssGadget        *gadget,
+                                          GtkOrientation       orientation,
+                                          gint                 for_size,
+                                          gint                *minimum_size,
+                                          gint                *natural_size,
+                                          gint                *minimum_baseline,
+                                          gint                *natural_baseline,
+                                          gpointer             data);
+static void     gtk_expander_allocate_title      (GtkCssGadget        *gadget,
+                                          const GtkAllocation *allocation,
+                                          int                  baseline,
+                                          GtkAllocation       *out_clip,
+                                          gpointer             data);
+static gboolean gtk_expander_draw_title (GtkCssGadget        *gadget,
+                                          cairo_t             *cr,
+                                          int                  x,
+                                          int                  y,
+                                          int                  width,
+                                          int                  height,
+                                          gpointer             data);
+static void     gtk_expander_get_arrow_size      (GtkCssGadget        *gadget,
+                                          GtkOrientation       orientation,
+                                          gint                 for_size,
+                                          gint                *minimum_size,
+                                          gint                *natural_size,
+                                          gint                *minimum_baseline,
+                                          gint                *natural_baseline,
+                                          gpointer             data);
+static gboolean gtk_expander_draw_arrow (GtkCssGadget        *gadget,
+                                          cairo_t             *cr,
+                                          int                  x,
+                                          int                  y,
+                                          int                  width,
+                                          int                  height,
+                                          gpointer             data);
+
+
 G_DEFINE_TYPE_WITH_CODE (GtkExpander, gtk_expander, GTK_TYPE_BIN,
                          G_ADD_PRIVATE (GtkExpander)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
@@ -270,6 +339,8 @@ gtk_expander_class_init (GtkExpanderClass *klass)
   widget_class->get_preferred_height           = gtk_expander_get_preferred_height;
   widget_class->get_preferred_height_for_width = gtk_expander_get_preferred_height_for_width;
   widget_class->get_preferred_width_for_height = gtk_expander_get_preferred_width_for_height;
+  widget_class->state_flags_changed  = gtk_expander_state_flags_changed;
+  widget_class->direction_changed  = gtk_expander_direction_changed;
 
   container_class->add    = gtk_expander_add;
   container_class->remove = gtk_expander_remove;
@@ -383,29 +454,6 @@ gtk_expander_class_init (GtkExpanderClass *klass)
 }
 
 static void
-node_style_changed_cb (GtkCssNode  *node,
-                       GtkCssStyle *old_style,
-                       GtkCssStyle *new_style,
-                       GtkWidget   *widget)
-{
-  GtkBitmask *changes;
-  static GtkBitmask *affects_size = NULL;
-
-  if (G_UNLIKELY (affects_size == NULL))
-    affects_size = _gtk_css_style_property_get_mask_affecting (GTK_CSS_AFFECTS_SIZE | GTK_CSS_AFFECTS_CLIP);
-
-  changes = _gtk_bitmask_new ();
-  changes = gtk_css_style_add_difference (changes, old_style, new_style);
-
-  if (_gtk_bitmask_intersects (changes, affects_size))
-    gtk_widget_queue_resize (widget);
-  else
-    gtk_widget_queue_draw (widget);
-
-  _gtk_bitmask_free (changes);
-}
-
-static void
 gtk_expander_init (GtkExpander *expander)
 {
   GtkExpanderPrivate *priv;
@@ -429,12 +477,31 @@ gtk_expander_init (GtkExpander *expander)
   priv->resize_toplevel = 0;
 
   widget_node = gtk_widget_get_css_node (GTK_WIDGET (expander));
-  priv->arrow_node = gtk_css_node_new ();
-  gtk_css_node_set_name (priv->arrow_node, I_("arrow"));
-  gtk_css_node_set_parent (priv->arrow_node, 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), expander, 
0);
-  g_object_unref (priv->arrow_node);
+  priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
+                                                     GTK_WIDGET (expander),
+                                                     gtk_expander_get_content_size,
+                                                     gtk_expander_allocate,
+                                                     gtk_expander_draw_contents,
+                                                     NULL,
+                                                     NULL);
+  priv->title_gadget = gtk_css_custom_gadget_new ("title",
+                                                  GTK_WIDGET (expander),
+                                                  priv->gadget,
+                                                  NULL,
+                                                  gtk_expander_get_title_size,
+                                                  gtk_expander_allocate_title,
+                                                  gtk_expander_draw_title,
+                                                  NULL,
+                                                  NULL);
+  priv->arrow_gadget = gtk_css_custom_gadget_new ("arrow",
+                                                  GTK_WIDGET (expander),
+                                                  priv->title_gadget,
+                                                  NULL,
+                                                  gtk_expander_get_arrow_size,
+                                                  NULL,
+                                                  gtk_expander_draw_arrow,
+                                                  NULL,
+                                                  NULL);
 
   gtk_drag_dest_set (GTK_WIDGET (expander), 0, NULL, 0, 0);
   gtk_drag_dest_set_track_motion (GTK_WIDGET (expander), TRUE);
@@ -566,70 +633,11 @@ gtk_expander_destroy (GtkWidget *widget)
 
   g_clear_object (&priv->multipress_gesture);
 
-  GTK_WIDGET_CLASS (gtk_expander_parent_class)->destroy (widget);
-}
+  g_clear_object (&priv->arrow_gadget);
+  g_clear_object (&priv->title_gadget);
+  g_clear_object (&priv->gadget);
 
-static void
-get_padding_and_border (GtkWidget *widget,
-                        GtkBorder *border)
-{
-  GtkStyleContext *context;
-  GtkStateFlags state;
-  GtkBorder tmp;
-
-  context = gtk_widget_get_style_context (widget);
-  state = gtk_style_context_get_state (context);
-
-  gtk_style_context_get_padding (context, state, border);
-  gtk_style_context_get_border (context, state, &tmp);
-  border->top += tmp.top;
-  border->right += tmp.right;
-  border->bottom += tmp.bottom;
-  border->left += tmp.left;
-}
-
-static void
-get_prelight_area_bounds (GtkExpander *expander,
-                          GdkRectangle *area)
-{
-  GtkWidget *widget;
-  GtkExpanderPrivate *priv;
-  GtkAllocation allocation;
-  GtkContainer *container;
-  int expander_size;
-  int expander_spacing;
-  guint border_width;
-  GtkBorder border;
-
-  priv = expander->priv;
-  widget = GTK_WIDGET (expander);
-  container = GTK_CONTAINER (expander);
-
-  gtk_widget_style_get (widget,
-                        "expander-size", &expander_size,
-                        "expander-spacing", &expander_spacing,
-                        NULL);
-
-  gtk_widget_get_allocation (widget, &allocation);
-  get_padding_and_border (widget, &border);
-
-  border_width = gtk_container_get_border_width (container);
-  area->x = border_width;
-  area->y = border_width;
-  area->width = allocation.width - (2 * border_width);
-
-  if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
-    {
-      GtkAllocation label_widget_allocation;
-
-      gtk_widget_get_allocation (priv->label_widget, &label_widget_allocation);
-      area->height = label_widget_allocation.height;
-    }
-  else
-    area->height = 0;
-
-  area->height = MAX (area->height, expander_size + 2 * expander_spacing);
-  area->height += border.top + border.bottom;
+  GTK_WIDGET_CLASS (gtk_expander_parent_class)->destroy (widget);
 }
 
 static void
@@ -640,18 +648,16 @@ gtk_expander_realize (GtkWidget *widget)
   GdkWindow *window;
   GdkWindowAttr attributes;
   gint attributes_mask;
-  GdkRectangle area;
 
   priv = GTK_EXPANDER (widget)->priv;
 
   gtk_widget_get_allocation (widget, &allocation);
-  get_prelight_area_bounds (GTK_EXPANDER (widget), &area);
 
   attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x = allocation.x + area.x;
-  attributes.y = allocation.y + area.y;
-  attributes.width = area.width;
-  attributes.height = area.height;
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
   attributes.wclass = GDK_INPUT_ONLY;
   attributes.event_mask = gtk_widget_get_events (widget)
                           | GDK_BUTTON_PRESS_MASK
@@ -700,7 +706,6 @@ get_expander_bounds (GtkExpander  *expander,
   gint expander_size;
   gint expander_spacing;
   gboolean ltr;
-  GtkBorder border;
 
   widget = GTK_WIDGET (expander);
   priv = expander->priv;
@@ -713,18 +718,17 @@ get_expander_bounds (GtkExpander  *expander,
                         "expander-size", &expander_size,
                         "expander-spacing", &expander_spacing,
                         NULL);
-  get_padding_and_border (widget, &border);
 
   ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
 
-  rect->x = allocation.x + border_width + border.left;
-  rect->y = allocation.y + border_width + border.top;
+  rect->x = border_width;
+  rect->y = border_width;
 
   if (ltr)
     rect->x += expander_spacing;
   else
-    rect->x += allocation.width - 2 * border_width -
-               expander_spacing - expander_size - border.right;
+    rect->x += allocation.width - border_width - 
+               expander_spacing - expander_size;
 
   if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
     {
@@ -749,53 +753,121 @@ static void
 gtk_expander_size_allocate (GtkWidget     *widget,
                             GtkAllocation *allocation)
 {
+  GtkAllocation clip;
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  gtk_css_gadget_allocate (GTK_EXPANDER (widget)->priv->gadget,
+                           allocation,
+                           gtk_widget_get_allocated_baseline (widget),
+                           &clip);
+
+  gtk_widget_set_clip (widget, &clip);
+}
+
+static void
+gtk_expander_allocate (GtkCssGadget        *gadget,
+                       const GtkAllocation *allocation,
+                       gint                 baseline,
+                       GtkAllocation       *out_clip,
+                       gpointer             data)
+{
+  GtkWidget *widget;
   GtkExpander *expander;
   GtkWidget *child;
   GtkExpanderPrivate *priv;
-  gboolean child_visible = FALSE;
-  guint border_width;
-  gint expander_size;
+  GtkAllocation title_allocation;
+  GtkAllocation title_clip;
+  gint title_height_min, title_height_nat;
+
+  widget = gtk_css_gadget_get_owner (gadget);
+  expander = GTK_EXPANDER (widget);
+  priv = expander->priv;
+  child = gtk_bin_get_child (GTK_BIN (widget));
+
+  gtk_css_gadget_get_preferred_size (priv->title_gadget,
+                                     GTK_ORIENTATION_VERTICAL,
+                                     allocation->width,
+                                     &title_height_min, &title_height_nat,
+                                     NULL, NULL);
+
+  title_allocation.x = allocation->x;
+  title_allocation.y = allocation->y;
+  title_allocation.width = allocation->width;
+  title_allocation.height = CLAMP (title_height_nat, title_height_min, allocation->height);
+
+  gtk_css_gadget_allocate (priv->title_gadget, &title_allocation, baseline, &title_clip);
+
+  if (gtk_widget_get_realized (widget))
+    gdk_window_move_resize (priv->event_window,
+                            title_allocation.x, title_allocation.y,
+                            title_allocation.width, title_allocation.height);
+
+  if (child && gtk_widget_get_child_visible (child))
+    {
+      GtkAllocation child_allocation;
+
+      child_allocation.x = allocation->x;
+      child_allocation.y = allocation->y + title_allocation.height + priv->spacing;
+      child_allocation.width = allocation->width;
+      child_allocation.height = allocation->height - title_allocation.height - priv->spacing;
+
+      gtk_widget_size_allocate (child, &child_allocation);
+    }
+
+  gtk_container_get_children_clip (GTK_CONTAINER (expander), out_clip);
+  gdk_rectangle_union (out_clip, &title_clip, out_clip);
+}
+
+static void
+gtk_expander_allocate_title (GtkCssGadget        *gadget,
+                             const GtkAllocation *allocation,
+                             gint                 baseline,
+                             GtkAllocation       *out_clip,
+                             gpointer             data)
+{
+  GtkWidget *widget;
+  GtkExpander *expander;
+  GtkExpanderPrivate *priv;
+  gint arrow_width, arrow_height;
   gint expander_spacing;
   gint label_height;
-  gint label_xpad, label_xoffset;
-  gint child_ypad, child_yoffset;
-  GtkBorder border;
+  gint label_xoffset;
+  GtkAllocation arrow_allocation;
+  GtkAllocation clip;
 
+  widget = gtk_css_gadget_get_owner (gadget);
   expander = GTK_EXPANDER (widget);
-  child    = gtk_bin_get_child (GTK_BIN (widget));
-  priv     = expander->priv;
-
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+  priv = expander->priv;
 
-  gtk_widget_set_allocation (widget, allocation);
+  gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                     GTK_ORIENTATION_HORIZONTAL,
+                                     -1,
+                                     NULL, &arrow_width,
+                                     NULL, NULL);
+  gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                     GTK_ORIENTATION_VERTICAL,
+                                     -1,
+                                     NULL, &arrow_height,
+                                     NULL, NULL);
 
   gtk_widget_style_get (widget,
-                        "expander-size", &expander_size,
                         "expander-spacing", &expander_spacing,
                         NULL);
-  get_padding_and_border (widget, &border);
-
-  /* Calculate some offsets/padding first */
-  label_xoffset = border_width + expander_size + 2 * expander_spacing + border.left;
-  label_xpad = 2 * border_width + expander_size + 2 * expander_spacing + border.left + border.right;
-
-  child_yoffset  = border_width + priv->spacing + border.top + border.bottom;
-  child_ypad     = 2 * border_width + priv->spacing + border.top + border.bottom;
-
-  child_visible = (child && gtk_widget_get_child_visible (child));
 
+  label_xoffset = arrow_width + 2 * expander_spacing;
   if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
     {
       GtkAllocation label_allocation;
-      gint          natural_label_width;
-      gboolean ltr;
+      gint label_width;
 
-      gtk_widget_get_preferred_width (priv->label_widget, NULL, &natural_label_width);
+      gtk_widget_get_preferred_width (priv->label_widget, NULL, &label_width);
 
       if (priv->label_fill)
-        label_allocation.width = allocation->width - label_xpad;
+        label_allocation.width = allocation->width - label_xoffset;
       else
-        label_allocation.width = MIN (natural_label_width, allocation->width - label_xpad);
+        label_allocation.width = MIN (label_width, allocation->width - label_xoffset);
+
       label_allocation.width = MAX (label_allocation.width, 1);
 
       /* We distribute the minimum height to the label widget and prioritize
@@ -804,22 +876,13 @@ gtk_expander_size_allocate (GtkWidget     *widget,
       gtk_widget_get_preferred_height_for_width (priv->label_widget,
                                                  label_allocation.width, &label_height, NULL);
 
-      ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-      if (priv->label_fill)
-        label_allocation.x = allocation->x + label_xoffset;
-      else if (ltr)
-        label_allocation.x = allocation->x + label_xoffset;
+      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+        label_allocation.x = allocation->x + allocation->width - label_xoffset - label_width;
       else
-        label_allocation.x = allocation->x + allocation->width -
-                             (label_allocation.width + label_xoffset);
+        label_allocation.x = allocation->x + label_xoffset;
 
-      label_allocation.y = allocation->y + border_width + border.top;
-      label_allocation.height = MIN (label_height,
-                                     allocation->height - 2 * border_width -
-                                     border.top - border.bottom -
-                                     (child_visible ? priv->spacing : 0));
-      label_allocation.height = MAX (label_allocation.height, 1);
+      label_allocation.y = allocation->y;
+      label_allocation.height = label_height;
 
       gtk_widget_size_allocate (priv->label_widget, &label_allocation);
 
@@ -830,33 +893,21 @@ gtk_expander_size_allocate (GtkWidget     *widget,
       label_height = 0;
     }
 
-  if (gtk_widget_get_realized (widget))
-    {
-      GdkRectangle rect;
-
-      get_prelight_area_bounds (expander, &rect);
-      gdk_window_move_resize (priv->event_window,
-                              allocation->x + rect.x,
-                              allocation->y + rect.y,
-                              rect.width, rect.height);
-    }
-
-  if (child_visible)
-    {
-      GtkAllocation child_allocation;
-      gint top_height;
-
-      top_height = MAX (2 * expander_spacing + expander_size, label_height);
-
-      child_allocation.x = allocation->x + border_width;
-      child_allocation.y = allocation->y + top_height + child_yoffset;
-
-      child_allocation.width = MAX (allocation->width - 2 * border_width, 1);
-      child_allocation.height = allocation->height - top_height - child_ypad;
-      child_allocation.height = MAX (child_allocation.height, 1);
-
-      gtk_widget_size_allocate (child, &child_allocation);
-    }
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+    arrow_allocation.x = allocation->x + allocation->width - expander_spacing - arrow_width;
+  else
+    arrow_allocation.x = allocation->x + expander_spacing;
+  arrow_allocation.y = allocation->y;
+  arrow_allocation.width = arrow_width;
+  arrow_allocation.height = arrow_height;
+
+  gtk_css_gadget_allocate (priv->arrow_gadget,
+                           &arrow_allocation,
+                           gtk_widget_get_allocated_baseline (widget),
+                           &clip);
+
+  gtk_container_get_children_clip (GTK_CONTAINER (expander), out_clip);
+  gdk_rectangle_union (out_clip, &clip, out_clip);
 }
 
 static void
@@ -887,42 +938,44 @@ gtk_expander_unmap (GtkWidget *widget)
     gtk_widget_unmap (priv->label_widget);
 }
 
-static void
-gtk_expander_paint (GtkExpander *expander,
-                    cairo_t     *cr)
+static gboolean
+gtk_expander_draw_arrow (GtkCssGadget *gadget,
+                         cairo_t      *cr,
+                         gint          x,
+                         gint          y,
+                         gint          width,
+                         gint          height,
+                         gpointer      data)
 {
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  GtkExpander *expander = GTK_EXPANDER (widget);
   GtkExpanderPrivate *priv = expander->priv;
-  GtkWidget *widget;
-  GdkRectangle clip;
-  GdkRectangle area;
-  GtkAllocation allocation;
   GtkStyleContext *context;
-  gint size;
 
-  widget = GTK_WIDGET (expander);
   context = gtk_widget_get_style_context (widget);
+  gtk_style_context_save_to_node (context, gtk_css_gadget_get_node (priv->arrow_gadget));
+  gtk_render_expander (context, cr, x, y, width, height);
+  gtk_style_context_restore (context);
 
-  get_expander_bounds (expander, &clip);
-  gtk_widget_get_allocation (widget, &allocation);
-
-  gtk_widget_style_get (widget, "expander-size", &size, NULL);
-
-  gtk_style_context_save_to_node (context, priv->arrow_node);
+  return FALSE;
+}
 
-  if (expander->priv->prelight)
-    {
-      get_prelight_area_bounds (expander, &area);
-      gtk_render_background (context, cr,
-                             area.x, area.y,
-                             area.width, area.height);
-    }
+static gboolean
+gtk_expander_draw_title (GtkCssGadget *gadget,
+                         cairo_t      *cr,
+                         gint          x,
+                         gint          y,
+                         gint          width,
+                         gint          height,
+                         gpointer      data)
+{
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  GtkExpander *expander = GTK_EXPANDER (widget);
+  GtkExpanderPrivate *priv = expander->priv;
 
-  gtk_render_expander (context, cr,
-                       clip.x - allocation.x,
-                       clip.y - allocation.y,
-                       size, size);
+  gtk_css_gadget_draw (priv->arrow_gadget, cr);
 
-  gtk_style_context_restore (context);
+  return FALSE;
 }
 
 static void
@@ -939,7 +992,6 @@ gtk_expander_paint_focus (GtkExpander *expander,
   gint expander_spacing;
   gboolean ltr;
   GtkAllocation allocation;
-  GtkBorder border;
 
   widget = GTK_WIDGET (expander);
   priv = expander->priv;
@@ -951,7 +1003,6 @@ gtk_expander_paint_focus (GtkExpander *expander,
                         "expander-size", &expander_size,
                         "expander-spacing", &expander_spacing,
                         NULL);
-  get_padding_and_border (widget, &border);
 
   ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
 
@@ -968,8 +1019,8 @@ gtk_expander_paint_focus (GtkExpander *expander,
           height = label_allocation.height;
         }
 
-      x = border_width + border.left;
-      y = border_width + border.top;
+      x = border_width;
+      y = border_width;
 
       if (ltr)
         {
@@ -985,30 +1036,44 @@ gtk_expander_paint_focus (GtkExpander *expander,
     {
       get_expander_bounds (expander, &rect);
 
-      x = rect.x - allocation.x;
-      y = rect.y - allocation.y;
+      x = rect.x;
+      y = rect.y;
       width = rect.width;
       height = rect.height;
     }
 
   context = gtk_widget_get_style_context (widget);
-  gtk_render_focus (context, cr,
-                    x, y, width, height);
+  gtk_render_focus (context, cr, x, y, width, height);
 }
 
 static gboolean
 gtk_expander_draw (GtkWidget *widget,
                    cairo_t   *cr)
 {
+  gtk_css_gadget_draw (GTK_EXPANDER (widget)->priv->gadget, cr);
+
+  return FALSE;
+}
+
+static gboolean
+gtk_expander_draw_contents (GtkCssGadget *gadget,
+                            cairo_t      *cr,
+                            gint          x,
+                            gint          y,
+                            gint          width,
+                            gint          height,
+                            gpointer      data)
+{
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
   GtkExpander *expander = GTK_EXPANDER (widget);
 
-  gtk_expander_paint (expander, cr);
+  gtk_css_gadget_draw (expander->priv->title_gadget, cr);
+
+  GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
 
   if (gtk_widget_has_visible_focus (widget))
     gtk_expander_paint_focus (expander, cr);
 
-  GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
-
   return FALSE;
 }
 
@@ -1037,7 +1102,7 @@ gtk_expander_redraw_expander (GtkExpander *expander)
 }
 
 static void
-update_arrow_state (GtkExpander *expander)
+update_node_state (GtkExpander *expander)
 {
   GtkExpanderPrivate *priv = expander->priv;
   GtkStateFlags state;
@@ -1049,12 +1114,51 @@ update_arrow_state (GtkExpander *expander)
   else
     state &= ~GTK_STATE_FLAG_PRELIGHT;
 
+  gtk_css_node_set_state (gtk_css_gadget_get_node (priv->title_gadget), state);
+
   if (priv->expanded)
     state |= GTK_STATE_FLAG_CHECKED;
   else
     state &= ~GTK_STATE_FLAG_CHECKED;
 
-  gtk_css_node_set_state (priv->arrow_node, state);
+  gtk_css_node_set_state (gtk_css_gadget_get_node (priv->arrow_gadget), state);
+}
+
+static void
+update_node_ordering (GtkExpander *expander)
+{
+  GtkExpanderPrivate *priv = expander->priv;
+  GtkCssNode *arrow_node, *label_node, *title_node;
+
+  if (!priv->label_widget)
+    return;
+
+  title_node = gtk_css_gadget_get_node (priv->title_gadget);
+  arrow_node = gtk_css_gadget_get_node (priv->arrow_gadget);
+  label_node = gtk_widget_get_css_node (priv->label_widget);
+
+  if (gtk_widget_get_direction (GTK_WIDGET (expander)) == GTK_TEXT_DIR_RTL)
+    gtk_css_node_insert_before (title_node, label_node, arrow_node);
+  else
+    gtk_css_node_insert_after (title_node, label_node, arrow_node);
+}
+
+static void
+gtk_expander_state_flags_changed (GtkWidget     *widget,
+                                  GtkStateFlags  previous_state)
+{
+  update_node_state (GTK_EXPANDER (widget));
+
+  GTK_WIDGET_CLASS (gtk_expander_parent_class)->state_flags_changed (widget, previous_state);
+}
+
+static void
+gtk_expander_direction_changed (GtkWidget        *widget,
+                                GtkTextDirection  previous_direction)
+{
+  update_node_ordering (GTK_EXPANDER (widget));
+
+  GTK_WIDGET_CLASS (gtk_expander_parent_class)->direction_changed (widget, previous_direction);
 }
 
 static gboolean
@@ -1068,7 +1172,7 @@ gtk_expander_enter_notify (GtkWidget        *widget,
     {
       expander->priv->prelight = TRUE;
 
-      update_arrow_state (expander);
+      update_node_state (expander);
 
       if (expander->priv->label_widget)
         gtk_widget_set_state_flags (expander->priv->label_widget,
@@ -1092,7 +1196,7 @@ gtk_expander_leave_notify (GtkWidget        *widget,
     {
       expander->priv->prelight = FALSE;
 
-      update_arrow_state (expander);
+      update_node_state (expander);
 
       if (expander->priv->label_widget)
         gtk_widget_unset_state_flags (expander->priv->label_widget,
@@ -1396,60 +1500,16 @@ gtk_expander_activate (GtkExpander *expander)
   gtk_expander_set_expanded (expander, !expander->priv->expanded);
 }
 
-
 static void
 gtk_expander_get_preferred_width (GtkWidget *widget,
                                   gint      *minimum_size,
                                   gint      *natural_size)
 {
-  GtkExpander *expander;
-  GtkWidget *child;
-  GtkExpanderPrivate *priv;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  GtkBorder border;
-
-  child = gtk_bin_get_child (GTK_BIN (widget));
-  expander = GTK_EXPANDER (widget);
-  priv = expander->priv;
-
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-
-  gtk_widget_style_get (GTK_WIDGET (widget),
-                        "expander-size", &expander_size,
-                        "expander-spacing", &expander_spacing,
-                        NULL);
-  get_padding_and_border (widget, &border);
-
-  *minimum_size = *natural_size =
-    expander_size + 2 * expander_spacing;
-
-  if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
-    {
-      gint label_min, label_nat;
-
-      gtk_widget_get_preferred_width (priv->label_widget,
-                                      &label_min, &label_nat);
-
-      *minimum_size += label_min;
-      *natural_size += label_nat;
-    }
-
-  if (child && gtk_widget_get_child_visible (child))
-    {
-      gint child_min, child_nat;
-
-      gtk_widget_get_preferred_width (child,
-                                      &child_min, &child_nat);
-
-      *minimum_size = MAX (*minimum_size, child_min);
-      *natural_size = MAX (*natural_size, child_nat);
-
-    }
-
-  *minimum_size += 2 * border_width + border.left + border.right;
-  *natural_size += 2 * border_width + border.left + border.right;
+  gtk_css_gadget_get_preferred_size (GTK_EXPANDER (widget)->priv->gadget,
+                                     GTK_ORIENTATION_HORIZONTAL,
+                                     -1,
+                                     minimum_size, natural_size,
+                                     NULL, NULL);
 }
 
 static void
@@ -1457,130 +1517,209 @@ gtk_expander_get_preferred_height (GtkWidget *widget,
                                    gint      *minimum_size,
                                    gint      *natural_size)
 {
+  gtk_css_gadget_get_preferred_size (GTK_EXPANDER (widget)->priv->gadget,
+                                     GTK_ORIENTATION_VERTICAL,
+                                     -1,
+                                     minimum_size, natural_size,
+                                     NULL, NULL);
+}
+
+static void
+gtk_expander_get_preferred_width_for_height (GtkWidget *widget,
+                                             gint       height,
+                                             gint      *minimum_size,
+                                             gint      *natural_size)
+{
+  gtk_css_gadget_get_preferred_size (GTK_EXPANDER (widget)->priv->gadget,
+                                     GTK_ORIENTATION_HORIZONTAL,
+                                     height,
+                                     minimum_size, natural_size,
+                                     NULL, NULL);
+}
+
+static void
+gtk_expander_get_preferred_height_for_width (GtkWidget *widget,
+                                             gint       width,
+                                             gint      *minimum_size,
+                                             gint      *natural_size)
+{
+  gtk_css_gadget_get_preferred_size (GTK_EXPANDER (widget)->priv->gadget,
+                                     GTK_ORIENTATION_VERTICAL,
+                                     width,
+                                     minimum_size, natural_size,
+                                     NULL, NULL);
+}
+
+static void
+gtk_expander_get_content_size (GtkCssGadget   *gadget,
+                               GtkOrientation  orientation,
+                               gint            for_size,
+                               gint           *minimum,
+                               gint           *natural,
+                               gint           *minimum_baseline,
+                               gint           *natural_baseline,
+                               gpointer        data)
+{
+  GtkWidget *widget;
   GtkExpander *expander;
-  GtkWidget *child;
   GtkExpanderPrivate *priv;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  GtkBorder border;
+  GtkWidget *child;
 
-  child = gtk_bin_get_child (GTK_BIN (widget));
+  widget = gtk_css_gadget_get_owner (gadget);
   expander = GTK_EXPANDER (widget);
   priv = expander->priv;
+  child = gtk_bin_get_child (GTK_BIN (widget));
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-
-  gtk_widget_style_get (GTK_WIDGET (widget),
-                        "expander-size", &expander_size,
-                        "expander-spacing", &expander_spacing,
-                        NULL);
-  get_padding_and_border (widget, &border);
-
-  *minimum_size = *natural_size = 0;
-
-  if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
     {
-      gint label_min, label_nat;
+      gint title_height;
+      gtk_css_gadget_get_preferred_size (priv->title_gadget,
+                                         GTK_ORIENTATION_VERTICAL,
+                                         -1,
+                                         &title_height, NULL,
+                                         NULL, NULL);
+      gtk_css_gadget_get_preferred_size (priv->title_gadget,
+                                         GTK_ORIENTATION_HORIZONTAL,
+                                         title_height,
+                                         minimum, natural,
+                                         NULL, NULL);
+
+      if (child && gtk_widget_get_child_visible (child))
+        {
+          gint child_min, child_nat;
 
-      gtk_widget_get_preferred_height (priv->label_widget,
-                                       &label_min, &label_nat);
+          if (for_size > -1)
+            gtk_widget_get_preferred_width_for_height (child, MAX (for_size - priv->spacing - title_height, 
0), &child_min, &child_nat);
+          else
+            gtk_widget_get_preferred_width (child, &child_min, &child_nat);
 
-      *minimum_size += label_min;
-      *natural_size += label_nat;
+          *minimum = MAX (*minimum, child_min);
+          *natural = MAX (*natural, child_nat);
+        }
     }
-
-  *minimum_size = MAX (*minimum_size, expander_size + 2 * expander_spacing);
-  *natural_size = MAX (*natural_size, *minimum_size);
-
-  if (child && gtk_widget_get_child_visible (child))
+  else
     {
-      gint child_min, child_nat;
+      gtk_css_gadget_get_preferred_size (priv->title_gadget,
+                                         GTK_ORIENTATION_VERTICAL,
+                                         for_size,
+                                         minimum, natural,
+                                         NULL, NULL);
 
-      gtk_widget_get_preferred_height (child,
-                                       &child_min, &child_nat);
+      if (child && gtk_widget_get_child_visible (child))
+        {
+          gint child_min, child_nat;
 
-      *minimum_size += child_min + priv->spacing;
-      *natural_size += child_nat + priv->spacing;
+          if (for_size > 0)
+            gtk_widget_get_preferred_height_for_width (child,
+                                                       for_size,
+                                                       &child_min, &child_nat);
+          else
+            gtk_widget_get_preferred_height (child, &child_min, &child_nat);
 
+          *minimum += child_min + priv->spacing;
+          *natural += child_nat + priv->spacing;
+        }
     }
-
-  *minimum_size += 2 * border_width + border.top + border.bottom;
-  *natural_size += 2 * border_width + border.top + border.bottom;
 }
 
+
 static void
-gtk_expander_get_preferred_height_for_width (GtkWidget *widget,
-                                             gint       width,
-                                             gint      *minimum_height,
-                                             gint      *natural_height)
+gtk_expander_get_title_size (GtkCssGadget   *gadget,
+                             GtkOrientation  orientation,
+                             gint            for_size,
+                             gint           *minimum,
+                             gint           *natural,
+                             gint           *minimum_baseline,
+                             gint           *natural_baseline,
+                             gpointer        data)
 {
+  GtkWidget *widget;
   GtkExpander *expander;
-  GtkWidget *child;
   GtkExpanderPrivate *priv;
-  gint border_width;
-  gint expander_size;
+  gint arrow_width, arrow_height;
   gint expander_spacing;
-  gint label_xpad;
-  GtkBorder border;
 
-  child = gtk_bin_get_child (GTK_BIN (widget));
+  widget = gtk_css_gadget_get_owner (gadget);
   expander = GTK_EXPANDER (widget);
   priv = expander->priv;
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+  gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                     GTK_ORIENTATION_HORIZONTAL,
+                                     -1,
+                                     NULL, &arrow_width,
+                                     NULL, NULL);
+  gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                     GTK_ORIENTATION_VERTICAL,
+                                     -1,
+                                     NULL, &arrow_height,
+                                     NULL, NULL);
 
   gtk_widget_style_get (GTK_WIDGET (widget),
-                        "expander-size", &expander_size,
                         "expander-spacing", &expander_spacing,
                         NULL);
-  get_padding_and_border (widget, &border);
 
-  label_xpad = 2 * border_width + expander_size + 2 * expander_spacing;
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      *minimum = *natural = arrow_width + 2 * expander_spacing;
 
-  *minimum_height = *natural_height = 0;
+      if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
+        {
+          gint label_min, label_nat;
 
-  if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
+          gtk_widget_get_preferred_width (priv->label_widget, &label_min, &label_nat);
+
+          *minimum += label_min;
+          *natural += label_nat;
+        }
+    }
+  else
     {
-      gint label_min, label_nat;
+      gint label_xpad;
 
-      gtk_widget_get_preferred_height_for_width (priv->label_widget,
-                                                 MAX (width - label_xpad, 1),
-                                                 &label_min, &label_nat);
+      label_xpad = arrow_width + 2 * expander_spacing;
 
-      *minimum_height += label_min;
-      *natural_height += label_nat;
-    }
+      *minimum = *natural = 0;
 
-  *minimum_height = MAX (*minimum_height, expander_size + 2 * expander_spacing);
-  *natural_height = MAX (*natural_height, *minimum_height);
+      if (priv->label_widget && gtk_widget_get_visible (priv->label_widget))
+        {
+          gint label_min, label_nat;
 
-  if (child && gtk_widget_get_child_visible (child))
-    {
-      gint child_min, child_nat;
+          if (for_size > 0)
+            gtk_widget_get_preferred_height_for_width (priv->label_widget,
+                                                       MAX (for_size - label_xpad, 1),
+                                                       &label_min, &label_nat);
+          else
+            gtk_widget_get_preferred_height (priv->label_widget,
+                                             &label_min, &label_nat);
 
-      gtk_widget_get_preferred_height_for_width (child,
-                                                 MAX (width - 2 * border_width, 1),
-                                                 &child_min, &child_nat);
+          *minimum += label_min;
+          *natural += label_nat;
+        }
 
-      *minimum_height += child_min + priv->spacing;
-      *natural_height += child_nat + priv->spacing;
+      *minimum = MAX (*minimum, arrow_height + 2 * expander_spacing);
+      *natural = MAX (*natural, *minimum);
     }
-
-  *minimum_height += 2 * border_width + border.top + border.bottom;
-  *natural_height += 2 * border_width + border.top + border.bottom;
 }
 
 static void
-gtk_expander_get_preferred_width_for_height (GtkWidget *widget,
-                                             gint       height,
-                                             gint      *minimum_width,
-                                             gint      *natural_width)
+gtk_expander_get_arrow_size (GtkCssGadget   *gadget,
+                             GtkOrientation  orientation,
+                             gint            for_size,
+                             gint           *minimum,
+                             gint           *natural,
+                             gint           *minimum_baseline,
+                             gint           *natural_baseline,
+                             gpointer        data)
 {
-  GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
-}
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  gint expander_size;
 
+  gtk_widget_style_get (GTK_WIDGET (widget),
+                        "expander-size", &expander_size,
+                        NULL);
 
+  *minimum = *natural = expander_size;
+}
 
 /**
  * gtk_expander_new:
@@ -1652,7 +1791,7 @@ gtk_expander_set_expanded (GtkExpander *expander,
 
   priv->expanded = expanded;
 
-  update_arrow_state (expander);
+  update_node_state (expander);
 
   child = gtk_bin_get_child (GTK_BIN (expander));
 
@@ -1949,7 +2088,9 @@ gtk_expander_set_label_widget (GtkExpander *expander,
   if (label_widget)
     {
       priv->label_widget = label_widget;
-
+      gtk_css_node_set_parent (gtk_widget_get_css_node (label_widget),
+                               gtk_css_gadget_get_node (priv->title_gadget));
+      update_node_ordering (expander);
       gtk_widget_set_parent (label_widget, widget);
 
       if (priv->prelight)



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