]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkscale.c
Simplify GTK_STATE_FLAG_FOCUSED handling in state propagation.
[~andy/gtk] / gtk / gtkscale.c
index 6babe29f8b40c004d05d317e0098d5b11be0ea30..a69ae8403624cd23b0b2345da1f35f3c3d03045b 100644 (file)
 #include <math.h>
 #include <stdlib.h>
 
-#include "gdk/gdkkeysyms.h"
 #include "gtkscale.h"
 #include "gtkiconfactory.h"
 #include "gtkicontheme.h"
 #include "gtkmarshalers.h"
 #include "gtkbindings.h"
 #include "gtkorientable.h"
+#include "gtktypebuiltins.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
 #include "gtkbuildable.h"
 
 /**
  * SECTION:gtkscale
- * @Short_description: Base class for #GtkHScale and #GtkVScale
+ * @Short_description: Base class for GtkHScale and GtkVScale
  * @Title: GtkScale
  *
- * A #GtkScale is a slider control used to select a numeric value.
+ * A GtkScale is a slider control used to select a numeric value.
  * To use it, you'll probably want to investigate the methods on
- * its base class, #GtkRange, in addition to the methods for #GtkScale itself.
+ * its base class, #GtkRange, in addition to the methods for GtkScale itself.
  * To set the value of a scale, you would normally use gtk_range_set_value().
  * To detect changes to the value, you would normally use the
- * #GtkRange::value_changed signal.
+ * #GtkRange::value-changed signal.
+ *
+ * Note that using the same upper and lower bounds for the #GtkScale (through
+ * the #GtkRange methods) will hide the slider itself. This is useful for
+ * applications that want to show an undeterminate value on the scale, without
+ * changing the layout of the application (such as movie or music players).
  *
  * <refsect2 id="GtkScale-BUILDER-UI"><title>GtkScale as GtkBuildable</title>
  * GtkScale supports a custom &lt;marks&gt; element, which
@@ -116,10 +121,13 @@ static void     gtk_scale_get_property            (GObject        *object,
                                                    guint           prop_id,
                                                    GValue         *value,
                                                    GParamSpec     *pspec);
-static void     gtk_scale_size_request            (GtkWidget      *widget,
-                                                   GtkRequisition *requisition);
-static void     gtk_scale_style_set               (GtkWidget      *widget,
-                                                   GtkStyle       *previous);
+static void     gtk_scale_get_preferred_width     (GtkWidget      *widget,
+                                                   gint           *minimum,
+                                                   gint           *natural);
+static void     gtk_scale_get_preferred_height    (GtkWidget      *widget,
+                                                   gint           *minimum,
+                                                   gint           *natural);
+static void     gtk_scale_style_updated           (GtkWidget      *widget);
 static void     gtk_scale_get_range_border        (GtkRange       *range,
                                                    GtkBorder      *border);
 static void     gtk_scale_get_mark_label_size     (GtkScale        *scale,
@@ -133,8 +141,8 @@ static void     gtk_scale_get_mark_label_size     (GtkScale        *scale,
 static void     gtk_scale_finalize                (GObject        *object);
 static void     gtk_scale_screen_changed          (GtkWidget      *widget,
                                                    GdkScreen      *old_screen);
-static gboolean gtk_scale_expose                  (GtkWidget      *widget,
-                                                   GdkEventExpose *event);
+static gboolean gtk_scale_draw                    (GtkWidget      *widget,
+                                                   cairo_t        *cr);
 static void     gtk_scale_real_get_layout_offsets (GtkScale       *scale,
                                                    gint           *x,
                                                    gint           *y);
@@ -195,10 +203,11 @@ gtk_scale_class_init (GtkScaleClass *class)
   gobject_class->get_property = gtk_scale_get_property;
   gobject_class->finalize = gtk_scale_finalize;
 
-  widget_class->style_set = gtk_scale_style_set;
+  widget_class->style_updated = gtk_scale_style_updated;
   widget_class->screen_changed = gtk_scale_screen_changed;
-  widget_class->expose_event = gtk_scale_expose;
-  widget_class->size_request = gtk_scale_size_request;
+  widget_class->draw = gtk_scale_draw;
+  widget_class->get_preferred_width = gtk_scale_get_preferred_width;
+  widget_class->get_preferred_height = gtk_scale_get_preferred_height;
 
   range_class->slider_detail = "Xscale";
   range_class->get_range_border = gtk_scale_get_range_border;
@@ -420,6 +429,7 @@ gtk_scale_init (GtkScale *scale)
 {
   GtkScalePrivate *priv;
   GtkRange *range = GTK_RANGE (scale);
+  GtkStyleContext *context;
 
   scale->priv = G_TYPE_INSTANCE_GET_PRIVATE (scale,
                                              GTK_TYPE_SCALE,
@@ -433,12 +443,15 @@ gtk_scale_init (GtkScale *scale)
   priv->draw_value = TRUE;
   priv->value_pos = GTK_POS_TOP;
   priv->digits = 1;
-  _gtk_range_set_round_digits (range, priv->digits);
+  gtk_range_set_round_digits (range, priv->digits);
 
   gtk_scale_orientation_notify (range, NULL);
   g_signal_connect (scale, "notify::orientation",
                     G_CALLBACK (gtk_scale_orientation_notify),
                     NULL);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (scale));
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_SCALE);
 }
 
 static void
@@ -497,8 +510,8 @@ gtk_scale_get_property (GObject      *object,
 /**
  * gtk_scale_new:
  * @orientation: the scale's orientation.
- * @adjustment: the #GtkAdjustment which sets the range of the scale, or
- *              %NULL to create a new adjustment.
+ * @adjustment: (allow-none): the #GtkAdjustment which sets the range
+ *              of the scale, or %NULL to create a new adjustment.
  *
  * Creates a new #GtkScale.
  *
@@ -546,7 +559,7 @@ gtk_scale_new_with_range (GtkOrientation orientation,
                           gdouble        max,
                           gdouble        step)
 {
-  GtkObject *adj;
+  GtkAdjustment *adj;
   gint digits;
 
   g_return_val_if_fail (min < max, NULL);
@@ -600,7 +613,7 @@ gtk_scale_set_digits (GtkScale *scale,
     {
       priv->digits = digits;
       if (priv->draw_value)
-        _gtk_range_set_round_digits (range, digits);
+        gtk_range_set_round_digits (range, digits);
 
       _gtk_scale_clear_layout (scale);
       gtk_widget_queue_resize (GTK_WIDGET (scale));
@@ -649,9 +662,9 @@ gtk_scale_set_draw_value (GtkScale *scale,
     {
       priv->draw_value = draw_value;
       if (draw_value)
-        _gtk_range_set_round_digits (GTK_RANGE (scale), priv->digits);
+        gtk_range_set_round_digits (GTK_RANGE (scale), priv->digits);
       else
-        _gtk_range_set_round_digits (GTK_RANGE (scale), -1);
+        gtk_range_set_round_digits (GTK_RANGE (scale), -1);
 
       _gtk_scale_clear_layout (scale);
 
@@ -911,8 +924,7 @@ gtk_scale_get_mark_label_size (GtkScale        *scale,
 }
 
 static void
-gtk_scale_style_set (GtkWidget *widget,
-                     GtkStyle  *previous)
+gtk_scale_style_updated (GtkWidget *widget)
 {
   gint slider_length;
   GtkRange *range;
@@ -927,7 +939,7 @@ gtk_scale_style_set (GtkWidget *widget,
 
   _gtk_scale_clear_layout (GTK_SCALE (widget));
 
-  GTK_WIDGET_CLASS (gtk_scale_parent_class)->style_set (widget, previous);
+  GTK_WIDGET_CLASS (gtk_scale_parent_class)->style_updated (widget);
 }
 
 static void
@@ -938,32 +950,54 @@ gtk_scale_screen_changed (GtkWidget *widget,
 }
 
 static void
-gtk_scale_size_request (GtkWidget      *widget,
-                        GtkRequisition *requisition)
+gtk_scale_get_preferred_width (GtkWidget *widget,
+                               gint      *minimum,
+                               gint      *natural)
 {
-  GtkRange *range = GTK_RANGE (widget);
-  gint n1, w1, h1, n2, w2, h2;
-  gint slider_length;
-
-  GTK_WIDGET_CLASS (gtk_scale_parent_class)->size_request (widget, requisition);
+  GTK_WIDGET_CLASS (gtk_scale_parent_class)->get_preferred_width (widget, minimum, natural);
   
-  gtk_widget_style_get (widget, "slider-length", &slider_length, NULL);
+  if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL)
+    {
+      gint n1, w1, h1, n2, w2, h2;
+      gint slider_length;
+      gint w;
 
+      gtk_widget_style_get (widget, "slider-length", &slider_length, NULL);
 
-  if (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL)
-    {
       gtk_scale_get_mark_label_size (GTK_SCALE (widget), GTK_POS_TOP, &n1, &w1, &h1, &n2, &w2, &h2);
 
       w1 = (n1 - 1) * w1 + MAX (w1, slider_length);
       w2 = (n2 - 1) * w2 + MAX (w2, slider_length);
-      requisition->width = MAX (requisition->width, MAX (w1, w2));
+      w = MAX (w1, w2);
+
+      *minimum = MAX (*minimum, w);
+      *natural = MAX (*natural, w);
     }
-  else
+}
+
+static void
+gtk_scale_get_preferred_height (GtkWidget *widget,
+                                gint      *minimum,
+                                gint      *natural)
+{
+  GTK_WIDGET_CLASS (gtk_scale_parent_class)->get_preferred_height (widget, minimum, natural);
+
+
+  if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_VERTICAL)
     {
+      gint n1, w1, h1, n2, w2, h2;
+      gint slider_length;
+      gint h;
+
+      gtk_widget_style_get (widget, "slider-length", &slider_length, NULL);
+
       gtk_scale_get_mark_label_size (GTK_SCALE (widget), GTK_POS_LEFT, &n1, &w1, &h1, &n2, &w2, &h2);
       h1 = (n1 - 1) * h1 + MAX (h1, slider_length);
       h2 = (n2 - 1) * h1 + MAX (h2, slider_length);
-      requisition->height = MAX (requisition->height, MAX (h1, h2));
+      h = MAX (h1, h2);
+
+      *minimum = MAX (*minimum, h);
+      *natural = MAX (*natural, h);
     }
 }
 
@@ -994,15 +1028,14 @@ find_next_pos (GtkWidget      *widget,
 }
 
 static gboolean
-gtk_scale_expose (GtkWidget      *widget,
-                  GdkEventExpose *event)
+gtk_scale_draw (GtkWidget *widget,
+                cairo_t   *cr)
 {
   GtkScale *scale = GTK_SCALE (widget);
   GtkScalePrivate *priv = scale->priv;
   GtkRange *range = GTK_RANGE (scale);
-  GtkStateType state_type;
-  GtkStyle *style;
-  GdkWindow *window;
+  GtkStateFlags state = 0;
+  GtkStyleContext *context;
   gint n_marks;
   gint *marks;
   gint focus_padding;
@@ -1010,7 +1043,7 @@ gtk_scale_expose (GtkWidget      *widget,
   gint value_spacing;
   gint min_sep = 4;
 
-  style = gtk_widget_get_style (widget);
+  context = gtk_widget_get_style_context (widget);
   gtk_widget_style_get (widget,
                         "focus-padding", &focus_padding,
                         "slider-width", &slider_width, 
@@ -1020,17 +1053,13 @@ gtk_scale_expose (GtkWidget      *widget,
   /* We need to chain up _first_ so the various geometry members of
    * GtkRange struct are updated.
    */
-  GTK_WIDGET_CLASS (gtk_scale_parent_class)->expose_event (widget, event);
+  GTK_WIDGET_CLASS (gtk_scale_parent_class)->draw (widget, cr);
 
-  window = gtk_widget_get_window (widget);
-
-  state_type = GTK_STATE_NORMAL;
   if (!gtk_widget_is_sensitive (widget))
-    state_type = GTK_STATE_INSENSITIVE;
+    state |= GTK_STATE_FLAG_INSENSITIVE;
 
   if (priv->marks)
     {
-      GtkAllocation allocation;
       GtkOrientation orientation;
       GdkRectangle range_rect;
       gint i;
@@ -1044,37 +1073,38 @@ gtk_scale_expose (GtkWidget      *widget,
       orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (range));
       n_marks = _gtk_range_get_stop_positions (range, &marks);
       layout = gtk_widget_create_pango_layout (widget, NULL);
-      gtk_widget_get_allocation (widget, &allocation);
       gtk_range_get_range_rect (range, &range_rect);
 
-      if (orientation == GTK_ORIENTATION_HORIZONTAL)
-        min_pos_before = min_pos_after = allocation.x;
-      else
-        min_pos_before = min_pos_after = allocation.y;
+      min_pos_before = min_pos_after = 0;
+
       for (m = priv->marks, i = 0; m; m = m->next, i++)
         {
           GtkScaleMark *mark = m->data;
 
           if (orientation == GTK_ORIENTATION_HORIZONTAL)
             {
-              x1 = allocation.x + marks[i];
+              x1 = marks[i];
               if (mark->position == GTK_POS_TOP)
                 {
-                  y1 = allocation.y + range_rect.y;
+                  y1 = range_rect.y;
                   y2 = y1 - slider_width / 2;
                   min_pos = min_pos_before;
-                  max_pos = allocation.x + find_next_pos (widget, m, marks + i, GTK_POS_TOP, 1) - min_sep;
+                  max_pos = find_next_pos (widget, m, marks + i, GTK_POS_TOP, 1) - min_sep;
                 }
               else
                 {
-                  y1 = allocation.y + range_rect.y + range_rect.height;
+                  y1 = range_rect.y + range_rect.height;
                   y2 = y1 + slider_width / 2;
                   min_pos = min_pos_after;
-                  max_pos = allocation.x + find_next_pos (widget, m, marks + i, GTK_POS_TOP, 0) - min_sep;
+                  max_pos = find_next_pos (widget, m, marks + i, GTK_POS_TOP, 0) - min_sep;
                 }
 
-              gtk_paint_vline (style, window, state_type,
-                               NULL, widget, "scale-mark", y1, y2, x1);
+              gtk_style_context_save (context);
+              gtk_style_context_add_class (context, GTK_STYLE_CLASS_MARK);
+              gtk_style_context_set_state (context, state);
+
+              gtk_render_line (context, cr,
+                               x1, y1, x1, y2);
 
               if (mark->markup)
                 {
@@ -1086,8 +1116,8 @@ gtk_scale_expose (GtkWidget      *widget,
                     x3 = min_pos;
                   if (x3 + logical_rect.width > max_pos)
                         x3 = max_pos - logical_rect.width;
-                  if (x3 < allocation.x)
-                     x3 = allocation.x;
+                  if (x3 < 0)
+                     x3 = 0;
                   if (mark->position == GTK_POS_TOP)
                     {
                       y3 = y2 - value_spacing - logical_rect.height;
@@ -1099,31 +1129,36 @@ gtk_scale_expose (GtkWidget      *widget,
                       min_pos_after = x3 + logical_rect.width + min_sep;
                     }
 
-                  gtk_paint_layout (style, window, state_type,
-                                    FALSE, NULL, widget, "scale-mark",
-                                    x3, y3, layout);
+                  gtk_render_layout (context, cr,
+                                     x3, y3, layout);
                 }
+
+              gtk_style_context_restore (context);
             }
           else
             {
               if (mark->position == GTK_POS_LEFT)
                 {
-                  x1 = allocation.x + range_rect.x;
-                  x2 = allocation.x + range_rect.x - slider_width / 2;
+                  x1 = range_rect.x;
+                  x2 = range_rect.x - slider_width / 2;
                   min_pos = min_pos_before;
-                  max_pos = allocation.y + find_next_pos (widget, m, marks + i, GTK_POS_LEFT, 1) - min_sep;
+                  max_pos = find_next_pos (widget, m, marks + i, GTK_POS_LEFT, 1) - min_sep;
                 }
               else
                 {
-                  x1 = allocation.x + range_rect.x + range_rect.width;
-                  x2 = allocation.x + range_rect.x + range_rect.width + slider_width / 2;
+                  x1 = range_rect.x + range_rect.width;
+                  x2 = range_rect.x + range_rect.width + slider_width / 2;
                   min_pos = min_pos_after;
-                  max_pos = allocation.y + find_next_pos (widget, m, marks + i, GTK_POS_LEFT, 0) - min_sep;
+                  max_pos = find_next_pos (widget, m, marks + i, GTK_POS_LEFT, 0) - min_sep;
                 }
-              y1 = allocation.y + marks[i];
+              y1 = marks[i];
+
+              gtk_style_context_save (context);
+              gtk_style_context_add_class (context, GTK_STYLE_CLASS_MARK);
+              gtk_style_context_set_state (context, state);
 
-              gtk_paint_hline (style, window, state_type,
-                               NULL, widget, "range-mark", x1, x2, y1);
+              gtk_render_line (context, cr,
+                               x1, y1, x2, y1);
 
               if (mark->markup)
                 {
@@ -1135,8 +1170,8 @@ gtk_scale_expose (GtkWidget      *widget,
                     y3 = min_pos;
                   if (y3 + logical_rect.height > max_pos)
                     y3 = max_pos - logical_rect.height;
-                  if (y3 < allocation.y)
-                    y3 = allocation.y;
+                  if (y3 < 0)
+                    y3 = 0;
                   if (mark->position == GTK_POS_LEFT)
                     {
                       x3 = x2 - value_spacing - logical_rect.width;
@@ -1148,10 +1183,11 @@ gtk_scale_expose (GtkWidget      *widget,
                       min_pos_after = y3 + logical_rect.height + min_sep;
                     }
 
-                  gtk_paint_layout (style, window, state_type,
-                                    FALSE, NULL, widget, "scale-mark",
-                                    x3, y3, layout);
+                  gtk_render_layout (context, cr,
+                                     x3, y3, layout);
                 }
+
+              gtk_style_context_restore (context);
             }
         } 
 
@@ -1162,24 +1198,20 @@ gtk_scale_expose (GtkWidget      *widget,
   if (priv->draw_value)
     {
       GtkOrientation orientation;
+      GtkAllocation allocation;
+
       PangoLayout *layout;
       gint x, y;
 
       orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (range));
       layout = gtk_scale_get_layout (scale);
       gtk_scale_get_layout_offsets (scale, &x, &y);
+      gtk_widget_get_allocation (widget, &allocation);
 
-      gtk_paint_layout (style,
-                        window,
-                        state_type,
-                       FALSE,
-                        NULL,
-                        widget,
-                        orientation == GTK_ORIENTATION_HORIZONTAL ?
-                        "hscale" : "vscale",
-                        x, y,
-                        layout);
-
+      gtk_render_layout (context, cr,
+                         x - allocation.x,
+                         y - allocation.y,
+                         layout);
     }
 
   return FALSE;
@@ -1329,13 +1361,13 @@ gtk_scale_finalize (GObject *object)
  * gtk_scale_get_layout:
  * @scale: A #GtkScale
  *
- * Gets the #PangoLayout used to display the scale. 
- * The returned object is owned by the scale so does 
- * not need to be freed by the caller. 
+ * Gets the #PangoLayout used to display the scale. The returned
+ * object is owned by the scale so does not need to be freed by
+ * the caller.
+ *
+ * Return value: (transfer none): the #PangoLayout for this scale,
+ *     or %NULL if the #GtkScale:draw-value property is %FALSE.
  *
- * Return value: the #PangoLayout for this scale, or %NULL 
- *    if the #GtkScale:draw-value property is %FALSE.
- *   
  * Since: 2.4
  */
 PangoLayout *
@@ -1368,8 +1400,8 @@ gtk_scale_get_layout (GtkScale *scale)
 /**
  * gtk_scale_get_layout_offsets:
  * @scale: a #GtkScale
- * @x: (allow-none): location to store X offset of layout, or %NULL
- * @y: (allow-none): location to store Y offset of layout, or %NULL
+ * @x: (out) (allow-none): location to store X offset of layout, or %NULL
+ * @y: (out) (allow-none): location to store Y offset of layout, or %NULL
  *
  * Obtains the coordinates where the scale will draw the 
  * #PangoLayout representing the text in the scale. Remember