]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrange.c
s/succesfully/successfully/g
[~andy/gtk] / gtk / gtkrange.c
index c4ae093d8ff54c3a536507e937095f5fb2ce94d6..6e63141ea642a99f7b78022b0a645d0f29d077db 100644 (file)
@@ -39,7 +39,8 @@
 enum {
   PROP_0,
   PROP_UPDATE_POLICY,
-  PROP_ADJUSTMENT
+  PROP_ADJUSTMENT,
+  PROP_INVERTED
 };
 
 enum {
@@ -83,6 +84,7 @@ struct _GtkRangeLayout
   gint grab_button; /* 0 if none */
 };
 
+
 static void gtk_range_class_init     (GtkRangeClass    *klass);
 static void gtk_range_init           (GtkRange         *range);
 static void gtk_range_set_property   (GObject          *object,
@@ -117,6 +119,9 @@ static gint gtk_range_scroll_event   (GtkWidget        *widget,
                                       GdkEventScroll   *event);
 static void gtk_range_style_set      (GtkWidget        *widget,
                                       GtkStyle         *previous_style);
+static void update_slider_position   (GtkRange        *range,
+                                     gint              mouse_x,
+                                     gint              mouse_y);
 
 
 /* Range methods */
@@ -128,7 +133,8 @@ static void gtk_range_move_slider              (GtkRange         *range,
 static void          gtk_range_scroll                   (GtkRange      *range,
                                                          GtkScrollType  scroll);
 static gboolean      gtk_range_update_mouse_location    (GtkRange      *range);
-static void          gtk_range_calc_layout              (GtkRange      *range);
+static void          gtk_range_calc_layout              (GtkRange      *range,
+                                                        gdouble        adjustment_value);
 static void          gtk_range_get_props                (GtkRange      *range,
                                                          gint          *slider_width,
                                                          gint          *stepper_size,
@@ -225,24 +231,24 @@ gtk_range_class_init (GtkRangeClass *class)
   class->stepper_detail = "stepper";
 
   signals[VALUE_CHANGED] =
-    g_signal_newc ("value_changed",
-                  G_TYPE_FROM_CLASS (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GtkRangeClass, value_changed),
-                  NULL, NULL,
-                  gtk_marshal_NONE__NONE,
-                  G_TYPE_NONE, 0);
+    g_signal_new ("value_changed",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkRangeClass, value_changed),
+                  NULL, NULL,
+                  gtk_marshal_NONE__NONE,
+                  G_TYPE_NONE, 0);
   
   signals[MOVE_SLIDER] =
-    g_signal_newc ("move_slider",
-                   G_TYPE_FROM_CLASS (object_class),
-                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                   G_STRUCT_OFFSET (GtkRangeClass, move_slider),
-                   NULL, NULL,
-                   gtk_marshal_VOID__ENUM,
-                   G_TYPE_NONE, 1,
-                   GTK_TYPE_SCROLL_TYPE);
-
+    g_signal_new ("move_slider",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GtkRangeClass, move_slider),
+                  NULL, NULL,
+                  gtk_marshal_VOID__ENUM,
+                  G_TYPE_NONE, 1,
+                  GTK_TYPE_SCROLL_TYPE);
+  
   
   g_object_class_install_property (gobject_class,
                                    PROP_UPDATE_POLICY,
@@ -259,8 +265,16 @@ gtk_range_class_init (GtkRangeClass *class)
                                                        _("Adjustment"),
                                                        _("The GtkAdjustment that contains the current value of this range object"),
                                                         GTK_TYPE_ADJUSTMENT,
-                                                        G_PARAM_READWRITE));
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
+  g_object_class_install_property (gobject_class,
+                                   PROP_INVERTED,
+                                   g_param_spec_boolean ("inverted",
+                                                       _("Inverted"),
+                                                       _("Invert direction slider moves to increase range value"),
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+  
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("slider_width",
                                                             _("Slider Width"),
@@ -313,6 +327,9 @@ gtk_range_set_property (GObject      *object,
     case PROP_ADJUSTMENT:
       gtk_range_set_adjustment (range, g_value_get_object (value));
       break;
+    case PROP_INVERTED:
+      gtk_range_set_inverted (range, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -337,6 +354,9 @@ gtk_range_get_property (GObject      *object,
     case PROP_ADJUSTMENT:
       g_value_set_object (value, G_OBJECT (range->adjustment));
       break;
+    case PROP_INVERTED:
+      g_value_set_boolean (value, range->inverted);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -377,7 +397,6 @@ gtk_range_init (GtkRange *range)
 GtkAdjustment*
 gtk_range_get_adjustment (GtkRange *range)
 {
-  g_return_val_if_fail (range != NULL, NULL);
   g_return_val_if_fail (GTK_IS_RANGE (range), NULL);
 
   if (!range->adjustment)
@@ -405,7 +424,6 @@ void
 gtk_range_set_update_policy (GtkRange      *range,
                             GtkUpdateType  policy)
 {
-  g_return_if_fail (range != NULL);
   g_return_if_fail (GTK_IS_RANGE (range));
 
   if (range->update_policy != policy)
@@ -415,6 +433,22 @@ gtk_range_set_update_policy (GtkRange      *range,
     }
 }
 
+/**
+ * gtk_range_get_update_policy:
+ * @range: a #GtkRange
+ *
+ * Gets the update policy of @range. See gtk_range_set_update_policy().
+ *
+ * Return value: the current update policy
+ **/
+GtkUpdateType
+gtk_range_get_update_policy (GtkRange *range)
+{
+  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_UPDATE_CONTINUOUS);
+
+  return range->update_policy;
+}
+
 /**
  * gtk_range_set_adjustment:
  * @range: a #GtkRange
@@ -433,7 +467,6 @@ void
 gtk_range_set_adjustment (GtkRange      *range,
                          GtkAdjustment *adjustment)
 {
-  g_return_if_fail (range != NULL);
   g_return_if_fail (GTK_IS_RANGE (range));
   
   if (!adjustment)
@@ -492,6 +525,7 @@ gtk_range_set_inverted (GtkRange *range,
   if (setting != range->inverted)
     {
       range->inverted = setting;
+      g_object_notify (G_OBJECT (range), "inverted");
       gtk_widget_queue_resize (GTK_WIDGET (range));
     }
 }
@@ -686,7 +720,7 @@ gtk_range_size_allocate (GtkWidget     *widget,
   range = GTK_RANGE (widget);
 
   range->need_recalc = TRUE;
-  gtk_range_calc_layout (range);
+  gtk_range_calc_layout (range, range->adjustment->value);
 
   (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
 }
@@ -700,7 +734,7 @@ gtk_range_realize (GtkWidget *widget)
 
   range = GTK_RANGE (widget);
 
-  gtk_range_calc_layout (range);
+  gtk_range_calc_layout (range, range->adjustment->value);
   
   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
@@ -735,7 +769,6 @@ gtk_range_unrealize (GtkWidget *widget)
 {
   GtkRange *range;
 
-  g_return_if_fail (widget != NULL);
   g_return_if_fail (GTK_IS_RANGE (widget));
 
   range = GTK_RANGE (widget);
@@ -795,13 +828,12 @@ gtk_range_expose (GtkWidget      *widget,
   GtkStateType state;
   GdkRectangle area;
   
-  g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
   range = GTK_RANGE (widget);
 
-  gtk_range_calc_layout (range);
+  gtk_range_calc_layout (range, range->adjustment->value);
 
   sensitive = GTK_WIDGET_IS_SENSITIVE (widget);
   
@@ -989,11 +1021,17 @@ coord_to_value (GtkRange *range,
   gdouble value;
   
   if (range->orientation == GTK_ORIENTATION_VERTICAL)
-    frac = ((coord - range->layout->trough.y) /
-            (gdouble) (range->layout->trough.height - range->layout->slider.height));
+    if (range->layout->trough.height == range->layout->slider.height)
+      frac = 1.0;
+    else 
+      frac = ((coord - range->layout->trough.y) /
+             (gdouble) (range->layout->trough.height - range->layout->slider.height));
   else
-    frac = ((coord - range->layout->trough.x) /
-            (gdouble) (range->layout->trough.width - range->layout->slider.width));
+    if (range->layout->trough.width == range->layout->slider.width)
+      frac = 1.0;
+    else
+      frac = ((coord - range->layout->trough.x) /
+             (gdouble) (range->layout->trough.width - range->layout->slider.width));
 
   if (should_invert (range))
     frac = 1.0 - frac;
@@ -1077,6 +1115,8 @@ gtk_range_button_press (GtkWidget      *widget,
             event->button == 2) ||
            range->layout->mouse_location == MOUSE_SLIDER)
     {
+      gboolean need_value_update = FALSE;
+
       /* Any button can be used to drag the slider, but you can start
        * dragging the slider with a trough click using button 2;
        * On button 2 press, we warp the slider to mouse position,
@@ -1084,7 +1124,7 @@ gtk_range_button_press (GtkWidget      *widget,
        */
       if (event->button == 2)
         {
-          gdouble slider_low_value, slider_high_value;
+          gdouble slider_low_value, slider_high_value, new_value;
           
           slider_high_value =
             coord_to_value (range,
@@ -1096,14 +1136,19 @@ gtk_range_button_press (GtkWidget      *widget,
                             event->y - range->layout->slider.height :
                             event->x - range->layout->slider.width);
           
-          /* middle button jumps to point */
-          gtk_range_internal_set_value (range,
-                                        slider_low_value + (slider_high_value - slider_low_value) / 2);
+          /* compute new value for warped slider */
+          new_value = slider_low_value + (slider_high_value - slider_low_value) / 2;
 
-          /* Calc layout so we can set slide_initial_slider_position
+         /* recalc slider, so we can set slide_initial_slider_position
            * properly
            */
-          gtk_range_calc_layout (range);
+         range->need_recalc = TRUE;
+          gtk_range_calc_layout (range, new_value);
+
+         /* defer adjustment updates to update_slider_position() in order
+          * to keep pixel quantisation
+          */
+         need_value_update = TRUE;
         }
       
       if (range->orientation == GTK_ORIENTATION_VERTICAL)
@@ -1117,6 +1162,9 @@ gtk_range_button_press (GtkWidget      *widget,
           range->slide_initial_coordinate = event->x;
         }
 
+      if (need_value_update)
+        update_slider_position (range, event->x, event->y);
+
       range_grab_add (range, MOUSE_SLIDER, event->button);
       
       return TRUE;
@@ -1252,7 +1300,7 @@ gtk_range_motion_notify (GtkWidget      *widget,
     gtk_widget_queue_draw (widget);
 
   if (range->layout->grab_location == MOUSE_SLIDER)
-    update_slider_position (range, event->x, event->y);
+    update_slider_position (range, x, y);
 
   /* We handled the event if the mouse was in the range_rect */
   return range->layout->mouse_location != MOUSE_OUTSIDE;
@@ -1356,7 +1404,6 @@ gtk_range_style_set (GtkWidget *widget,
 {
   GtkRange *range;
 
-  g_return_if_fail (widget != NULL);
   g_return_if_fail (GTK_IS_RANGE (widget));
 
   range = GTK_RANGE (widget);
@@ -1743,7 +1790,8 @@ gtk_range_calc_request (GtkRange      *range,
 }
 
 static void
-gtk_range_calc_layout (GtkRange *range)
+gtk_range_calc_layout (GtkRange *range,
+                      gdouble   adjustment_value)
 {
   gint slider_width, stepper_size, trough_border, stepper_spacing;
   gint slider_length;
@@ -1910,7 +1958,7 @@ gtk_range_calc_layout (GtkRange *range)
         
         y = top;
         
-        y += (bottom - top - height) * ((range->adjustment->value - range->adjustment->lower) /
+        y += (bottom - top - height) * ((adjustment_value - range->adjustment->lower) /
                                         (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
         
         y = CLAMP (y, top, bottom);
@@ -2045,7 +2093,7 @@ gtk_range_calc_layout (GtkRange *range)
         
         x = left;
         
-        x += (right - left - width) * ((range->adjustment->value - range->adjustment->lower) /
+        x += (right - left - width) * ((adjustment_value - range->adjustment->lower) /
                                        (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
         
         x = CLAMP (x, left, right);
@@ -2160,9 +2208,10 @@ second_timeout (gpointer data)
 {
   GtkRange *range;
 
+  GDK_THREADS_ENTER ();
   range = GTK_RANGE (data);
-
   gtk_range_scroll (range, range->timer->step);
+  GDK_THREADS_LEAVE ();
   
   return TRUE;
 }
@@ -2172,12 +2221,13 @@ initial_timeout (gpointer data)
 {
   GtkRange *range;
 
+  GDK_THREADS_ENTER ();
   range = GTK_RANGE (data);
-
   range->timer->timeout_id = 
     g_timeout_add (SCROLL_LATER_DELAY,
                    second_timeout,
                    range);
+  GDK_THREADS_LEAVE ();
 
   /* remove self */
   return FALSE;
@@ -2218,11 +2268,11 @@ update_timeout (gpointer data)
 {
   GtkRange *range;
 
+  GDK_THREADS_ENTER ();
   range = GTK_RANGE (data);
-
   gtk_range_update_value (range);
-
   range->update_timeout_id = 0;
+  GDK_THREADS_LEAVE ();
 
   /* self-remove */
   return FALSE;