forked from AuroraMiddleware/gtk
scrolledwindow: Accumulate velocity with kinetic scrolling
Accumulate existing velocity when decelerating from a swipe if the swipe velocity is above a certain fraction of that existing velocity.
This commit is contained in:
parent
8ed1f51f7f
commit
4b459a99be
@ -145,7 +145,8 @@ gtk_kinetic_scrolling_init_overshoot (GtkKineticScrolling *data,
|
||||
gboolean
|
||||
gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
|
||||
double time_delta,
|
||||
double *position)
|
||||
double *position,
|
||||
double *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;
|
||||
}
|
||||
|
@ -36,7 +36,8 @@ void gtk_kinetic_scrolling_free (GtkKineticScrolling *kinet
|
||||
|
||||
gboolean gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
|
||||
double time_delta,
|
||||
double *position);
|
||||
double *position,
|
||||
double *velocity);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -184,6 +184,9 @@
|
||||
#define MAX_OVERSHOOT_DISTANCE 100
|
||||
#define DECELERATION_FRICTION 4
|
||||
#define OVERSHOOT_FRICTION 20
|
||||
#define VELOCITY_ACCUMULATION_FLOOR 0.33
|
||||
#define VELOCITY_ACCUMULATION_CEIL 1.0
|
||||
#define VELOCITY_ACCUMULATION_MAX 6.0
|
||||
|
||||
/* Animated scrolling */
|
||||
#define ANIMATION_DURATION 200
|
||||
@ -274,6 +277,9 @@ typedef struct
|
||||
/* Kinetic scrolling */
|
||||
GtkGesture *long_press_gesture;
|
||||
GtkGesture *swipe_gesture;
|
||||
GtkKineticScrolling *hscrolling;
|
||||
GtkKineticScrolling *vscrolling;
|
||||
gint64 last_deceleration_time;
|
||||
|
||||
/* These two gestures are mutually exclusive */
|
||||
GtkGesture *drag_gesture;
|
||||
@ -294,15 +300,6 @@ typedef struct
|
||||
double unclamped_vadj_value;
|
||||
} GtkScrolledWindowPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkScrolledWindow *scrolled_window;
|
||||
gint64 last_deceleration_time;
|
||||
|
||||
GtkKineticScrolling *hscrolling;
|
||||
GtkKineticScrolling *vscrolling;
|
||||
} KineticScrollData;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_HADJUSTMENT,
|
||||
@ -2578,6 +2575,9 @@ gtk_scrolled_window_dispose (GObject *object)
|
||||
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);
|
||||
@ -3193,41 +3193,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 = gtk_scrolled_window_get_instance_private (scrolled_window);
|
||||
GtkAdjustment *hadjustment, *vadjustment;
|
||||
gint64 current_time;
|
||||
double 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_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
|
||||
vadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (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;
|
||||
@ -3252,14 +3251,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
|
||||
@ -3267,26 +3281,29 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
{
|
||||
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
|
||||
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))
|
||||
{
|
||||
double lower,upper;
|
||||
GtkAdjustment *hadjustment;
|
||||
|
||||
gtk_scrolled_window_accumulate_velocity (&priv->hscrolling, elapsed, &priv->x_velocity);
|
||||
|
||||
hadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (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,
|
||||
@ -3295,17 +3312,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))
|
||||
{
|
||||
double lower,upper;
|
||||
GtkAdjustment *vadjustment;
|
||||
|
||||
gtk_scrolled_window_accumulate_velocity (&priv->vscrolling, elapsed, &priv->y_velocity);
|
||||
|
||||
vadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (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,
|
||||
@ -3314,10 +3335,12 @@ 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);
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user