[gtk+] Add a 'fine adjustment' mode to ranges



commit 22eb687264ea60498532fd5ce5f541271782bd3e
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Apr 26 17:51:13 2012 -0400

    Add a 'fine adjustment' mode to ranges
    
    Shift-click in the slider now starts a drag in 'fine adjustment'
    mode, where we move the slider 10-times slower than the mouse.
    
    This can be very helpful when scrolling through a very long document
    or webpage, and moving the scrollbar even a single pixel already
    jumps too far in the content.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=563688

 gtk/gtkrange.c |   42 ++++++++++++++++++++++++++++++++++--------
 1 files changed, 34 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index a224f4f..29384f7 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -138,6 +138,9 @@ struct _GtkRangePrivate
   /* The range has an origin, should be drawn differently. Used by GtkScale */
   guint has_origin             : 1;
 
+  /* Whether we're doing fine adjustment */
+  guint zoom                   : 1;
+
   /* Fill level */
   guint show_fill_level        : 1;
   guint restrict_to_fill_level : 1;
@@ -2367,6 +2370,8 @@ range_grab_remove (GtkRange *range)
   if (gtk_range_update_mouse_location (range) ||
       location != MOUSE_OUTSIDE)
     gtk_widget_queue_draw (GTK_WIDGET (range));
+
+  priv->zoom = FALSE;
 }
 
 static GtkScrollType
@@ -2433,7 +2438,7 @@ range_get_scroll_for_grab (GtkRange      *range)
 
 static gdouble
 coord_to_value (GtkRange *range,
-                gint      coord)
+                gdouble   coord)
 {
   GtkRangePrivate *priv = range->priv;
   gdouble frac;
@@ -2635,6 +2640,12 @@ gtk_range_button_press (GtkWidget      *widget,
 	   */
 	  need_value_update = TRUE;
         }
+      else
+        {
+          /* Shift-click in the slider = fine adjustment */
+          if (event->state & GDK_SHIFT_MASK)
+            priv->zoom = TRUE;
+        }
 
       if (priv->orientation == GTK_ORIENTATION_VERTICAL)
         {
@@ -2667,13 +2678,14 @@ update_slider_position (GtkRange *range,
                         gint      mouse_y)
 {
   GtkRangePrivate *priv = range->priv;
-  gint delta;
-  gint c;
+  gdouble delta;
+  gdouble c;
   gdouble new_value;
   gboolean handled;
   gdouble next_value;
   gdouble mark_value;
   gdouble mark_delta;
+  gdouble zoom;
   gint i;
 
   if (priv->orientation == GTK_ORIENTATION_VERTICAL)
@@ -2681,11 +2693,25 @@ update_slider_position (GtkRange *range,
   else
     delta = mouse_x - priv->slide_initial_coordinate;
 
-  c = priv->slide_initial_slider_position + delta;
+  if (priv->zoom)
+    {
+      zoom = MIN(1.0, (priv->orientation == GTK_ORIENTATION_VERTICAL ?
+                       priv->trough.height : priv->trough.width) /
+                       (gtk_adjustment_get_upper (priv->adjustment) -
+                        gtk_adjustment_get_lower (priv->adjustment) -
+                        gtk_adjustment_get_page_size (priv->adjustment)));
+      /* the above is ineffective for scales, so just set a zoom factor */
+      if (zoom == 1.0)
+        zoom = 0.25;
+    }
+  else
+    zoom = 1.0;
+
+  c = priv->slide_initial_slider_position + zoom * delta;
 
   new_value = coord_to_value (range, c);
   next_value = coord_to_value (range, c + 1);
-  mark_delta = fabs (next_value - new_value); 
+  mark_delta = fabs (next_value - new_value);
 
   for (i = 0; i < priv->n_marks; i++)
     {
@@ -2699,13 +2725,13 @@ update_slider_position (GtkRange *range,
               break;
             }
         }
-    }  
+    }
 
   g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, new_value,
                  &handled);
 }
 
-static void 
+static void
 stop_scrolling (GtkRange *range)
 {
   range_grab_remove (range);
@@ -2726,7 +2752,7 @@ gtk_range_grab_broken (GtkWidget          *widget,
       priv->grab_location != MOUSE_OUTSIDE)
     {
       if (priv->grab_location == MOUSE_SLIDER)
-	update_slider_position (range, priv->mouse_x, priv->mouse_y);
+        update_slider_position (range, priv->mouse_x, priv->mouse_y);
 
       stop_scrolling (range);
       



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