304
304
TidyFingerScrollPrivate *priv = scroll->priv;
305
305
ClutterActor *child = tidy_scroll_view_get_child (TIDY_SCROLL_VIEW(scroll));
309
ClutterFixed value, lower, upper, page_size;
309
gdouble value, lower, upper, page_size;
310
310
TidyAdjustment *hadjust, *vadjust;
312
312
gboolean stop = TRUE;
314
314
tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
318
for (i = 0; i < clutter_timeline_get_delta (timeline, NULL); i++)
318
for (i = 0; i < clutter_timeline_get_delta (timeline) / 15; i++)
320
tidy_adjustment_set_valuex (hadjust,
320
tidy_adjustment_set_value (hadjust,
322
tidy_adjustment_get_valuex (hadjust));
323
tidy_adjustment_set_valuex (vadjust,
322
tidy_adjustment_get_value (hadjust));
323
tidy_adjustment_set_value (vadjust,
325
tidy_adjustment_get_valuex (vadjust));
326
priv->dx = clutter_qdivx (priv->dx, priv->decel_rate);
327
priv->dy = clutter_qdivx (priv->dy, priv->decel_rate);
325
tidy_adjustment_get_value (vadjust));
326
priv->dx = (priv->dx / priv->decel_rate);
327
priv->dy = (priv->dy / priv->decel_rate);
330
330
/* Check if we've hit the upper or lower bounds and stop the timeline */
331
tidy_adjustment_get_valuesx (hadjust, &value, &lower, &upper,
331
tidy_adjustment_get_values (hadjust, &value, &lower, &upper,
332
332
NULL, NULL, &page_size);
333
333
if (((priv->dx > 0) && (value < upper - page_size)) ||
334
334
((priv->dx < 0) && (value > lower)))
339
tidy_adjustment_get_valuesx (vadjust, &value, &lower, &upper,
339
tidy_adjustment_get_values (vadjust, &value, &lower, &upper,
340
340
NULL, NULL, &page_size);
341
341
if (((priv->dy > 0) && (value < upper - page_size)) ||
342
342
((priv->dy < 0) && (value > lower)))
348
348
clutter_timeline_stop (timeline);
400
400
TidyFingerScrollMotion *motion =
401
401
&g_array_index (priv->motion_buffer, TidyFingerScrollMotion, i);
403
403
/* FIXME: This doesn't guard against overflows - Should
404
404
* either fix that, or calculate the correct maximum
405
405
* value for the buffer size
407
408
x_origin += motion->x;
408
409
y_origin += motion->y;
409
410
motion_time.tv_sec += motion->time.tv_sec;
410
411
motion_time.tv_usec += motion->time.tv_usec;
412
x_origin = CLUTTER_UNITS_FROM_FIXED (
413
clutter_qdivx (CLUTTER_UNITS_TO_FIXED (x_origin),
414
CLUTTER_INT_TO_FIXED (priv->last_motion)));
415
y_origin = CLUTTER_UNITS_FROM_FIXED (
416
clutter_qdivx (CLUTTER_UNITS_TO_FIXED (y_origin),
417
CLUTTER_INT_TO_FIXED (priv->last_motion)));
413
x_origin /= priv->last_motion;
414
y_origin /= priv->last_motion;
418
415
motion_time.tv_sec /= priv->last_motion;
419
416
motion_time.tv_usec /= priv->last_motion;
421
418
if (motion_time.tv_sec == release_time.tv_sec)
422
419
time_diff = release_time.tv_usec - motion_time.tv_usec;
424
421
time_diff = release_time.tv_usec +
425
422
(G_USEC_PER_SEC - motion_time.tv_usec);
427
/* Work out the fraction of 1/60th of a second that has elapsed */
428
frac = clutter_qdivx (CLUTTER_FLOAT_TO_FIXED (time_diff/1000.0),
429
CLUTTER_FLOAT_TO_FIXED (1000.0/60.0));
431
/* See how many units to move in 1/60th of a second */
432
priv->dx = CLUTTER_UNITS_FROM_FIXED(clutter_qdivx (
433
CLUTTER_UNITS_TO_FIXED(x_origin - x), frac));
434
priv->dy = CLUTTER_UNITS_FROM_FIXED(clutter_qdivx (
435
CLUTTER_UNITS_TO_FIXED(y_origin - y), frac));
437
/* Get adjustments to do step-increment snapping */
438
tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
442
if (ABS(CLUTTER_UNITS_TO_INT(priv->dx)) > 1 ||
443
ABS(CLUTTER_UNITS_TO_INT(priv->dy)) > 1)
445
gdouble value, lower, step_increment, d, a, x, y, n;
447
/* TODO: Convert this all to fixed point? */
449
/* We want n, where x / y^n < z,
450
* x = Distance to move per frame
451
* y = Deceleration rate
452
* z = maximum distance from target
454
* Rearrange to n = log (x / z) / log (y)
455
* To simplify, z = 1, so n = log (x) / log (y)
457
* As z = 1, this will cause stops to be slightly abrupt -
458
* add a constant 15 frames to compensate.
460
x = CLUTTER_FIXED_TO_FLOAT (MAX(ABS(priv->dx), ABS(priv->dy)));
461
y = CLUTTER_FIXED_TO_FLOAT (priv->decel_rate);
462
n = logf (x) / logf (y) + 15.0;
464
/* Now we have n, adjust dx/dy so that we finish on a step
467
* Distance moved, using the above variable names:
469
* d = x + x/y + x/y^2 + ... + x/y^n
471
* Using geometric series,
473
* d = (1 - 1/y^(n+1))/(1 - 1/y)*x
475
* Let a = (1 - 1/y^(n+1))/(1 - 1/y),
479
* Find d and find its nearest page boundary, then solve for x
484
/* Get adjustments, work out y^n */
485
a = (1.0 - 1.0 / pow (y, n + 1)) / (1.0 - 1.0 / y);
488
d = a * CLUTTER_UNITS_TO_FLOAT (priv->dx);
489
tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
490
&step_increment, NULL, NULL);
491
d = ((rint (((value + d) - lower) / step_increment) *
492
step_increment) + lower) - value;
493
priv->dx = CLUTTER_UNITS_FROM_FLOAT (d / a);
496
d = a * CLUTTER_UNITS_TO_FLOAT (priv->dy);
497
tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
498
&step_increment, NULL, NULL);
499
d = ((rint (((value + d) - lower) / step_increment) *
500
step_increment) + lower) - value;
501
priv->dy = CLUTTER_UNITS_FROM_FLOAT (d / a);
503
priv->deceleration_timeline = clutter_timeline_new ((gint)n, 60);
507
gdouble value, lower, step_increment, d, a, y;
509
/* Start a short effects timeline to snap to the nearest step
510
* boundary (see equations above)
512
y = CLUTTER_FIXED_TO_FLOAT (priv->decel_rate);
513
a = (1.0 - 1.0 / pow (y, 4 + 1)) / (1.0 - 1.0 / y);
515
tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
516
&step_increment, NULL, NULL);
517
d = ((rint ((value - lower) / step_increment) *
518
step_increment) + lower) - value;
519
priv->dx = CLUTTER_UNITS_FROM_FLOAT (d / a);
521
tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
522
&step_increment, NULL, NULL);
523
d = ((rint ((value - lower) / step_increment) *
524
step_increment) + lower) - value;
525
priv->dy = CLUTTER_UNITS_FROM_FLOAT (d / a);
527
priv->deceleration_timeline = clutter_timeline_new (4, 60);
530
g_signal_connect (priv->deceleration_timeline, "new_frame",
531
G_CALLBACK (deceleration_new_frame_cb), scroll);
532
g_signal_connect (priv->deceleration_timeline, "completed",
533
G_CALLBACK (deceleration_completed_cb), scroll);
534
clutter_timeline_start (priv->deceleration_timeline);
424
/* On a macbook that's running Ubuntu 9.04 sometimes 'time_diff' is 0
425
and this causes a division by 0 when computing 'frac'. This check
430
/* Work out the fraction of 1/60th of a second that has elapsed */
431
frac = (time_diff/1000.0) / (1000.0/60.0);
433
/* See how many units to move in 1/60th of a second */
434
priv->dx = (x_origin - x) / frac;
435
priv->dy = (y_origin - y) / frac;
437
/* Get adjustments to do step-increment snapping */
438
tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
442
if (ABS(priv->dx) > 1 ||
445
gdouble value, lower, step_increment, d, a, x, y, n;
447
/* TODO: Convert this all to fixed point? */
449
/* We want n, where x / y n < z,
450
* x = Distance to move per frame
451
* y = Deceleration rate
452
* z = maximum distance from target
454
* Rearrange to n = log (x / z) / log (y)
455
* To simplify, z = 1, so n = log (x) / log (y)
457
* As z = 1, this will cause stops to be slightly abrupt -
458
* add a constant 15 frames to compensate.
460
x = MAX(ABS(priv->dx), ABS(priv->dy));
461
y = priv->decel_rate;
462
n = logf (x) / logf (y) + 15.0;
464
/* Now we have n, adjust dx/dy so that we finish on a step
467
* Distance moved, using the above variable names:
469
* d = x + x/y + x/y 2 + ... + x/y n
471
* Using geometric series,
473
* d = (1 - 1/y (n+1))/(1 - 1/y)*x
475
* Let a = (1 - 1/y (n+1))/(1 - 1/y),
479
* Find d and find its nearest page boundary, then solve for x
484
/* Get adjustments, work out y n */
485
a = (1.0 - 1.0 / pow (y, n + 1)) / (1.0 - 1.0 / y);
489
tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
490
&step_increment, NULL, NULL);
491
d = ((rint (((value + d) - lower) / step_increment) *
492
step_increment) + lower) - value;
497
tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
498
&step_increment, NULL, NULL);
499
d = ((rint (((value + d) - lower) / step_increment) *
500
step_increment) + lower) - value;
503
priv->deceleration_timeline = clutter_timeline_new ((n / 60) * 1000.0);
507
gdouble value, lower, step_increment, d, a, y;
509
/* Start a short effects timeline to snap to the nearest step
510
* boundary (see equations above)
512
y = priv->decel_rate;
513
a = (1.0 - 1.0 / pow (y, 4 + 1)) / (1.0 - 1.0 / y);
515
tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
516
&step_increment, NULL, NULL);
517
d = ((rint ((value - lower) / step_increment) *
518
step_increment) + lower) - value;
521
tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
522
&step_increment, NULL, NULL);
523
d = ((rint ((value - lower) / step_increment) *
524
step_increment) + lower) - value;
527
priv->deceleration_timeline = clutter_timeline_new (250);
530
g_signal_connect (priv->deceleration_timeline, "new_frame",
531
G_CALLBACK (deceleration_new_frame_cb), scroll);
532
g_signal_connect (priv->deceleration_timeline, "completed",
533
G_CALLBACK (deceleration_completed_cb), scroll);
534
clutter_timeline_start (priv->deceleration_timeline);