[gtk+] gtk: Implement smooth scrolling in scrolledwindow/range



commit 2a72e7b7b86d1bdb3a6a818b94cb21bc8f611127
Author: Michael Natterer <mitch lanedo com>
Date:   Tue Jan 24 12:12:34 2012 +0100

    gtk: Implement smooth scrolling in scrolledwindow/range
    
    If delta_x/y information is provided in scroll events, use it
    to modify the underlying adjustment in steps proportional to
    the deltas provided.
    
    If the child widget of a scrolledwindow doesn't set
    GDK_SMOOTH_SCROLL_MASK, regular scroll events will be dispatched,
    and still handled by these 2 widgets.

 gtk/gtkrange.c          |   65 ++++++++++++++++++++++++++++++----------
 gtk/gtkrange.h          |    4 +-
 gtk/gtkscrolledwindow.c |   75 +++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 114 insertions(+), 30 deletions(-)
---
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index b920d00..b38fa89 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -1728,9 +1728,11 @@ gtk_range_realize (GtkWidget *widget)
   attributes.wclass = GDK_INPUT_ONLY;
   attributes.event_mask = gtk_widget_get_events (widget);
   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
-			    GDK_BUTTON_RELEASE_MASK |
-			    GDK_ENTER_NOTIFY_MASK |
-			    GDK_LEAVE_NOTIFY_MASK |
+                            GDK_BUTTON_RELEASE_MASK |
+                            GDK_SCROLL_MASK |
+                            GDK_SMOOTH_SCROLL_MASK |
+                            GDK_ENTER_NOTIFY_MASK |
+                            GDK_LEAVE_NOTIFY_MASK |
                             GDK_POINTER_MOTION_MASK |
                             GDK_POINTER_MOTION_HINT_MASK);
 
@@ -2784,7 +2786,7 @@ gtk_range_button_release (GtkWidget      *widget,
 /**
  * _gtk_range_get_wheel_delta:
  * @range: a #GtkRange
- * @direction: A #GdkScrollDirection
+ * @event: A #GdkEventScroll
  * 
  * Returns a good step value for the mouse wheel.
  * 
@@ -2793,28 +2795,59 @@ gtk_range_button_release (GtkWidget      *widget,
  * Since: 2.4
  **/
 gdouble
-_gtk_range_get_wheel_delta (GtkRange           *range,
-			    GdkScrollDirection  direction)
+_gtk_range_get_wheel_delta (GtkRange       *range,
+                            GdkEventScroll *event)
 {
   GtkRangePrivate *priv = range->priv;
   GtkAdjustment *adjustment = priv->adjustment;
+  gdouble dx, dy;
   gdouble delta;
+  gdouble page_size;
 
-  if (GTK_IS_SCROLLBAR (range))
-    delta = pow (gtk_adjustment_get_page_size (adjustment), 2.0 / 3.0);
+  page_size = gtk_adjustment_get_page_size (adjustment);
+
+  if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy))
+    {
+      GtkAllocation allocation;
+
+      gtk_widget_get_allocation (GTK_WIDGET (range), &allocation);
+
+      if (dx != 0 &&
+          gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL)
+        {
+          if (GTK_IS_SCROLLBAR (range) && page_size > 0)
+            delta = dx * page_size / allocation.width;
+          else
+            delta = dx * (gtk_adjustment_get_upper (adjustment) -
+                          gtk_adjustment_get_lower (adjustment)) / allocation.width;
+        }
+      else
+        {
+          if (GTK_IS_SCROLLBAR (range) && page_size > 0)
+            delta = dy * page_size / allocation.height;
+          else
+            delta = dy * (gtk_adjustment_get_upper (adjustment) -
+                          gtk_adjustment_get_lower (adjustment)) / allocation.height;
+        }
+    }
   else
-    delta = gtk_adjustment_get_step_increment (adjustment) * 2;
-  
-  if (direction == GDK_SCROLL_UP ||
-      direction == GDK_SCROLL_LEFT)
-    delta = - delta;
-  
+    {
+      if (GTK_IS_SCROLLBAR (range))
+        delta = pow (page_size, 2.0 / 3.0);
+      else
+        delta = gtk_adjustment_get_page_increment (adjustment) * 2;
+
+      if (event->direction == GDK_SCROLL_UP ||
+          event->direction == GDK_SCROLL_LEFT)
+        delta = - delta;
+    }
+
   if (priv->inverted)
     delta = - delta;
 
   return delta;
 }
-      
+
 static gboolean
 gtk_range_scroll_event (GtkWidget      *widget,
 			GdkEventScroll *event)
@@ -2827,7 +2860,7 @@ gtk_range_scroll_event (GtkWidget      *widget,
       gdouble delta;
       gboolean handled;
 
-      delta = _gtk_range_get_wheel_delta (range, event->direction);
+      delta = _gtk_range_get_wheel_delta (range, event);
 
       g_signal_emit (range, signals[CHANGE_VALUE], 0,
                      GTK_SCROLL_JUMP, gtk_adjustment_get_value (priv->adjustment) + delta,
diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h
index 0f52554..c4d9e9e 100644
--- a/gtk/gtkrange.h
+++ b/gtk/gtkrange.h
@@ -146,8 +146,8 @@ void               gtk_range_set_round_digits              (GtkRange      *range
 gint                gtk_range_get_round_digits              (GtkRange      *range);
 
 /* internal API */
-gdouble            _gtk_range_get_wheel_delta              (GtkRange      *range,
-                                                            GdkScrollDirection direction);
+gdouble            _gtk_range_get_wheel_delta              (GtkRange       *range,
+                                                            GdkEventScroll *event);
 void               _gtk_range_set_has_origin               (GtkRange      *range,
                                                             gboolean       has_origin);
 gboolean           _gtk_range_get_has_origin               (GtkRange      *range);
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 7c73994..05bad81 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -2248,7 +2248,9 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
 {
   GtkScrolledWindowPrivate *priv;
   GtkScrolledWindow *scrolled_window;
-  GtkWidget *range;
+  gboolean handled = FALSE;
+  gdouble delta_x;
+  gdouble delta_y;
 
   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);  
@@ -2256,23 +2258,72 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
   scrolled_window = GTK_SCROLLED_WINDOW (widget);
   priv = scrolled_window->priv;
 
-  if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
-    range = priv->vscrollbar;
-  else
-    range = priv->hscrollbar;
+  if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
+    {
+      if (delta_x != 0.0 && priv->hscrollbar &&
+          gtk_widget_get_visible (priv->hscrollbar))
+        {
+          GtkAdjustment *adj;
+          gdouble new_value;
+
+          adj = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
+
+          new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_x,
+                             gtk_adjustment_get_lower (adj),
+                             gtk_adjustment_get_upper (adj) -
+                             gtk_adjustment_get_page_size (adj));
+
+          gtk_adjustment_set_value (adj, new_value);
+
+          handled = TRUE;
+        }
+
+      if (delta_y != 0.0 && priv->vscrollbar &&
+          gtk_widget_get_visible (priv->vscrollbar))
+        {
+          GtkAdjustment *adj;
+          gdouble new_value;
+
+          adj = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
+
+          new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_y,
+                             gtk_adjustment_get_lower (adj),
+                             gtk_adjustment_get_upper (adj) -
+                             gtk_adjustment_get_page_size (adj));
+
+          gtk_adjustment_set_value (adj, new_value);
 
-  if (range && gtk_widget_get_visible (range))
+          handled = TRUE;
+        }
+    }
+  else
     {
-      GtkAdjustment *adjustment = gtk_range_get_adjustment (GTK_RANGE (range));
-      gdouble delta;
+      GtkWidget *range;
 
-      delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event->direction);
-      gtk_adjustment_set_value (adjustment, gtk_adjustment_get_value (adjustment) + delta);
+      if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
+        range = priv->vscrollbar;
+      else
+        range = priv->hscrollbar;
 
-      return TRUE;
+      if (range && gtk_widget_get_visible (range))
+        {
+          GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (range));
+          gdouble delta, new_value;
+
+          delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event);
+
+          new_value = CLAMP (gtk_adjustment_get_value (adj) + delta,
+                             gtk_adjustment_get_lower (adj),
+                             gtk_adjustment_get_upper (adj) -
+                             gtk_adjustment_get_page_size (adj));
+
+          gtk_adjustment_set_value (adj, new_value);
+
+          handled = TRUE;
+        }
     }
 
-  return FALSE;
+  return handled;
 }
 
 static gboolean



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