[gtk+/wip/matthiasc/gadget: 2/34] Use gadgets for GtkProgressBar



commit 5dfb31360598b16ef7bd5427939e90c5e937d8ac
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Nov 24 07:22:52 2015 -0500

    Use gadgets for GtkProgressBar
    
    Use gadgets for the trough and the progress. The text is still
    rendered manually.

 gtk/gtkprogressbar.c |  953 ++++++++++++++++++++++++++++----------------------
 1 files changed, 532 insertions(+), 421 deletions(-)
---
diff --git a/gtk/gtkprogressbar.c b/gtk/gtkprogressbar.c
index 0a845a0..fdeaeb8 100644
--- a/gtk/gtkprogressbar.c
+++ b/gtk/gtkprogressbar.c
@@ -25,6 +25,7 @@
 #include "config.h"
 
 #include <string.h>
+#include <math.h>
 
 #include "gtkprogressbar.h"
 #include "gtkorientableprivate.h"
@@ -35,6 +36,8 @@
 #include "gtkstylecontextprivate.h"
 #include "gtkcssnodeprivate.h"
 #include "gtkcssstylepropertyprivate.h"
+#include "gtkcsscustomgadgetprivate.h"
+#include "gtkcssnumbervalueprivate.h"
 
 #include "a11y/gtkprogressbaraccessible.h"
 
@@ -71,14 +74,15 @@
  * |[<!-- language="plain" -->
  * progressbar
  * ╰── trough
+ *     ├── [text]
  *     ╰── progress[.pulse]
  * ]|
  *
- * GtkProgressBar has a main CSS node with name progressbar and subnodes
- * with names trough and progress. The progress subnode has the style class
- * .pulse when in activity mode. It gets the style classes .left, .right,
- * .top or .bottom added when the progress 'touches' the corresponding end
- * of the GtkProgressBar.
+ * GtkProgressBar has a main CSS node with name progressbar and subnodes with
+ * names text, trough and progress. The text subnode is only present if text
+ * is shown. The progress subnode has the style class .pulse when in activity
+ * mode. It gets the style classes .left, .right, .top or .bottom added when
+ * the progress 'touches' the corresponding end of the GtkProgressBar.
  */
 
 #define MIN_HORIZONTAL_BAR_WIDTH   150
@@ -91,8 +95,10 @@ struct _GtkProgressBarPrivate
 {
   gchar         *text;
 
-  GtkCssNode    *trough_node;
-  GtkCssNode    *progress_node;
+  GtkCssGadget  *gadget;
+  GtkCssGadget  *text_gadget;
+  GtkCssGadget  *trough;
+  GtkCssGadget  *progress;
 
   gdouble        fraction;
   gdouble        pulse_fraction;
@@ -154,6 +160,64 @@ static void     gtk_progress_bar_set_orientation  (GtkProgressBar *progress,
                                                    GtkOrientation  orientation);
 static void     gtk_progress_bar_direction_changed (GtkWidget        *widget,
                                                     GtkTextDirection  previous_dir);
+static void     gtk_progress_bar_state_flags_changed (GtkWidget      *widget,
+                                                      GtkStateFlags   previous_state);
+
+static void     gtk_progress_bar_get_content_size  (GtkCssGadget        *gadget,
+                                                    GtkOrientation       orientation,
+                                                    gint                 for_size,
+                                                    gint                *minimum,
+                                                    gint                *natural,
+                                                    gint                *minimum_baseline,
+                                                    gint                *natural_baseline,
+                                                    gpointer             data);
+static void     gtk_progress_bar_allocate_contents (GtkCssGadget        *gadget,
+                                                    const GtkAllocation *allocation,
+                                                    gint                 baseline,
+                                                    GtkAllocation       *out_clip,
+                                                    gpointer             data);
+static gboolean gtk_progress_bar_render_contents   (GtkCssGadget        *gadget,
+                                                    cairo_t             *cr,
+                                                    gint                 x,
+                                                    gint                 y,
+                                                    gint                 width,
+                                                    gint                 height,
+                                                    gpointer             data);
+static void     gtk_progress_bar_allocate_trough   (GtkCssGadget        *gadget,
+                                                    const GtkAllocation *allocation,
+                                                    gint                 baseline,
+                                                    GtkAllocation       *out_clip,
+                                                    gpointer             data);
+static void     gtk_progress_bar_get_trough_size   (GtkCssGadget        *gadget,
+                                                    GtkOrientation       orientation,
+                                                    gint                 for_size,
+                                                    gint                *minimum,
+                                                    gint                *natural,
+                                                    gint                *minimum_baseline,
+                                                    gint                *natural_baseline,
+                                                    gpointer             data);
+static gboolean gtk_progress_bar_render_trough     (GtkCssGadget        *gadget,
+                                                    cairo_t             *cr,
+                                                    gint                 x,
+                                                    gint                 y,
+                                                    gint                 width,
+                                                    gint                 height,
+                                                    gpointer             data);
+static void     gtk_progress_bar_get_text_size     (GtkCssGadget        *gadget,
+                                                    GtkOrientation       orientation,
+                                                    gint                 for_size,
+                                                    gint                *minimum,
+                                                    gint                *natural,
+                                                    gint                *minimum_baseline,
+                                                    gint                *natural_baseline,
+                                                    gpointer             data);
+static gboolean gtk_progress_bar_render_text       (GtkCssGadget        *gadget,
+                                                    cairo_t             *cr,
+                                                    gint                 x,
+                                                    gint                 y,
+                                                    gint                 width,
+                                                    gint                 height,
+                                                    gpointer             data);
 
 G_DEFINE_TYPE_WITH_CODE (GtkProgressBar, gtk_progress_bar, GTK_TYPE_WIDGET,
                          G_ADD_PRIVATE (GtkProgressBar)
@@ -177,6 +241,7 @@ gtk_progress_bar_class_init (GtkProgressBarClass *class)
   widget_class->get_preferred_width = gtk_progress_bar_get_preferred_width;
   widget_class->get_preferred_height = gtk_progress_bar_get_preferred_height;
   widget_class->direction_changed = gtk_progress_bar_direction_changed;
+  widget_class->state_flags_changed = gtk_progress_bar_state_flags_changed;
 
   g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");
 
@@ -293,69 +358,66 @@ gtk_progress_bar_class_init (GtkProgressBarClass *class)
    * The minimum horizontal width of the progress bar.
    *
    * Since: 2.14
+   *
+   * Deprecated: 3.20: Use the standard CSS property min-width.
    */
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_int ("min-horizontal-bar-width",
                                                              P_("Minimum horizontal bar width"),
                                                              P_("The minimum horizontal width of the 
progress bar"),
                                                              1, G_MAXINT, MIN_HORIZONTAL_BAR_WIDTH,
-                                                             G_PARAM_READWRITE));
+                                                             G_PARAM_READWRITE|G_PARAM_DEPRECATED));
   /**
    * GtkProgressBar:min-horizontal-bar-height:
    *
    * Minimum horizontal height of the progress bar.
    *
    * Since: 2.14
+   *
+   * Deprecated: 3.20: Use the standard CSS property min-height.
    */
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_int ("min-horizontal-bar-height",
                                                              P_("Minimum horizontal bar height"),
                                                              P_("Minimum horizontal height of the progress 
bar"),
                                                              1, G_MAXINT, MIN_HORIZONTAL_BAR_HEIGHT,
-                                                             G_PARAM_READWRITE));
+                                                             G_PARAM_READWRITE|G_PARAM_DEPRECATED));
   /**
    * GtkProgressBar:min-vertical-bar-width:
    *
    * The minimum vertical width of the progress bar.
    *
    * Since: 2.14
+   *
+   * Deprecated: 3.20: Use the standard CSS proeprty min-width.
    */
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_int ("min-vertical-bar-width",
                                                              P_("Minimum vertical bar width"),
                                                              P_("The minimum vertical width of the progress 
bar"),
                                                              1, G_MAXINT, MIN_VERTICAL_BAR_WIDTH,
-                                                             G_PARAM_READWRITE));
+                                                             G_PARAM_READWRITE|G_PARAM_DEPRECATED));
   /**
    * GtkProgressBar:min-vertical-bar-height:
    *
    * The minimum vertical height of the progress bar.
    *
    * Since: 2.14
+   *
+   * Deprecated: 3.20: Use the standard CSS property min-height.
    */
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_int ("min-vertical-bar-height",
                                                              P_("Minimum vertical bar height"),
                                                              P_("The minimum vertical height of the progress 
bar"),
                                                              1, G_MAXINT, MIN_VERTICAL_BAR_HEIGHT,
-                                                             G_PARAM_READWRITE));
+                                                             G_PARAM_READWRITE|G_PARAM_DEPRECATED));
 
   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_PROGRESS_BAR_ACCESSIBLE);
   gtk_widget_class_set_css_name (widget_class, "progressbar");
 }
 
 static void
-node_style_changed_cb (GtkCssNode        *node,
-                       GtkCssStyleChange *change,
-                       GtkWidget         *widget)
-{
-  if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE | GTK_CSS_AFFECTS_CLIP))
-    gtk_widget_queue_resize (widget);
-  else
-    gtk_widget_queue_draw (widget);
-}
-
-static void
 update_node_classes (GtkProgressBar *pbar)
 {
   GtkProgressBarPrivate *priv = pbar->priv;
@@ -405,24 +467,37 @@ update_node_classes (GtkProgressBar *pbar)
     }
 
   if (left)
-    gtk_css_node_add_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_LEFT));
+    gtk_css_gadget_add_class (priv->progress, GTK_STYLE_CLASS_LEFT);
   else
-    gtk_css_node_remove_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_LEFT));
+    gtk_css_gadget_remove_class (priv->progress, GTK_STYLE_CLASS_LEFT);
 
   if (right)
-    gtk_css_node_add_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_RIGHT));
+    gtk_css_gadget_add_class (priv->progress, GTK_STYLE_CLASS_RIGHT);
   else
-    gtk_css_node_remove_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_RIGHT));
+    gtk_css_gadget_remove_class (priv->progress, GTK_STYLE_CLASS_RIGHT);
 
   if (top)
-    gtk_css_node_add_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_TOP));
+    gtk_css_gadget_add_class (priv->progress, GTK_STYLE_CLASS_TOP);
   else
-    gtk_css_node_remove_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_TOP));
+    gtk_css_gadget_remove_class (priv->progress, GTK_STYLE_CLASS_TOP);
 
   if (bottom)
-    gtk_css_node_add_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_BOTTOM));
+    gtk_css_gadget_add_class (priv->progress, GTK_STYLE_CLASS_BOTTOM);
   else
-    gtk_css_node_remove_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_BOTTOM));
+    gtk_css_gadget_remove_class (priv->progress, GTK_STYLE_CLASS_BOTTOM);
+}
+
+static void
+update_node_state (GtkProgressBar *pbar)
+{
+  GtkProgressBarPrivate *priv = pbar->priv;
+  GtkStateFlags state;
+
+  state = gtk_widget_get_state_flags (GTK_WIDGET (pbar));
+
+  gtk_css_node_set_state (gtk_css_gadget_get_node (priv->gadget), state);
+  gtk_css_node_set_state (gtk_css_gadget_get_node (priv->trough), state);
+  gtk_css_node_set_state (gtk_css_gadget_get_node (priv->progress), state);
 }
 
 static void
@@ -451,20 +526,35 @@ gtk_progress_bar_init (GtkProgressBar *pbar)
   _gtk_orientable_set_style_classes (GTK_ORIENTABLE (pbar));
 
   widget_node = gtk_widget_get_css_node (GTK_WIDGET (pbar));
-
-  priv->trough_node = gtk_css_node_new ();
-  gtk_css_node_set_name (priv->trough_node, I_("trough"));
-  gtk_css_node_set_parent (priv->trough_node, widget_node);
-  gtk_css_node_set_state (priv->trough_node, gtk_css_node_get_state (widget_node));
-  g_signal_connect_object (priv->trough_node, "style-changed", G_CALLBACK (node_style_changed_cb), pbar, 0);
-  g_object_unref (priv->trough_node);
-
-  priv->progress_node = gtk_css_node_new ();
-  gtk_css_node_set_name (priv->progress_node, I_("progress"));
-  gtk_css_node_set_parent (priv->progress_node, priv->trough_node);
-  gtk_css_node_set_state (priv->progress_node, gtk_css_node_get_state (widget_node));
-  g_signal_connect_object (priv->progress_node, "style-changed", G_CALLBACK (node_style_changed_cb), pbar, 
0);
-  g_object_unref (priv->progress_node);
+  priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
+                                                     GTK_WIDGET (pbar),
+                                                     gtk_progress_bar_get_content_size,
+                                                     gtk_progress_bar_allocate_contents,
+                                                     gtk_progress_bar_render_contents,
+                                                     NULL,
+                                                     NULL);
+
+  priv->trough = gtk_css_custom_gadget_new ("trough",
+                                            GTK_WIDGET (pbar),
+                                            priv->gadget,
+                                            NULL,
+                                            gtk_progress_bar_get_trough_size,
+                                            gtk_progress_bar_allocate_trough,
+                                            gtk_progress_bar_render_trough,
+                                            NULL,
+                                            NULL);
+  gtk_css_node_set_state (gtk_css_gadget_get_node (priv->trough), gtk_css_node_get_state (widget_node));
+
+  priv->progress = gtk_css_custom_gadget_new ("progress",
+                                              GTK_WIDGET (pbar),
+                                              priv->trough,
+                                              NULL,
+                                              gtk_progress_bar_get_trough_size,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              NULL);
+  gtk_css_node_set_state (gtk_css_gadget_get_node (priv->progress), gtk_css_node_get_state (widget_node));
 
   update_node_classes (pbar);
 }
@@ -574,6 +664,11 @@ gtk_progress_bar_finalize (GObject *object)
 
   g_free (priv->text);
 
+  g_clear_object (&priv->text_gadget);
+  g_clear_object (&priv->progress);
+  g_clear_object (&priv->trough);
+  g_clear_object (&priv->gadget);
+
   G_OBJECT_CLASS (gtk_progress_bar_parent_class)->finalize (object);
 }
 
@@ -589,46 +684,88 @@ get_current_text (GtkProgressBar *pbar)
 }
 
 static void
-gtk_progress_bar_size_allocate (GtkWidget     *widget,
-                                GtkAllocation *allocation)
+gtk_progress_bar_get_content_size (GtkCssGadget   *gadget,
+                                   GtkOrientation  orientation,
+                                   gint            for_size,
+                                   gint           *minimum,
+                                   gint           *natural,
+                                   gint           *minimum_baseline,
+                                   gint           *natural_baseline,
+                                   gpointer        data)
 {
-  GTK_WIDGET_CLASS (gtk_progress_bar_parent_class)->size_allocate (widget, allocation);
+  GtkWidget *widget;
+  GtkProgressBar *pbar;
+  GtkProgressBarPrivate *priv;
+  gint text_minimum, text_natural;
+  gint trough_minimum, trough_natural;
+
+  widget = gtk_css_gadget_get_owner (gadget);
+  pbar = GTK_PROGRESS_BAR (widget);
+  priv = pbar->priv;
+
+  if (priv->show_text)
+    gtk_css_gadget_get_preferred_size (priv->text_gadget, orientation, -1, &text_minimum, &text_natural, 
NULL, NULL);
+  else
+    text_minimum = text_natural = 0;
+
+  gtk_css_gadget_get_preferred_size (priv->trough, orientation, -1, &trough_minimum, &trough_natural, NULL, 
NULL);
 
-  _gtk_widget_set_simple_clip (widget, NULL);
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          *minimum = MAX (text_minimum, trough_minimum);
+          *natural = MAX (text_natural, trough_natural);
+        }
+      else
+        {
+          *minimum = text_minimum + trough_minimum;
+          *natural = text_natural + trough_natural;
+        }
+    }
+  else
+    {
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          *minimum = text_minimum + trough_minimum;
+          *natural = text_natural + trough_natural;
+        }
+      else
+        {
+          *minimum = MAX (text_minimum, trough_minimum);
+          *natural = MAX (text_natural, trough_natural);
+        }
+    }
 }
 
 static void
-gtk_progress_bar_get_preferred_width (GtkWidget *widget,
-                                      gint      *minimum,
-                                      gint      *natural)
+gtk_progress_bar_get_text_size (GtkCssGadget   *gadget,
+                                GtkOrientation  orientation,
+                                gint            for_size,
+                                gint           *minimum,
+                                gint           *natural,
+                                gint           *minimum_baseline,
+                                gint           *natural_baseline,
+                                gpointer        data)
 {
+  GtkWidget *widget;
   GtkProgressBar *pbar;
   GtkProgressBarPrivate *priv;
-  GtkStyleContext *context;
-  GtkBorder padding;
   gchar *buf;
-  PangoRectangle logical_rect;
   PangoLayout *layout;
-  gint width;
-  gint bar_width;
-
-  g_return_if_fail (GTK_IS_PROGRESS_BAR (widget));
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
+  PangoRectangle logical_rect;
 
+  widget = gtk_css_gadget_get_owner (gadget);
   pbar = GTK_PROGRESS_BAR (widget);
   priv = pbar->priv;
 
-  width = padding.left + padding.right;
-
-  if (priv->show_text)
-    {
-      buf = get_current_text (pbar);
-      layout = gtk_widget_create_pango_layout (widget, buf);
+  buf = get_current_text (pbar);
+  layout = gtk_widget_create_pango_layout (widget, buf);
 
-      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+  pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
       if (priv->ellipsize)
         {
           PangoContext *context;
@@ -644,75 +781,266 @@ gtk_progress_bar_get_preferred_width (GtkWidget *widget,
           char_width = pango_font_metrics_get_approximate_char_width (metrics);
           pango_font_metrics_unref (metrics);
 
-          width += PANGO_PIXELS (char_width) * 3;
+          *minimum = PANGO_PIXELS (char_width) * 3;
         }
       else
-        width += logical_rect.width;
+        *minimum = logical_rect.width;
 
-      g_object_unref (layout);
-      g_free (buf);
+      *natural = logical_rect.width;
     }
-
-  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-    gtk_widget_style_get (widget,
-                          "min-horizontal-bar-width", &bar_width,
-                          NULL);
   else
-    gtk_widget_style_get (widget,
-                          "min-vertical-bar-width", &bar_width,
-                          NULL);
+    *minimum = *natural = logical_rect.height;
+
+  g_object_unref (layout);
+  g_free (buf);
+}
+
+static gint
+get_number (GtkCssStyle *style,
+            guint        property)
+{
+  double d = _gtk_css_number_value_get (gtk_css_style_get_value (style, property), 100.0);
 
-  *minimum = *natural = width + bar_width;
+  if (d < 1)
+    return ceil (d);
+  else
+    return floor (d);
 }
 
 static void
-gtk_progress_bar_get_preferred_height (GtkWidget *widget,
-                                       gint      *minimum,
-                                       gint      *natural)
+gtk_progress_bar_get_trough_size (GtkCssGadget   *gadget,
+                                  GtkOrientation  orientation,
+                                  gint            for_size,
+                                  gint           *minimum,
+                                  gint           *natural,
+                                  gint           *minimum_baseline,
+                                  gint           *natural_baseline,
+                                  gpointer        data)
 {
+  GtkWidget *widget;
   GtkProgressBar *pbar;
   GtkProgressBarPrivate *priv;
-  GtkStyleContext *context;
-  GtkBorder padding;
-  gchar *buf;
-  PangoRectangle logical_rect;
-  PangoLayout *layout;
-  gint height;
-  gint bar_height;
-
-  g_return_if_fail (GTK_IS_PROGRESS_BAR (widget));
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
+  GtkCssStyle *style;
 
+  widget = gtk_css_gadget_get_owner (gadget);
   pbar = GTK_PROGRESS_BAR (widget);
   priv = pbar->priv;
 
-  height = padding.top + padding.bottom;
+  style = gtk_css_gadget_get_style (gadget);
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      gint min_width;
 
-  if (priv->show_text)
+      min_width = get_number (style, GTK_CSS_PROPERTY_MIN_WIDTH);
+
+      if (min_width != 0)
+        *minimum = min_width;
+      else if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        gtk_widget_style_get (widget, "min-horizontal-bar-width", minimum, NULL);
+      else
+        gtk_widget_style_get (widget, "min-vertical-bar-width", minimum, NULL);
+    }
+  else
     {
-      buf = get_current_text (pbar);
-      layout = gtk_widget_create_pango_layout (widget, buf);
+      gint min_height;
+
+      min_height = get_number (style, GTK_CSS_PROPERTY_MIN_HEIGHT);
+
+      if (min_height != 0)
+        *minimum = min_height;
+      else if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        gtk_widget_style_get (widget, "min-horizontal-bar-height", minimum, NULL);
+      else
+        gtk_widget_style_get (widget, "min-vertical-bar-height", minimum, NULL);
+    }
+
+  *natural = *minimum;
+
+  if (minimum_baseline)
+    *minimum_baseline = -1;
+  if (natural_baseline)
+    *natural_baseline = -1;
+}
+
+static void
+gtk_progress_bar_size_allocate (GtkWidget     *widget,
+                                GtkAllocation *allocation)
+{
+  GtkAllocation clip;
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  gtk_css_gadget_allocate (GTK_PROGRESS_BAR (widget)->priv->gadget,
+                           allocation,
+                           gtk_widget_get_allocated_baseline (widget),
+                           &clip);
 
-      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+  gtk_widget_set_clip (widget, &clip);
+}
+
+static void
+gtk_progress_bar_allocate_contents (GtkCssGadget        *gadget,
+                                    const GtkAllocation *allocation,
+                                    gint                 baseline,
+                                    GtkAllocation       *out_clip,
+                                    gpointer             data)
+{
+  GtkWidget *widget;
+  GtkProgressBarPrivate *priv;
+  gint bar_width, bar_height;
+  gint text_width, text_height, text_min, text_nat;
+  GtkAllocation alloc;
+  GtkAllocation text_clip;
 
-      height += logical_rect.height;
+  widget = gtk_css_gadget_get_owner (gadget);
+  priv = GTK_PROGRESS_BAR (widget)->priv;
 
-      g_object_unref (layout);
-      g_free (buf);
+  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      gtk_css_gadget_get_preferred_size (priv->trough, GTK_ORIENTATION_VERTICAL, -1, &bar_height, NULL, 
NULL, NULL);
+      bar_width = allocation->width;
+    }
+  else
+    {
+      gtk_css_gadget_get_preferred_size (priv->trough, GTK_ORIENTATION_HORIZONTAL, -1, &bar_width, NULL, 
NULL, NULL);
+      bar_height = allocation->height;
     }
 
+  alloc.x = allocation->x + allocation->width - bar_width;
+  alloc.y = allocation->y + allocation->height - bar_height;
+  alloc.width = bar_width;
+  alloc.height = bar_height;
+
+  gtk_css_gadget_allocate (priv->trough, &alloc, -1, out_clip);
+
+  if (!priv->show_text)
+    return;
+
+  gtk_css_gadget_get_preferred_size (priv->text_gadget, GTK_ORIENTATION_HORIZONTAL, -1, &text_min, 
&text_nat, NULL, NULL);
+  gtk_css_gadget_get_preferred_size (priv->text_gadget, GTK_ORIENTATION_VERTICAL, -1, &text_height, NULL, 
NULL, NULL);
+
+  text_width = CLAMP(text_nat, text_min, allocation->width);
+
   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-    gtk_widget_style_get (widget,
-                          "min-horizontal-bar-height", &bar_height,
-                          NULL);
+    {
+      alloc.x = allocation->x + (allocation->width - text_width) / 2;
+      alloc.y = allocation->y;
+      alloc.width = text_width;
+      alloc.height = text_height;
+    }
   else
-    gtk_widget_style_get (widget,
-                          "min-vertical-bar-height", &bar_height,
-                          NULL);
+    {
+      alloc.x = allocation->x + allocation->width - text_width;
+      alloc.y = allocation->y + (allocation->height - text_height) / 2;
+      alloc.width = text_width;
+      alloc.height = text_height;
+    }
+
+  gtk_css_gadget_allocate (priv->text_gadget, &alloc, -1, &text_clip);
 
-  *minimum = *natural = height + bar_height;
+  gdk_rectangle_union (out_clip, &text_clip, out_clip);
+}
+
+
+static void
+gtk_progress_bar_allocate_trough (GtkCssGadget        *gadget,
+                                  const GtkAllocation *allocation,
+                                  gint                 baseline,
+                                  GtkAllocation       *out_clip,
+                                  gpointer             data)
+{
+  GtkWidget *widget;
+  GtkProgressBarPrivate *priv;
+  GtkAllocation alloc;
+  gint width, height;
+  gboolean inverted;
+
+  widget = gtk_css_gadget_get_owner (gadget);
+  priv = GTK_PROGRESS_BAR (widget)->priv;
+
+  inverted = priv->inverted;
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+    {
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        inverted = !inverted;
+    }
+
+  if (priv->activity_mode)
+    {
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          gtk_css_gadget_get_preferred_size (priv->progress, GTK_ORIENTATION_VERTICAL, -1, &height, NULL, 
NULL, NULL);
+
+          alloc.width = MAX (2, allocation->width / priv->activity_blocks);
+          alloc.x = allocation->x + priv->activity_pos * (allocation->width - alloc.width);
+          alloc.y = allocation->y + (allocation->height - height) / 2;
+          alloc.height = height;
+        }
+      else
+        {
+          gtk_css_gadget_get_preferred_size (priv->progress, GTK_ORIENTATION_HORIZONTAL, -1, &width, NULL, 
NULL, NULL);
+
+          alloc.height = MAX (2, allocation->height / priv->activity_blocks);
+          alloc.y = allocation->y + priv->activity_pos * (allocation->height - alloc.height);
+          alloc.x = allocation->x + (allocation->width - width) / 2;
+          alloc.width = width;
+        }
+    }
+  else
+    {
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          gtk_css_gadget_get_preferred_size (priv->progress, GTK_ORIENTATION_VERTICAL, -1, &height, NULL, 
NULL, NULL);
+
+          alloc.width = allocation->width * priv->fraction;
+          alloc.height = height;
+          alloc.y = allocation->y + (allocation->height - height) / 2;
+
+          if (!inverted)
+            alloc.x = allocation->x;
+          else
+            alloc.x = allocation->x + allocation->width - alloc.width;
+        }
+      else
+        {
+          gtk_css_gadget_get_preferred_size (priv->progress, GTK_ORIENTATION_HORIZONTAL, -1, &width, NULL, 
NULL, NULL);
+
+          alloc.width = width;
+          alloc.height = allocation->height * priv->fraction;
+          alloc.x = allocation->x + (allocation->width - width) / 2;
+
+          if (!inverted)
+            alloc.y = allocation->y;
+          else
+            alloc.y = allocation->y + allocation->height - alloc.height;
+        }
+    }
+
+  gtk_css_gadget_allocate (priv->progress, &alloc, -1, out_clip);
+}
+
+static void
+gtk_progress_bar_get_preferred_width (GtkWidget *widget,
+                                      gint      *minimum,
+                                      gint      *natural)
+{
+  gtk_css_gadget_get_preferred_size (GTK_PROGRESS_BAR (widget)->priv->gadget,
+                                     GTK_ORIENTATION_HORIZONTAL,
+                                     -1,
+                                     minimum, natural,
+                                     NULL, NULL);
+}
+
+static void
+gtk_progress_bar_get_preferred_height (GtkWidget *widget,
+                                       gint      *minimum,
+                                       gint      *natural)
+{
+  gtk_css_gadget_get_preferred_size (GTK_PROGRESS_BAR (widget)->priv->gadget,
+                                     GTK_ORIENTATION_VERTICAL,
+                                     -1,
+                                     minimum, natural,
+                                     NULL, NULL);
 }
 
 static gboolean
@@ -770,7 +1098,7 @@ tick_cb (GtkWidget     *widget,
 
   update_node_classes (pbar);
 
-  gtk_widget_queue_draw (widget);
+  gtk_widget_queue_allocate (widget);
 
   return G_SOURCE_CONTINUE;
 }
@@ -783,7 +1111,7 @@ gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar)
   GtkOrientation orientation;
   gboolean inverted;
 
-  gtk_css_node_add_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_PULSE));
+  gtk_css_gadget_add_class (priv->progress, GTK_STYLE_CLASS_PULSE);
 
   orientation = priv->orientation;
   inverted = priv->inverted;
@@ -838,261 +1166,91 @@ gtk_progress_bar_act_mode_leave (GtkProgressBar *pbar)
     gtk_widget_remove_tick_callback (GTK_WIDGET (pbar), priv->tick_id);
   priv->tick_id = 0;
 
-  gtk_css_node_remove_class (priv->progress_node, g_quark_from_static_string (GTK_STYLE_CLASS_PULSE));
+  gtk_css_gadget_remove_class (priv->progress, GTK_STYLE_CLASS_PULSE);
   update_node_classes (pbar);
 }
 
-static void
-gtk_progress_bar_get_activity (GtkProgressBar *pbar,
-                               GtkOrientation  orientation,
-                               gint           *offset,
-                               gint           *amount)
-{
-  GtkProgressBarPrivate *priv = pbar->priv;
-  GtkWidget *widget = GTK_WIDGET (pbar);
-  GtkStyleContext *context;
-  GtkAllocation allocation;
-  GtkStateFlags state;
-  GtkBorder padding;
-  int size;
-
-  context = gtk_widget_get_style_context (widget);
-  state = gtk_style_context_get_state (context);
-  gtk_widget_get_allocation (widget, &allocation);
-  gtk_style_context_get_padding (context, state, &padding);
-
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    size = allocation.width - padding.left - padding.top;
-  else
-    size = allocation.height - padding.left - padding.top;
-
-  *amount = MAX (2, size / priv->activity_blocks);
-  *offset = priv->activity_pos * (size - *amount);
-}
-
-static void
-gtk_progress_bar_paint_activity (GtkProgressBar *pbar,
-                                 cairo_t        *cr,
-                                 GtkOrientation  orientation,
-                                 gboolean        inverted,
-                                 int             x,
-                                 int             y,
-                                 int             width,
-                                 int             height)
-{
-  GtkProgressBarPrivate *priv = pbar->priv;
-  GtkStyleContext *context;
-  GtkBorder padding;
-  GtkWidget *widget = GTK_WIDGET (pbar);
-  GdkRectangle area;
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-
-  gtk_style_context_save_to_node (context, priv->progress_node);
-
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    {
-      gtk_progress_bar_get_activity (pbar, orientation, &area.x, &area.width);
-      area.y = y + padding.top;
-      area.height = height - padding.top - padding.bottom;
-    }
-  else
-    {
-      gtk_progress_bar_get_activity (pbar, orientation, &area.y, &area.height);
-      area.x = x + padding.left;
-      area.width = width - padding.left - padding.right;
-    }
-
-  gtk_render_background (context, cr, area.x, area.y, area.width, area.height);
-  gtk_render_frame (context, cr, area.x, area.y, area.width, area.height);
-
-  gtk_style_context_restore (context);
-}
-
-static void
-gtk_progress_bar_paint_continuous (GtkProgressBar *pbar,
-                                   cairo_t        *cr,
-                                   gint            amount,
-                                   GtkOrientation  orientation,
-                                   gboolean        inverted,
-                                   int             x,
-                                   int             y,
-                                   int             width,
-                                   int             height)
-{
-  GtkProgressBarPrivate *priv = pbar->priv;
-  GtkStyleContext *context;
-  GtkBorder padding;
-  GtkWidget *widget = GTK_WIDGET (pbar);
-  GdkRectangle area;
-
-  if (amount <= 0)
-    return;
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-
-  gtk_style_context_save_to_node (context, priv->progress_node);
-
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    {
-      area.width = amount;
-      area.height = height - padding.top - padding.bottom;
-      area.y = y + padding.top;
-
-      if (!inverted)
-        area.x = x + padding.left;
-      else
-        area.x = width - amount - padding.right;
-    }
-  else
-    {
-      area.width = width - padding.left - padding.right;
-      area.height = amount;
-      area.x = x + padding.left;
-
-      if (!inverted)
-        area.y = y + padding.top;
-      else
-        area.y = height - amount - padding.bottom;
-    }
-
-  gtk_render_background (context, cr, area.x, area.y, area.width, area.height);
-  gtk_render_frame (context, cr, area.x, area.y, area.width, area.height);
-
-  gtk_style_context_restore (context);
-}
-
-static void
-gtk_progress_bar_paint_text (GtkProgressBar *pbar,
-                             cairo_t        *cr,
-                             gint            offset,
-                             gint            amount,
-                             GtkOrientation  orientation,
-                             gboolean        inverted,
-                             int             width,
-                             int             height)
+static gboolean
+gtk_progress_bar_render_text (GtkCssGadget *gadget,
+                              cairo_t      *cr,
+                              gint          x,
+                              gint          y,
+                              gint          width,
+                              gint          height,
+                              gpointer      data)
 {
-  GtkProgressBarPrivate *priv = pbar->priv;
+  GtkWidget *widget;
+  GtkProgressBar *pbar;
+  GtkProgressBarPrivate *priv;
   GtkStyleContext *context;
-  GtkBorder padding;
-  GtkWidget *widget = GTK_WIDGET (pbar);
-  gint x;
-  gint y;
   gchar *buf;
-  GdkRectangle rect;
   PangoLayout *layout;
-  PangoRectangle logical_rect;
-  GdkRectangle prelight_clip, start_clip, end_clip;
+
+  widget = gtk_css_gadget_get_owner (gadget);
+  pbar = GTK_PROGRESS_BAR (widget);
+  priv = pbar->priv;
 
   context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
+  gtk_style_context_save_to_node (context, gtk_css_gadget_get_node (gadget));
 
   buf = get_current_text (pbar);
-
   layout = gtk_widget_create_pango_layout (widget, buf);
   pango_layout_set_ellipsize (layout, priv->ellipsize);
   if (priv->ellipsize)
     pango_layout_set_width (layout, width * PANGO_SCALE);
 
-  pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    {
-      x = padding.left + (width - padding.left - padding.right - 2 - logical_rect.width) / 2;
-      y = padding.top + 1;
-    }
-  else
-    {
-      x = padding.left + 1;
-      y = padding.top + 1 + (height - padding.top - padding.bottom - 2 - logical_rect.height) / 2;
-    }
+  gtk_render_layout (context, cr, x, y, layout);
 
-  rect.x = padding.left;
-  rect.y = padding.top;
-  rect.width = width - padding.left - padding.right;
-  rect.height = height - padding.top - padding.bottom;
+  g_object_unref (layout);
+  g_free (buf);
 
-  prelight_clip = start_clip = end_clip = rect;
+  gtk_style_context_restore (context);
 
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    {
-      if (!inverted)
-        {
-          if (offset != -1)
-            prelight_clip.x = offset;
-          prelight_clip.width = amount;
-          start_clip.width = prelight_clip.x - start_clip.x;
-          end_clip.x = start_clip.x + start_clip.width + prelight_clip.width;
-          end_clip.width -= prelight_clip.width + start_clip.width;
-        }
-      else
-        {
-          if (offset != -1)
-            prelight_clip.x = offset;
-          else
-            prelight_clip.x = rect.x + rect.width - amount;
-          prelight_clip.width = amount;
-          start_clip.width = prelight_clip.x - start_clip.x;
-          end_clip.x = start_clip.x + start_clip.width + prelight_clip.width;
-          end_clip.width -= prelight_clip.width + start_clip.width;
-        }
-    }
-  else
-    {
-      if (!inverted)
-        {
-          if (offset != -1)
-            prelight_clip.y = offset;
-          prelight_clip.height = amount;
-          start_clip.height = prelight_clip.y - start_clip.y;
-          end_clip.y = start_clip.y + start_clip.height + prelight_clip.height;
-          end_clip.height -= prelight_clip.height + start_clip.height;
-        }
-      else
-        {
-          if (offset != -1)
-            prelight_clip.y = offset;
-          else
-            prelight_clip.y = rect.y + rect.height - amount;
-          prelight_clip.height = amount;
-          start_clip.height = prelight_clip.y - start_clip.y;
-          end_clip.y = start_clip.y + start_clip.height + prelight_clip.height;
-          end_clip.height -= prelight_clip.height + start_clip.height;
-        }
-    }
+  return FALSE;
+}
 
-  if (start_clip.width > 0 && start_clip.height > 0)
-    {
-      cairo_save (cr);
-      gdk_cairo_rectangle (cr, &start_clip);
-      cairo_clip (cr);
+static gboolean
+gtk_progress_bar_render_trough (GtkCssGadget *gadget,
+                                cairo_t      *cr,
+                                gint          x,
+                                gint          y,
+                                gint          width,
+                                gint          height,
+                                gpointer      data)
+{
+  GtkWidget *widget;
+  GtkProgressBarPrivate *priv;
 
-      gtk_render_layout (context, cr, x, y, layout);
-      cairo_restore (cr);
-    }
+  widget = gtk_css_gadget_get_owner (gadget);
+  priv = GTK_PROGRESS_BAR (widget)->priv;
 
-  if (end_clip.width > 0 && end_clip.height > 0)
-    {
-      cairo_save (cr);
-      gdk_cairo_rectangle (cr, &end_clip);
-      cairo_clip (cr);
+  gtk_css_gadget_draw (priv->progress, cr);
 
-      gtk_render_layout (context, cr, x, y, layout);
-      cairo_restore (cr);
-    }
+  return FALSE;
+}
 
-  cairo_save (cr);
-  gdk_cairo_rectangle (cr, &prelight_clip);
-  cairo_clip (cr);
+static gboolean
+gtk_progress_bar_render_contents (GtkCssGadget *gadget,
+                                  cairo_t      *cr,
+                                  gint          x,
+                                  gint          y,
+                                  gint          width,
+                                  gint          height,
+                                  gpointer      data)
+{
+  GtkWidget *widget;
+  GtkProgressBar *pbar;
+  GtkProgressBarPrivate *priv;
 
-  gtk_render_layout (context, cr, x, y, layout);
+  widget = gtk_css_gadget_get_owner (gadget);
+  pbar = GTK_PROGRESS_BAR (widget);
+  priv = pbar->priv;
 
-  cairo_restore (cr);
+  gtk_css_gadget_draw (priv->trough, cr);
+  if (priv->show_text)
+    gtk_css_gadget_draw (priv->text_gadget, cr);
 
-  g_object_unref (layout);
-  g_free (buf);
+  return FALSE;
 }
 
 static gboolean
@@ -1101,82 +1259,8 @@ gtk_progress_bar_draw (GtkWidget *widget,
 {
   GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget);
   GtkProgressBarPrivate *priv = pbar->priv;
-  GtkOrientation orientation;
-  gboolean inverted;
-  GtkStyleContext *context;
-  GtkBorder padding;
-  int width, height;
-  int bar_width, bar_height;
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-
-  orientation = priv->orientation;
-  inverted = priv->inverted;
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
-    {
-      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-        inverted = !inverted;
-    }
-  width = gtk_widget_get_allocated_width (widget);
-  height = gtk_widget_get_allocated_height (widget);
-
-  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-    {
-      gtk_widget_style_get (widget, "min-horizontal-bar-height", &bar_height, NULL);
-      bar_width = width;
-    }
-  else
-    {
-      gtk_widget_style_get (widget, "min-vertical-bar-width", &bar_width, NULL);
-      bar_height = height;
-    }
-
-  gtk_style_context_save_to_node (context, priv->trough_node);
-
-  gtk_render_background (context, cr, width - bar_width, height - bar_height, bar_width, bar_height);
-  gtk_render_frame (context, cr, width - bar_width, height - bar_height, bar_width, bar_height);
-
-  gtk_style_context_restore (context);
-
-  if (priv->activity_mode)
-    {
-      gtk_progress_bar_paint_activity (pbar, cr,
-                                       orientation, inverted,
-                                       width - bar_width, height - bar_height,
-                                       bar_width, bar_height);
-
-      if (priv->show_text)
-        {
-          gint offset;
-          gint amount;
-
-          gtk_progress_bar_get_activity (pbar, orientation, &offset, &amount);
-          gtk_progress_bar_paint_text (pbar, cr,
-                                       offset, amount,
-                                       orientation, inverted,
-                                       width, height);
-        }
-    }
-  else
-    {
-      gint amount;
-      gint space;
-
-      if (orientation == GTK_ORIENTATION_HORIZONTAL)
-        space = bar_width - padding.left - padding.right;
-      else
-        space = bar_height - padding.top - padding.bottom;
-
-      amount = space * gtk_progress_bar_get_fraction (pbar);
-
-      gtk_progress_bar_paint_continuous (pbar, cr, amount, orientation, inverted,
-                                         width - bar_width, height - bar_height,
-                                         bar_width, bar_height);
 
-      if (priv->show_text)
-        gtk_progress_bar_paint_text (pbar, cr, -1, amount, orientation, inverted, width, height);
-    }
+  gtk_css_gadget_draw (priv->gadget, cr);
 
   return FALSE;
 }
@@ -1322,14 +1406,31 @@ gtk_progress_bar_set_show_text (GtkProgressBar *pbar,
 
   show_text = !!show_text;
 
-  if (priv->show_text != show_text)
-    {
-      priv->show_text = show_text;
+  if (priv->show_text == show_text)
+    return;
 
-      gtk_widget_queue_resize (GTK_WIDGET (pbar));
+  priv->show_text = show_text;
 
-      g_object_notify_by_pspec (G_OBJECT (pbar), progress_props[PROP_SHOW_TEXT]);
+  if (show_text)
+    {
+      priv->text_gadget = gtk_css_custom_gadget_new ("text",
+                                                     GTK_WIDGET (pbar),
+                                                     priv->gadget,
+                                                     priv->trough,
+                                                     gtk_progress_bar_get_text_size,
+                                                     NULL,
+                                                     gtk_progress_bar_render_text,
+                                                     NULL,
+                                                     NULL);
     }
+  else
+    {
+      g_clear_object (&priv->text_gadget);
+    }
+
+  gtk_widget_queue_resize (GTK_WIDGET (pbar));
+
+  g_object_notify_by_pspec (G_OBJECT (pbar), progress_props[PROP_SHOW_TEXT]);
 }
 
 /**
@@ -1381,11 +1482,21 @@ gtk_progress_bar_direction_changed (GtkWidget        *widget,
   GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget);
 
   update_node_classes (pbar);
+  update_node_state (pbar);
 
   GTK_WIDGET_CLASS (gtk_progress_bar_parent_class)->direction_changed (widget, previous_dir);
 }
 
 static void
+gtk_progress_bar_state_flags_changed (GtkWidget     *widget,
+                                      GtkStateFlags  previous_state)
+{
+  GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget);
+
+  update_node_state (pbar);
+}
+
+static void
 gtk_progress_bar_set_orientation (GtkProgressBar *pbar,
                                   GtkOrientation  orientation)
 {



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