kineticscrolling: use computed frame times
Instead of accumulating a series of doubles, use the actual computed frame time for duration tracking. While there is extremely low chance of aliasing with animations under a few seconds, this just ensures we're using the same clocking inside and outside of GtkKineticScrolling.
This commit is contained in:
@@ -70,18 +70,20 @@ struct _GtkKineticScrolling
|
||||
double c2;
|
||||
double equilibrium_position;
|
||||
|
||||
double t;
|
||||
gint64 t;
|
||||
double position;
|
||||
double velocity;
|
||||
};
|
||||
|
||||
static void gtk_kinetic_scrolling_init_overshoot (GtkKineticScrolling *data,
|
||||
gint64 frame_time,
|
||||
double equilibrium_position,
|
||||
double initial_position,
|
||||
double initial_velocity);
|
||||
|
||||
GtkKineticScrolling *
|
||||
gtk_kinetic_scrolling_new (double lower,
|
||||
gtk_kinetic_scrolling_new (gint64 frame_time,
|
||||
double lower,
|
||||
double upper,
|
||||
double overshoot_width,
|
||||
double decel_friction,
|
||||
@@ -96,16 +98,18 @@ gtk_kinetic_scrolling_new (double lower,
|
||||
data->upper = upper;
|
||||
data->decel_friction = decel_friction;
|
||||
data->overshoot_friction = overshoot_friction;
|
||||
if(initial_position < lower)
|
||||
if (initial_position < lower)
|
||||
{
|
||||
gtk_kinetic_scrolling_init_overshoot (data,
|
||||
frame_time,
|
||||
lower,
|
||||
initial_position,
|
||||
initial_velocity);
|
||||
}
|
||||
else if(initial_position > upper)
|
||||
else if (initial_position > upper)
|
||||
{
|
||||
gtk_kinetic_scrolling_init_overshoot (data,
|
||||
frame_time,
|
||||
upper,
|
||||
initial_position,
|
||||
initial_velocity);
|
||||
@@ -115,9 +119,9 @@ gtk_kinetic_scrolling_new (double lower,
|
||||
data->phase = GTK_KINETIC_SCROLLING_PHASE_DECELERATING;
|
||||
data->c1 = initial_velocity / decel_friction + initial_position;
|
||||
data->c2 = -initial_velocity / decel_friction;
|
||||
data->t = 0;
|
||||
data->position = initial_position;
|
||||
data->velocity = initial_velocity;
|
||||
data->t = frame_time;
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -160,6 +164,7 @@ gtk_kinetic_scrolling_free (GtkKineticScrolling *kinetic)
|
||||
|
||||
static void
|
||||
gtk_kinetic_scrolling_init_overshoot (GtkKineticScrolling *data,
|
||||
gint64 frame_time,
|
||||
double equilibrium_position,
|
||||
double initial_position,
|
||||
double initial_velocity)
|
||||
@@ -168,36 +173,36 @@ gtk_kinetic_scrolling_init_overshoot (GtkKineticScrolling *data,
|
||||
data->equilibrium_position = equilibrium_position;
|
||||
data->c1 = initial_position - equilibrium_position;
|
||||
data->c2 = initial_velocity + data->overshoot_friction / 2 * data->c1;
|
||||
data->t = 0;
|
||||
data->t = frame_time;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
|
||||
double time_delta,
|
||||
gint64 frame_time,
|
||||
double *position,
|
||||
double *velocity)
|
||||
{
|
||||
switch(data->phase)
|
||||
double t = (frame_time - data->t) / (double)G_USEC_PER_SEC;
|
||||
|
||||
switch (data->phase)
|
||||
{
|
||||
case GTK_KINETIC_SCROLLING_PHASE_DECELERATING:
|
||||
{
|
||||
double exp_part;
|
||||
|
||||
data->t += time_delta;
|
||||
|
||||
exp_part = exp (-data->decel_friction * data->t);
|
||||
exp_part = exp (-data->decel_friction * t);
|
||||
data->position = data->c1 + data->c2 * exp_part;
|
||||
data->velocity = -data->decel_friction * data->c2 * exp_part;
|
||||
|
||||
if(data->position < data->lower)
|
||||
if (data->position < data->lower)
|
||||
{
|
||||
gtk_kinetic_scrolling_init_overshoot(data,data->lower,data->position,data->velocity);
|
||||
gtk_kinetic_scrolling_init_overshoot (data, frame_time, data->lower, data->position, data->velocity);
|
||||
}
|
||||
else if (data->position > data->upper)
|
||||
{
|
||||
gtk_kinetic_scrolling_init_overshoot(data, data->upper, data->position, data->velocity);
|
||||
gtk_kinetic_scrolling_init_overshoot (data, frame_time, data->upper, data->position, data->velocity);
|
||||
}
|
||||
else if (fabs(data->velocity) < 0.1)
|
||||
else if (fabs (data->velocity) < 0.1)
|
||||
{
|
||||
gtk_kinetic_scrolling_stop (data);
|
||||
}
|
||||
@@ -208,21 +213,20 @@ gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
|
||||
{
|
||||
double exp_part, pos;
|
||||
|
||||
data->t += time_delta;
|
||||
exp_part = exp(-data->overshoot_friction / 2 * data->t);
|
||||
pos = exp_part * (data->c1 + data->c2 * data->t);
|
||||
exp_part = exp (-data->overshoot_friction / 2 * t);
|
||||
pos = exp_part * (data->c1 + data->c2 * t);
|
||||
|
||||
if (pos < data->lower - 50 || pos > data->upper + 50)
|
||||
{
|
||||
pos = CLAMP (pos, data->lower - 50, data->upper + 50);
|
||||
gtk_kinetic_scrolling_init_overshoot (data, data->equilibrium_position, pos, 0);
|
||||
gtk_kinetic_scrolling_init_overshoot (data, frame_time, data->equilibrium_position, pos, 0);
|
||||
}
|
||||
else
|
||||
data->velocity = data->c2 * exp_part - data->overshoot_friction / 2 * pos;
|
||||
|
||||
data->position = pos + data->equilibrium_position;
|
||||
|
||||
if(fabs (pos) < 0.1)
|
||||
if (fabs (pos) < 0.1)
|
||||
{
|
||||
data->phase = GTK_KINETIC_SCROLLING_PHASE_FINISHED;
|
||||
data->position = data->equilibrium_position;
|
||||
|
||||
@@ -31,7 +31,8 @@ typedef enum {
|
||||
|
||||
typedef struct _GtkKineticScrolling GtkKineticScrolling;
|
||||
|
||||
GtkKineticScrolling * gtk_kinetic_scrolling_new (double lower,
|
||||
GtkKineticScrolling * gtk_kinetic_scrolling_new (gint64 frame_time,
|
||||
double lower,
|
||||
double upper,
|
||||
double overshoot_width,
|
||||
double decel_friction,
|
||||
@@ -45,7 +46,7 @@ GtkKineticScrollingChange gtk_kinetic_scrolling_update_size (GtkKineticScrolling
|
||||
double upper);
|
||||
|
||||
gboolean gtk_kinetic_scrolling_tick (GtkKineticScrolling *data,
|
||||
double time_delta,
|
||||
gint64 frame_time,
|
||||
double *position,
|
||||
double *velocity);
|
||||
|
||||
|
||||
@@ -3263,11 +3263,10 @@ scrolled_window_deceleration_cb (GtkWidget *widget,
|
||||
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
|
||||
GtkAdjustment *hadjustment, *vadjustment;
|
||||
gint64 current_time;
|
||||
double position, elapsed;
|
||||
double position;
|
||||
gboolean retval = G_SOURCE_REMOVE;
|
||||
|
||||
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;
|
||||
|
||||
hadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
|
||||
@@ -3276,7 +3275,7 @@ scrolled_window_deceleration_cb (GtkWidget *widget,
|
||||
gtk_scrolled_window_invalidate_overshoot (scrolled_window);
|
||||
|
||||
if (priv->hscrolling &&
|
||||
gtk_kinetic_scrolling_tick (priv->hscrolling, elapsed, &position, NULL))
|
||||
gtk_kinetic_scrolling_tick (priv->hscrolling, current_time, &position, NULL))
|
||||
{
|
||||
priv->unclamped_hadj_value = position;
|
||||
gtk_adjustment_set_value (hadjustment, position);
|
||||
@@ -3284,7 +3283,7 @@ scrolled_window_deceleration_cb (GtkWidget *widget,
|
||||
}
|
||||
|
||||
if (priv->vscrolling &&
|
||||
gtk_kinetic_scrolling_tick (priv->vscrolling, elapsed, &position, NULL))
|
||||
gtk_kinetic_scrolling_tick (priv->vscrolling, current_time, &position, NULL))
|
||||
{
|
||||
priv->unclamped_vadj_value = position;
|
||||
gtk_adjustment_set_value (vadjustment, position);
|
||||
@@ -3320,13 +3319,15 @@ kinetic_scroll_stop_notify (GtkScrolledWindow *scrolled_window)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scrolled_window_accumulate_velocity (GtkKineticScrolling **scrolling, double elapsed, double *velocity)
|
||||
gtk_scrolled_window_accumulate_velocity (GtkKineticScrolling **scrolling,
|
||||
gint64 current_time,
|
||||
double *velocity)
|
||||
{
|
||||
if (!*scrolling)
|
||||
return;
|
||||
|
||||
double last_velocity;
|
||||
gtk_kinetic_scrolling_tick (*scrolling, elapsed, NULL, &last_velocity);
|
||||
gtk_kinetic_scrolling_tick (*scrolling, current_time, NULL, &last_velocity);
|
||||
if (((*velocity >= 0) == (last_velocity >= 0)) &&
|
||||
(fabs (*velocity) >= fabs (last_velocity) * VELOCITY_ACCUMULATION_FLOOR))
|
||||
{
|
||||
@@ -3344,7 +3345,6 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
|
||||
GdkFrameClock *frame_clock;
|
||||
gint64 current_time;
|
||||
double elapsed;
|
||||
int overshoot_x, overshoot_y;
|
||||
|
||||
g_return_if_fail (priv->deceleration_id == 0);
|
||||
@@ -3352,7 +3352,6 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window));
|
||||
|
||||
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;
|
||||
|
||||
_gtk_scrolled_window_get_overshoot (scrolled_window, &overshoot_x, &overshoot_y);
|
||||
@@ -3362,7 +3361,7 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
double lower,upper;
|
||||
GtkAdjustment *hadjustment;
|
||||
|
||||
gtk_scrolled_window_accumulate_velocity (&priv->hscrolling, elapsed, &priv->x_velocity);
|
||||
gtk_scrolled_window_accumulate_velocity (&priv->hscrolling, current_time, &priv->x_velocity);
|
||||
g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free);
|
||||
|
||||
if (priv->x_velocity != 0 || overshoot_x != 0)
|
||||
@@ -3372,7 +3371,8 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
upper = gtk_adjustment_get_upper (hadjustment);
|
||||
upper -= gtk_adjustment_get_page_size (hadjustment);
|
||||
priv->hscrolling =
|
||||
gtk_kinetic_scrolling_new (lower,
|
||||
gtk_kinetic_scrolling_new (current_time,
|
||||
lower,
|
||||
upper,
|
||||
MAX_OVERSHOOT_DISTANCE,
|
||||
DECELERATION_FRICTION,
|
||||
@@ -3389,7 +3389,7 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
double lower,upper;
|
||||
GtkAdjustment *vadjustment;
|
||||
|
||||
gtk_scrolled_window_accumulate_velocity (&priv->vscrolling, elapsed, &priv->y_velocity);
|
||||
gtk_scrolled_window_accumulate_velocity (&priv->vscrolling, current_time, &priv->y_velocity);
|
||||
g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free);
|
||||
|
||||
if (priv->y_velocity != 0 || overshoot_y != 0)
|
||||
@@ -3399,7 +3399,8 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
upper = gtk_adjustment_get_upper(vadjustment);
|
||||
upper -= gtk_adjustment_get_page_size(vadjustment);
|
||||
priv->vscrolling =
|
||||
gtk_kinetic_scrolling_new (lower,
|
||||
gtk_kinetic_scrolling_new (current_time,
|
||||
lower,
|
||||
upper,
|
||||
MAX_OVERSHOOT_DISTANCE,
|
||||
DECELERATION_FRICTION,
|
||||
|
||||
Reference in New Issue
Block a user