From 4afda26e15369c1ff2dbbdb132438f3cfaccb529 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Mon, 24 Dec 2007 21:46:31 +0000 Subject: [PATCH] Kinetic scrolling implemented as requested in bug #461271. Thanks to David 2007-12-25 Nickolay V. Shmyrev * shell/ev-view-private.h: * shell/ev-view.c: (ev_view_drag_update_momentum), (ev_view_scroll_drag_release), (ev_view_motion_notify_event), (ev_view_button_release_event), (ev_view_destroy): Kinetic scrolling implemented as requested in bug #461271. Thanks to David Turner . svn path=/trunk/; revision=2783 --- ChangeLog | 10 +++++ shell/ev-view-private.h | 6 +++ shell/ev-view.c | 96 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 65612106..cb0830ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-12-25 Nickolay V. Shmyrev + + * shell/ev-view-private.h: + * shell/ev-view.c: (ev_view_drag_update_momentum), + (ev_view_scroll_drag_release), (ev_view_motion_notify_event), + (ev_view_button_release_event), (ev_view_destroy): + + Kinetic scrolling implemented as requested in + bug #461271. Thanks to David Turner . + 2007-12-23 Nickolay V. Shmyrev * data/evince-toolbar.xml: diff --git a/shell/ev-view-private.h b/shell/ev-view-private.h index 22bd7a0e..a2a28125 100644 --- a/shell/ev-view-private.h +++ b/shell/ev-view-private.h @@ -28,12 +28,18 @@ #include "ev-form-field.h" #include "ev-selection.h" +#define DRAG_HISTORY 10 + /* Information for middle clicking and moving around the doc */ typedef struct { gboolean in_drag; GdkPoint start; gdouble hadj; gdouble vadj; + guint drag_timeout_id; + guint release_timeout_id; + GdkPoint buffer[DRAG_HISTORY]; + GdkPoint momentum; } DragInfo; /* Autoscrolling */ diff --git a/shell/ev-view.c b/shell/ev-view.c index c4baa7c1..9782d0b1 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -2892,6 +2892,66 @@ selection_scroll_timeout_cb (EvView *view) return TRUE; } +static gboolean +ev_view_drag_update_momentum (EvView *view) +{ + int i; + if (!view->drag_info.in_drag) + return FALSE; + + for (i = DRAG_HISTORY - 1; i > 0; i--) { + view->drag_info.buffer[i].x = view->drag_info.buffer[i-1].x; + view->drag_info.buffer[i].y = view->drag_info.buffer[i-1].y; + } + + /* Momentum is a moving average of 10ms granularity over + * the last 100ms with each 10ms stored in buffer. + */ + + view->drag_info.momentum.x = (view->drag_info.buffer[DRAG_HISTORY - 1].x - view->drag_info.buffer[0].x); + view->drag_info.momentum.y = (view->drag_info.buffer[DRAG_HISTORY - 1].y - view->drag_info.buffer[0].y); + + return TRUE; +} + +static gboolean +ev_view_scroll_drag_release (EvView *view) +{ + gdouble dhadj_value, dvadj_value; + gdouble oldhadjustment, oldvadjustment; + + view->drag_info.momentum.x /= 1.2; + view->drag_info.momentum.y /= 1.2; /* Alter these constants to change "friction" */ + + dhadj_value = view->hadjustment->page_size * + (gdouble)view->drag_info.momentum.x / GTK_WIDGET (view)->allocation.width; + dvadj_value = view->vadjustment->page_size * + (gdouble)view->drag_info.momentum.y / GTK_WIDGET (view)->allocation.height; + + oldhadjustment = gtk_adjustment_get_value (view->hadjustment); + oldvadjustment = gtk_adjustment_get_value (view->vadjustment); + + if (((oldhadjustment + dhadj_value) > (view->hadjustment->upper - view->hadjustment->page_size)) || + ((oldhadjustment + dhadj_value) < 0)) + view->drag_info.momentum.x *= -0.5; /* 0.5 rather than 1 means the edges absorb some momentum */ + if (((oldvadjustment + dvadj_value) > (view->vadjustment->upper - view->vadjustment->page_size)) || + ((oldvadjustment + dvadj_value) < 0)) + view->drag_info.momentum.y *= -0.5; + + gtk_adjustment_set_value (view->hadjustment, + MIN (oldhadjustment + dhadj_value, + view->hadjustment->upper - view->hadjustment->page_size)); + gtk_adjustment_set_value (view->vadjustment, + MIN (oldvadjustment + dvadj_value, + view->vadjustment->upper - view->vadjustment->page_size)); + + if (((view->drag_info.momentum.x < 1) && (view->drag_info.momentum.x > -1)) && + ((view->drag_info.momentum.y < 1) && (view->drag_info.momentum.y > -1))) + return FALSE; + else + return TRUE; +} + static gboolean ev_view_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) @@ -2983,6 +3043,7 @@ ev_view_motion_notify_event (GtkWidget *widget, } else if (view->pressed_button == 2) { if (!view->drag_info.in_drag) { gboolean start; + int i; start = gtk_drag_check_threshold (widget, view->drag_info.start.x, @@ -2990,12 +3051,25 @@ ev_view_motion_notify_event (GtkWidget *widget, event->x_root, event->y_root); view->drag_info.in_drag = start; + view->drag_info.drag_timeout_id = g_timeout_add (10, + (GSourceFunc)ev_view_drag_update_momentum, view); + /* Set 100 to choose how long it takes to build up momentum */ + /* Clear out previous momentum info: */ + for (i = 0; i < DRAG_HISTORY; i++) { + view->drag_info.buffer[i].x = event->x; + view->drag_info.buffer[i].y = event->y; + } + view->drag_info.momentum.x = 0; + view->drag_info.momentum.y = 0; } if (view->drag_info.in_drag) { int dx, dy; gdouble dhadj_value, dvadj_value; + view->drag_info.buffer[0].x = event->x; + view->drag_info.buffer[0].y = event->y; + dx = event->x_root - view->drag_info.start.x; dy = event->y_root - view->drag_info.start.y; @@ -3033,6 +3107,9 @@ ev_view_button_release_event (GtkWidget *widget, view->drag_info.in_drag = FALSE; view->image_dnd_info.in_drag = FALSE; + + view->drag_info.release_timeout_id = g_timeout_add (20, + (GSourceFunc)ev_view_scroll_drag_release, view); if (view->pressed_button == 2) { ev_view_handle_cursor_over_xy (view, event->x, event->y); @@ -3048,10 +3125,6 @@ ev_view_button_release_event (GtkWidget *widget, g_source_remove (view->selection_scroll_id); view->selection_scroll_id = 0; } - if (view->scroll_info.timeout_id) { - g_source_remove (view->scroll_info.timeout_id); - view->scroll_info.timeout_id = 0; - } if (view->selection_update_id) { g_source_remove (view->selection_update_id); view->selection_update_id = 0; @@ -3764,6 +3837,21 @@ ev_view_destroy (GtkObject *object) view->loading_text = NULL; } + if (view->scroll_info.timeout_id) { + g_source_remove (view->scroll_info.timeout_id); + view->scroll_info.timeout_id = 0; + } + + if (view->drag_info.drag_timeout_id) { + g_source_remove (view->drag_info.drag_timeout_id); + view->drag_info.drag_timeout_id = 0; + } + + if (view->drag_info.release_timeout_id) { + g_source_remove (view->drag_info.release_timeout_id); + view->drag_info.release_timeout_id = 0; + } + ev_view_presentation_transition_stop (view); ev_view_set_scroll_adjustments (GTK_LAYOUT (view), NULL, NULL); -- 2.43.5