From 001a1517da69a568d91f272f51532908b6a0576c Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sat, 26 Nov 2011 20:23:08 +0100 Subject: [PATCH] gtk,scrolledwindow: Clamp early overshooting when snapping back Fixes the situation where overshooting in scrolled windows with a small viewport could end up overshooting right to the opposite side, and then back again indefinitely. --- gtk/gtkscrolledwindow.c | 80 ++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index 31770df088..9ee91a476e 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -286,7 +286,8 @@ static void gtk_scrolled_window_auto_hide_scrollbars_stop (GtkScrolledWindo static gboolean _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window, GtkAdjustment *adjustment, gdouble value, - gboolean allow_overshooting); + gboolean allow_overshooting, + gboolean snap_to_border); static guint signals[LAST_SIGNAL] = {0}; @@ -2276,37 +2277,41 @@ static gboolean _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window, GtkAdjustment *adjustment, gdouble value, - gboolean allow_overshooting) + gboolean allow_overshooting, + gboolean snap_to_border) { GtkScrolledWindowPrivate *priv = scrolled_window->priv; - gdouble lower, upper; + gdouble lower, upper, *prev_value; lower = gtk_adjustment_get_lower (adjustment); upper = gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_page_size (adjustment); + if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar))) + prev_value = &priv->unclamped_hadj_value; + else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar))) + prev_value = &priv->unclamped_vadj_value; + else + return FALSE; + + if (snap_to_border) + { + if (*prev_value < 0 && value > 0) + value = 0; + else if (*prev_value > upper && value < upper) + value = upper; + } + if (allow_overshooting) { lower -= MAX_OVERSHOOT_DISTANCE; upper += MAX_OVERSHOOT_DISTANCE; } - if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar))) - { - priv->unclamped_hadj_value = CLAMP (value, lower, upper); - gtk_adjustment_set_value (adjustment, value); + *prev_value = CLAMP (value, lower, upper); + gtk_adjustment_set_value (adjustment, value); - return (priv->unclamped_hadj_value != value); - } - else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar))) - { - priv->unclamped_vadj_value = CLAMP (value, lower, upper); - gtk_adjustment_set_value (adjustment, value); - - return (priv->unclamped_vadj_value != value); - } - - return FALSE; + return (*prev_value != value); } static gboolean @@ -2317,7 +2322,7 @@ scrolled_window_deceleration_cb (gpointer user_data) GtkScrolledWindowPrivate *priv = scrolled_window->priv; GtkAdjustment *hadjustment, *vadjustment; gint old_overshoot_x, old_overshoot_y, overshoot_x, overshoot_y; - gdouble value, clamp_value; + gdouble value; gint64 current_time; guint elapsed; @@ -2337,7 +2342,7 @@ scrolled_window_deceleration_cb (gpointer user_data) if (_gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment, - value, TRUE)) + value, TRUE, TRUE)) data->x_velocity = 0; } else @@ -2349,7 +2354,7 @@ scrolled_window_deceleration_cb (gpointer user_data) if (_gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment, - value, TRUE)) + value, TRUE, TRUE)) data->y_velocity = 0; } else @@ -2362,17 +2367,7 @@ scrolled_window_deceleration_cb (gpointer user_data) { if (old_overshoot_x != 0) { - /* Overshooting finished, clamp to border */ - clamp_value = (old_overshoot_x < 0) ? - gtk_adjustment_get_lower (hadjustment) : - gtk_adjustment_get_upper (hadjustment) - - gtk_adjustment_get_page_size (hadjustment); - - _gtk_scrolled_window_set_adjustment_value (scrolled_window, - hadjustment, - clamp_value, - FALSE); - + /* Overshooting finished snapping back */ data->x_velocity = 0; } else if (data->x_velocity > 0) @@ -2395,16 +2390,7 @@ scrolled_window_deceleration_cb (gpointer user_data) { if (old_overshoot_y != 0) { - /* Overshooting finished, clamp to border */ - clamp_value = (old_overshoot_y < 0) ? - gtk_adjustment_get_lower (vadjustment) : - gtk_adjustment_get_upper (vadjustment) - - gtk_adjustment_get_page_size (vadjustment); - - _gtk_scrolled_window_set_adjustment_value (scrolled_window, - vadjustment, - clamp_value, - FALSE); + /* Overshooting finished snapping back */ data->y_velocity = 0; } else if (data->y_velocity > 0) @@ -2470,11 +2456,11 @@ gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window) _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment, gtk_adjustment_get_value (vadjustment), - FALSE); + FALSE, TRUE); _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment, gtk_adjustment_get_value (hadjustment), - FALSE); + FALSE, TRUE); } } @@ -2675,14 +2661,16 @@ gtk_scrolled_window_motion_notify_event (GtkWidget *widget, if (hadjustment && priv->hscrollbar_visible) { dx = (priv->last_motion_event_x_root - event->x_root) + priv->unclamped_hadj_value; - _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment, dx, TRUE); + _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment, + dx, TRUE, FALSE); } vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)); if (vadjustment && priv->vscrollbar_visible) { dy = (priv->last_motion_event_y_root - event->y_root) + priv->unclamped_vadj_value; - _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment, dy, TRUE); + _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment, + dy, TRUE, FALSE); } _gtk_scrolled_window_get_overshoot (scrolled_window,