]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkscale.c
When finding a matching non-scalable dir, keep going and look for a closer
[~andy/gtk] / gtk / gtkscale.c
index e406535e6557544f2f7e68e4ae4d30469949b465..7cce057b9a060401bc9a338dc725f5a5d295bf5a 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include <config.h>
 #include <math.h>
 #include "gtkintl.h"
 #include "gtkscale.h"
-#include "gtkmarshal.h"
+#include "gtkmarshalers.h"
 #include "gdk/gdkkeysyms.h"
 #include "gtkbindings.h"
+#include "gtkprivate.h"
+#include "gtkalias.h"
+
+
+#define        MAX_DIGITS      (64)    /* don't change this,
+                                * a) you don't need to and
+                                * b) you might cause buffer owerflows in
+                                *    unrelated code portions otherwise
+                                */
+
+#define GTK_SCALE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCALE, GtkScalePrivate))
+
+typedef struct _GtkScalePrivate GtkScalePrivate;
+
+struct _GtkScalePrivate
+{
+  PangoLayout *layout;
+};
 
 enum {
   PROP_0,
@@ -45,10 +64,7 @@ enum {
 };
 
 static guint signals[LAST_SIGNAL];
-static GtkRangeClass *parent_class = NULL;
 
-static void gtk_scale_class_init       (GtkScaleClass *klass);
-static void gtk_scale_init             (GtkScale      *scale);
 static void gtk_scale_set_property     (GObject       *object,
                                         guint          prop_id,
                                         const GValue  *value,
@@ -61,40 +77,20 @@ static void gtk_scale_style_set        (GtkWidget     *widget,
                                         GtkStyle      *previous);
 static void gtk_scale_get_range_border (GtkRange      *range,
                                         GtkBorder     *border);
+static void gtk_scale_finalize         (GObject       *object);
+static void gtk_scale_screen_changed   (GtkWidget     *widget,
+                                        GdkScreen     *old_screen);
 
-GtkType
-gtk_scale_get_type (void)
-{
-  static GtkType scale_type = 0;
+G_DEFINE_ABSTRACT_TYPE (GtkScale, gtk_scale, GTK_TYPE_RANGE)
 
-  if (!scale_type)
-    {
-      static const GtkTypeInfo scale_info =
-      {
-       "GtkScale",
-       sizeof (GtkScale),
-       sizeof (GtkScaleClass),
-       (GtkClassInitFunc) gtk_scale_class_init,
-       (GtkObjectInitFunc) gtk_scale_init,
-       /* reserved_1 */ NULL,
-        /* reserved_2 */ NULL,
-        (GtkClassInitFunc) NULL,
-      };
-
-      scale_type = gtk_type_unique (GTK_TYPE_RANGE, &scale_info);
-    }
-
-  return scale_type;
-}
-
-gboolean
+static gboolean
 single_string_accumulator (GSignalInvocationHint *ihint,
                            GValue                *return_accu,
                            const GValue          *handler_return,
                            gpointer               dummy)
 {
   gboolean continue_emission;
-  gchar *str;
+  const gchar *str;
   
   str = g_value_get_string (handler_return);
   g_value_set_string (return_accu, str);
@@ -104,88 +100,86 @@ single_string_accumulator (GSignalInvocationHint *ihint,
 }
 
 
-#define add_slider_binding(binding_set, keyval, mask, scroll)          \
-  gtk_binding_entry_add_signal (binding_set, keyval, mask,             \
-                                "move_slider", 1,                      \
+#define add_slider_binding(binding_set, keyval, mask, scroll)              \
+  gtk_binding_entry_add_signal (binding_set, keyval, mask,                 \
+                                I_("move_slider"), 1, \
                                 GTK_TYPE_SCROLL_TYPE, scroll)
 
 static void
 gtk_scale_class_init (GtkScaleClass *class)
 {
   GObjectClass   *gobject_class;
-  GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
-  GtkRangeClass *range_class;
-  GtkBindingSet *binding_set;
+  GtkRangeClass  *range_class;
+  GtkBindingSet  *binding_set;
   
   gobject_class = G_OBJECT_CLASS (class);
-  object_class = (GtkObjectClass*) class;
   range_class = (GtkRangeClass*) class;
   widget_class = (GtkWidgetClass*) class;
   
-  parent_class = gtk_type_class (GTK_TYPE_RANGE);
-  
   gobject_class->set_property = gtk_scale_set_property;
   gobject_class->get_property = gtk_scale_get_property;
+  gobject_class->finalize = gtk_scale_finalize;
 
   widget_class->style_set = gtk_scale_style_set;
+  widget_class->screen_changed = gtk_scale_screen_changed;
 
   range_class->get_range_border = gtk_scale_get_range_border;
   
   signals[FORMAT_VALUE] =
-    g_signal_newc ("format_value",
-                  G_TYPE_FROM_CLASS (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GtkScaleClass, format_value),
-                  single_string_accumulator, NULL,
-                  gtk_marshal_STRING__DOUBLE,
-                  G_TYPE_STRING, 1,
-                  G_TYPE_DOUBLE);
+    g_signal_new (I_("format_value"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkScaleClass, format_value),
+                  single_string_accumulator, NULL,
+                  _gtk_marshal_STRING__DOUBLE,
+                  G_TYPE_STRING, 1,
+                  G_TYPE_DOUBLE);
 
   g_object_class_install_property (gobject_class,
                                    PROP_DIGITS,
                                    g_param_spec_int ("digits",
-                                                    _("Digits"),
-                                                    _("The number of decimal places that are displayed in the value"),
-                                                    0,
-                                                    G_MAXINT,
-                                                    0,
-                                                    G_PARAM_READWRITE));
+                                                    P_("Digits"),
+                                                    P_("The number of decimal places that are displayed in the value"),
+                                                    -1,
+                                                    MAX_DIGITS,
+                                                    1,
+                                                    GTK_PARAM_READWRITE));
   
   g_object_class_install_property (gobject_class,
                                    PROP_DRAW_VALUE,
-                                   g_param_spec_boolean ("draw_value",
-                                                        _("Draw Value"),
-                                                        _("Whether the current value is displayed as a string next to the slider"),
-                                                        FALSE,
-                                                        G_PARAM_READWRITE));
+                                   g_param_spec_boolean ("draw-value",
+                                                        P_("Draw Value"),
+                                                        P_("Whether the current value is displayed as a string next to the slider"),
+                                                        TRUE,
+                                                        GTK_PARAM_READWRITE));
   
   g_object_class_install_property (gobject_class,
                                    PROP_VALUE_POS,
-                                   g_param_spec_enum ("value_pos",
-                                                     _("Value Position"),
-                                                     _("The position in which the current value is displayed"),
+                                   g_param_spec_enum ("value-pos",
+                                                     P_("Value Position"),
+                                                     P_("The position in which the current value is displayed"),
                                                      GTK_TYPE_POSITION_TYPE,
-                                                     GTK_POS_LEFT,
-                                                     G_PARAM_READWRITE));
+                                                     GTK_POS_TOP,
+                                                     GTK_PARAM_READWRITE));
 
   gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_int ("slider_length",
-                                                            _("Slider Length"),
-                                                            _("Length of scale's slider"),
+                                          g_param_spec_int ("slider-length",
+                                                            P_("Slider Length"),
+                                                            P_("Length of scale's slider"),
                                                             0,
                                                             G_MAXINT,
                                                             31,
-                                                            G_PARAM_READABLE));
+                                                            GTK_PARAM_READABLE));
 
   gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_int ("value_spacing",
-                                                            _("Value spacing"),
-                                                            _("Space between value text and the slider/trough area"),
+                                          g_param_spec_int ("value-spacing",
+                                                            P_("Value spacing"),
+                                                            P_("Space between value text and the slider/trough area"),
                                                             0,
                                                             G_MAXINT,
                                                             2,
-                                                            G_PARAM_READABLE));
+                                                            GTK_PARAM_READABLE));
   
   /* All bindings (even arrow keys) are on both h/v scale, because
    * blind users etc. don't care about scale orientation.
@@ -241,10 +235,10 @@ gtk_scale_class_init (GtkScaleClass *class)
   add_slider_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK,
                       GTK_SCROLL_PAGE_DOWN);
    
-  add_slider_binding (binding_set, GDK_Page_Up, 0,
+  add_slider_binding (binding_set, GDK_Page_Up, GDK_CONTROL_MASK,
                       GTK_SCROLL_PAGE_LEFT);
 
-  add_slider_binding (binding_set, GDK_KP_Page_Up, 0,
+  add_slider_binding (binding_set, GDK_KP_Page_Up, GDK_CONTROL_MASK,
                       GTK_SCROLL_PAGE_LEFT);  
 
   add_slider_binding (binding_set, GDK_Page_Up, 0,
@@ -253,10 +247,10 @@ gtk_scale_class_init (GtkScaleClass *class)
   add_slider_binding (binding_set, GDK_KP_Page_Up, 0,
                       GTK_SCROLL_PAGE_UP);
   
-  add_slider_binding (binding_set, GDK_Page_Down, 0,
+  add_slider_binding (binding_set, GDK_Page_Down, GDK_CONTROL_MASK,
                       GTK_SCROLL_PAGE_RIGHT);
 
-  add_slider_binding (binding_set, GDK_KP_Page_Down, 0,
+  add_slider_binding (binding_set, GDK_KP_Page_Down, GDK_CONTROL_MASK,
                       GTK_SCROLL_PAGE_RIGHT);
 
   add_slider_binding (binding_set, GDK_Page_Down, 0,
@@ -304,6 +298,8 @@ gtk_scale_class_init (GtkScaleClass *class)
 
   add_slider_binding (binding_set, GDK_KP_End, 0,
                       GTK_SCROLL_END);
+
+  g_type_class_add_private (gobject_class, sizeof (GtkScalePrivate));
 }
 
 static void
@@ -391,13 +387,15 @@ gtk_scale_set_digits (GtkScale *scale,
 
   range = GTK_RANGE (scale);
   
-  digits = CLAMP (digits, -1, 16);
+  digits = CLAMP (digits, -1, MAX_DIGITS);
 
   if (scale->digits != digits)
     {
       scale->digits = digits;
-      range->round_digits = digits;
+      if (scale->draw_value)
+       range->round_digits = digits;
       
+      _gtk_scale_clear_layout (scale);
       gtk_widget_queue_resize (GTK_WIDGET (scale));
 
       g_object_notify (G_OBJECT (scale), "digits");
@@ -416,7 +414,6 @@ void
 gtk_scale_set_draw_value (GtkScale *scale,
                          gboolean  draw_value)
 {
-  g_return_if_fail (scale != NULL);
   g_return_if_fail (GTK_IS_SCALE (scale));
 
   draw_value = draw_value != FALSE;
@@ -424,10 +421,16 @@ gtk_scale_set_draw_value (GtkScale *scale,
   if (scale->draw_value != draw_value)
     {
       scale->draw_value = draw_value;
+      if (draw_value)
+       GTK_RANGE (scale)->round_digits = scale->digits;
+      else
+       GTK_RANGE (scale)->round_digits = -1;
+
+      _gtk_scale_clear_layout (scale);
 
       gtk_widget_queue_resize (GTK_WIDGET (scale));
 
-      g_object_notify (G_OBJECT (scale), "draw_value");
+      g_object_notify (G_OBJECT (scale), "draw-value");
     }
 }
 
@@ -449,10 +452,11 @@ gtk_scale_set_value_pos (GtkScale        *scale,
     {
       scale->value_pos = pos;
 
+      _gtk_scale_clear_layout (scale);
       if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale))
        gtk_widget_queue_resize (GTK_WIDGET (scale));
 
-      g_object_notify (G_OBJECT (scale), "value_pos");
+      g_object_notify (G_OBJECT (scale), "value-pos");
     }
 }
 
@@ -485,7 +489,7 @@ gtk_scale_get_range_border (GtkRange  *range,
   if (scale->draw_value)
     {
       gint value_spacing;
-      gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
+      gtk_widget_style_get (widget, "value-spacing", &value_spacing, NULL);
 
       switch (scale->value_pos)
         {
@@ -513,7 +517,6 @@ _gtk_scale_get_value_size (GtkScale *scale,
 {
   GtkRange *range;
 
-  g_return_if_fail (scale != NULL);
   g_return_if_fail (GTK_IS_SCALE (scale));
 
   if (scale->draw_value)
@@ -548,7 +551,7 @@ _gtk_scale_get_value_size (GtkScale *scale,
       if (height)
        *height = MAX (*height, logical_rect.height);
 
-      g_object_unref (G_OBJECT (layout));
+      g_object_unref (layout);
     }
   else
     {
@@ -570,14 +573,22 @@ gtk_scale_style_set (GtkWidget *widget,
   range = GTK_RANGE (widget);
   
   gtk_widget_style_get (widget,
-                        "slider_length", &slider_length,
+                        "slider-length", &slider_length,
                         NULL);
   
   range->min_slider_size = slider_length;
   
-  (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
+  _gtk_scale_clear_layout (GTK_SCALE (widget));
+
+  (* GTK_WIDGET_CLASS (gtk_scale_parent_class)->style_set) (widget, previous);
 }
 
+static void
+gtk_scale_screen_changed (GtkWidget *widget,
+                          GdkScreen *old_screen)
+{
+  _gtk_scale_clear_layout (GTK_SCALE (widget));
+}
 
 /**
  * _gtk_scale_format_value:
@@ -595,7 +606,7 @@ _gtk_scale_format_value (GtkScale *scale,
 {
   gchar *fmt = NULL;
 
-  g_signal_emit (G_OBJECT (scale),
+  g_signal_emit (scale,
                  signals[FORMAT_VALUE],
                  0,
                  value,
@@ -604,6 +615,109 @@ _gtk_scale_format_value (GtkScale *scale,
   if (fmt)
     return fmt;
   else
-    return g_strdup_printf ("%0.*f", scale->digits,
-                            value);
+    /* insert a LRM, to prevent -20 to come out as 20- in RTL locales */
+    return g_strdup_printf ("\342\200\216%0.*f", scale->digits, value);
+}
+
+static void
+gtk_scale_finalize (GObject *object)
+{
+  GtkScale *scale;
+
+  g_return_if_fail (GTK_IS_SCALE (object));
+
+  scale = GTK_SCALE (object);
+
+  _gtk_scale_clear_layout (scale);
+
+  G_OBJECT_CLASS (gtk_scale_parent_class)->finalize (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. 
+ *
+ * Return value: the #PangoLayout for this scale, or %NULL if the draw_value property
+ *    is %FALSE.
+ *   
+ * Since: 2.4
+ **/
+PangoLayout *
+gtk_scale_get_layout (GtkScale *scale)
+{
+  GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);
+  gchar *txt;
+
+  g_return_val_if_fail (GTK_IS_SCALE (scale), NULL);
+
+  if (!priv->layout)
+    {
+      if (scale->draw_value)
+       priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL);
+    }
+
+  if (scale->draw_value) 
+    {
+      txt = _gtk_scale_format_value (scale,
+                                    GTK_RANGE (scale)->adjustment->value);
+      pango_layout_set_text (priv->layout, txt, -1);
+      g_free (txt);
+    }
+
+  return priv->layout;
 }
+
+/**
+ * gtk_scale_get_layout_offsets:
+ * @scale: a #GtkScale
+ * @x: location to store X offset of layout, or %NULL
+ * @y: 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
+ * when using the #PangoLayout function you need to convert to
+ * and from pixels using PANGO_PIXELS() or #PANGO_SCALE. 
+ *
+ * If the draw_value property is %FALSE, the return values are 
+ * undefined.
+ *
+ * Since: 2.4
+ **/
+void 
+gtk_scale_get_layout_offsets (GtkScale *scale,
+                              gint     *x,
+                              gint     *y)
+{
+  gint local_x = 0; 
+  gint local_y = 0;
+
+  g_return_if_fail (GTK_IS_SCALE (scale));
+
+  if (GTK_SCALE_GET_CLASS (scale)->get_layout_offsets)
+    (GTK_SCALE_GET_CLASS (scale)->get_layout_offsets) (scale, &local_x, &local_y);
+
+  if (x)
+    *x = local_x;
+  
+  if (y)
+    *y = local_y;
+}
+
+void _gtk_scale_clear_layout (GtkScale *scale)
+{
+  GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);
+
+  g_return_if_fail (GTK_IS_SCALE (scale));
+
+  if (priv->layout)
+    {
+      g_object_unref (priv->layout);
+      priv->layout = NULL;
+    }
+}
+
+#define __GTK_SCALE_C__
+#include "gtkaliasdef.c"