diff options
author | Chris Lord <chrislord.net@gmail.com> | 2020-10-30 18:36:53 +0000 |
---|---|---|
committer | Alexander Mikhaylenko <alexm@gnome.org> | 2020-11-12 18:56:14 +0500 |
commit | 1d62a010eff89055635faf2656088a28663faa2e (patch) | |
tree | c58ee1bb78734ff415f051624a78453baed01788 | |
parent | 2560af284d0c32cbf8bd8956a76c834dda75c5d4 (diff) | |
download | gtk+-wip/exalm/accumulate-scrolling-backport.tar.gz |
scrolledwindow: Accumulate velocity with kinetic scrollingwip/exalm/accumulate-scrolling-backport
Accumulate existing velocity when decelerating from a swipe if the swipe
velocity is above a certain fraction of that existing velocity.
-rw-r--r-- | gtk/gtkkineticscrolling.c | 5 | ||||
-rw-r--r-- | gtk/gtkkineticscrolling.h | 3 | ||||
-rw-r--r-- | gtk/gtkscrolledwindow.c | 95 |
3 files changed, 65 insertions, 38 deletions
diff --git a/gtk/gtkkineticscrolling.c b/gtk/gtkkineticscrolling.c index 29bf085674..9036e158dc 100644 --- a/gtk/gtkkineticscrolling.c +++ b/gtk/gtkkineticscrolling.c @@ -146,7 +146,8 @@ gtk_kinetic_scrolling_init_overshoot (GtkKineticScrolling *data, gboolean gtk_kinetic_scrolling_tick (GtkKineticScrolling *data, gdouble time_delta, - gdouble *position) + gdouble *position, + gdouble *velocity) { switch(data->phase) { @@ -213,6 +214,8 @@ gtk_kinetic_scrolling_tick (GtkKineticScrolling *data, if (position) *position = data->position; + if (velocity) + *velocity = data->velocity; return data->phase != GTK_KINETIC_SCROLLING_PHASE_FINISHED; } diff --git a/gtk/gtkkineticscrolling.h b/gtk/gtkkineticscrolling.h index 92883b8c1c..d00f1d05f6 100644 --- a/gtk/gtkkineticscrolling.h +++ b/gtk/gtkkineticscrolling.h @@ -36,7 +36,8 @@ void gtk_kinetic_scrolling_free (GtkKineticScrolling *kinet gboolean gtk_kinetic_scrolling_tick (GtkKineticScrolling *data, gdouble time_delta, - gdouble *position); + gdouble *position, + gdouble *velocity); G_END_DECLS diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index f17863d805..0f4193b14b 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -179,6 +179,9 @@ #define DECELERATION_FRICTION 4 #define OVERSHOOT_FRICTION 20 #define SCROLL_CAPTURE_THRESHOLD_MS 150 +#define VELOCITY_ACCUMULATION_FLOOR 0.33 +#define VELOCITY_ACCUMULATION_CEIL 1.0 +#define VELOCITY_ACCUMULATION_MAX 6.0 /* Animated scrolling */ #define ANIMATION_DURATION 200 @@ -252,6 +255,9 @@ struct _GtkScrolledWindowPrivate /* Kinetic scrolling */ GtkGesture *long_press_gesture; GtkGesture *swipe_gesture; + GtkKineticScrolling *hscrolling; + GtkKineticScrolling *vscrolling; + gint64 last_deceleration_time; GArray *scroll_history; GdkDevice *scroll_device; @@ -279,15 +285,6 @@ struct _GtkScrolledWindowPrivate gdouble unclamped_vadj_value; }; -typedef struct -{ - GtkScrolledWindow *scrolled_window; - gint64 last_deceleration_time; - - GtkKineticScrolling *hscrolling; - GtkKineticScrolling *vscrolling; -} KineticScrollData; - enum { PROP_0, PROP_HADJUSTMENT, @@ -2837,6 +2834,9 @@ gtk_scrolled_window_destroy (GtkWidget *widget) priv->deceleration_id = 0; } + g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free); + g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free); + if (priv->scroll_events_overshoot_id) { g_source_remove (priv->scroll_events_overshoot_id); @@ -3687,41 +3687,40 @@ scrolled_window_deceleration_cb (GtkWidget *widget, GdkFrameClock *frame_clock, gpointer user_data) { - KineticScrollData *data = user_data; - GtkScrolledWindow *scrolled_window = data->scrolled_window; + GtkScrolledWindow *scrolled_window = user_data; GtkScrolledWindowPrivate *priv = scrolled_window->priv; GtkAdjustment *hadjustment, *vadjustment; gint64 current_time; gdouble position, elapsed; current_time = gdk_frame_clock_get_frame_time (frame_clock); - elapsed = (current_time - data->last_deceleration_time) / 1000000.0; - data->last_deceleration_time = current_time; + elapsed = (current_time - priv->last_deceleration_time) / (double)G_TIME_SPAN_SECOND; + priv->last_deceleration_time = current_time; hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)); vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)); gtk_scrolled_window_invalidate_overshoot (scrolled_window); - if (data->hscrolling && - gtk_kinetic_scrolling_tick (data->hscrolling, elapsed, &position)) + if (priv->hscrolling && + gtk_kinetic_scrolling_tick (priv->hscrolling, elapsed, &position, NULL)) { priv->unclamped_hadj_value = position; gtk_adjustment_set_value (hadjustment, position); } - else if (data->hscrolling) - g_clear_pointer (&data->hscrolling, gtk_kinetic_scrolling_free); + else if (priv->hscrolling) + g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free); - if (data->vscrolling && - gtk_kinetic_scrolling_tick (data->vscrolling, elapsed, &position)) + if (priv->vscrolling && + gtk_kinetic_scrolling_tick (priv->vscrolling, elapsed, &position, NULL)) { priv->unclamped_vadj_value = position; gtk_adjustment_set_value (vadjustment, position); } - else if (data->vscrolling) - g_clear_pointer (&data->vscrolling, gtk_kinetic_scrolling_free); + else if (priv->vscrolling) + g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free); - if (!data->hscrolling && !data->vscrolling) + if (!priv->hscrolling && !priv->vscrolling) { gtk_scrolled_window_cancel_deceleration (scrolled_window); return G_SOURCE_REMOVE; @@ -3746,14 +3745,29 @@ gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window) } static void -kinetic_scroll_data_free (KineticScrollData *data) +kinetic_scroll_stop_notify (GtkScrolledWindow *scrolled_window) { - if (data->hscrolling) - gtk_kinetic_scrolling_free (data->hscrolling); - if (data->vscrolling) - gtk_kinetic_scrolling_free (data->vscrolling); + GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window); + priv->deceleration_id = 0; +} - g_free (data); +static void +gtk_scrolled_window_accumulate_velocity (GtkKineticScrolling **scrolling, double elapsed, double *velocity) +{ + if (!*scrolling) + return; + + double last_velocity; + gtk_kinetic_scrolling_tick (*scrolling, elapsed, NULL, &last_velocity); + if (((*velocity >= 0) == (last_velocity >= 0)) && + (fabs (*velocity) >= fabs (last_velocity) * VELOCITY_ACCUMULATION_FLOOR)) + { + double min_velocity = last_velocity * VELOCITY_ACCUMULATION_FLOOR; + double max_velocity = last_velocity * VELOCITY_ACCUMULATION_CEIL; + double accumulation_multiplier = (*velocity - min_velocity) / (max_velocity - min_velocity); + *velocity += last_velocity * fmin (accumulation_multiplier, VELOCITY_ACCUMULATION_MAX); + } + g_clear_pointer (scrolling, gtk_kinetic_scrolling_free); } static void @@ -3761,26 +3775,29 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window) { GtkScrolledWindowPrivate *priv = scrolled_window->priv; GdkFrameClock *frame_clock; - KineticScrollData *data; + gint64 current_time; + double elapsed; g_return_if_fail (priv->deceleration_id == 0); frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window)); - data = g_new0 (KineticScrollData, 1); - data->scrolled_window = scrolled_window; - data->last_deceleration_time = gdk_frame_clock_get_frame_time (frame_clock); + current_time = gdk_frame_clock_get_frame_time (frame_clock); + elapsed = (current_time - priv->last_deceleration_time) / (double)G_TIME_SPAN_SECOND; + priv->last_deceleration_time = current_time; if (may_hscroll (scrolled_window)) { gdouble lower,upper; GtkAdjustment *hadjustment; + gtk_scrolled_window_accumulate_velocity (&priv->hscrolling, elapsed, &priv->x_velocity); + hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)); lower = gtk_adjustment_get_lower (hadjustment); upper = gtk_adjustment_get_upper (hadjustment); upper -= gtk_adjustment_get_page_size (hadjustment); - data->hscrolling = + priv->hscrolling = gtk_kinetic_scrolling_new (lower, upper, MAX_OVERSHOOT_DISTANCE, @@ -3789,17 +3806,21 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window) priv->unclamped_hadj_value, priv->x_velocity); } + else + g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free); if (may_vscroll (scrolled_window)) { gdouble lower,upper; GtkAdjustment *vadjustment; + gtk_scrolled_window_accumulate_velocity (&priv->vscrolling, elapsed, &priv->y_velocity); + vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)); lower = gtk_adjustment_get_lower(vadjustment); upper = gtk_adjustment_get_upper(vadjustment); upper -= gtk_adjustment_get_page_size(vadjustment); - data->vscrolling = + priv->vscrolling = gtk_kinetic_scrolling_new (lower, upper, MAX_OVERSHOOT_DISTANCE, @@ -3808,11 +3829,13 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window) priv->unclamped_vadj_value, priv->y_velocity); } + else + g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free); scrolled_window->priv->deceleration_id = gtk_widget_add_tick_callback (GTK_WIDGET (scrolled_window), - scrolled_window_deceleration_cb, data, - (GDestroyNotify) kinetic_scroll_data_free); + scrolled_window_deceleration_cb, scrolled_window, + (GDestroyNotify) kinetic_scroll_stop_notify); } static gboolean |