[gtk+] Add autoscroll when dragging past boundary of range
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Add autoscroll when dragging past boundary of range
- Date: Mon, 5 Aug 2013 06:48:10 +0000 (UTC)
commit 8c7a8e9314f4cdef015611a9d9cad2fd21d4f2b4
Author: William Jon McCann <william jon mccann gmail com>
Date: Mon Jul 29 12:06:20 2013 -0400
Add autoscroll when dragging past boundary of range
A problem with the zoom scroll mode is that you have to restart
if you hit the bottom of the screen before you hit the bottom
of your document.
This commit adds an autoscroll feature to the zoom scroll: if
you move outside the window while in zoom scroll mode, we keep
scrolling in the direction you were going until you let go
of the mouse button.
https://bugzilla.gnome.org/show_bug.cgi?id=704703
gtk/gtkrange.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 119 insertions(+), 13 deletions(-)
---
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index f99c309..aff4ff3 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -64,6 +64,7 @@
#define TIMEOUT_INITIAL 500
#define TIMEOUT_REPEAT 50
#define ZOOM_HOLD_TIME 500
+#define AUTOSCROLL_FACTOR 20
typedef struct _GtkRangeStepTimer GtkRangeStepTimer;
@@ -116,7 +117,7 @@ struct _GtkRangePrivate
gint n_marks;
gint round_digits; /* Round off value to this many digits, -1 for no rounding */
gint slide_initial_slider_position;
- gint slide_initial_coordinate;
+ gint slide_initial_coordinate_delta;
gint slider_start; /* Slider range along the long dimension, in widget->window coords */
gint slider_end;
@@ -146,6 +147,8 @@ struct _GtkRangePrivate
guint zoom : 1;
guint zoom_set : 1;
GtkPressAndHold *press_and_hold;
+ GtkScrollType autoscroll_mode;
+ guint autoscroll_id;
/* Fill level */
guint show_fill_level : 1;
@@ -2536,8 +2539,8 @@ gtk_range_key_press (GtkWidget *widget,
stop_scrolling (range);
update_slider_position (range,
- priv->slide_initial_coordinate,
- priv->slide_initial_coordinate);
+ priv->slide_initial_coordinate_delta + priv->slide_initial_slider_position,
+ priv->slide_initial_coordinate_delta + priv->slide_initial_slider_position);
return TRUE;
}
@@ -2732,12 +2735,12 @@ gtk_range_button_press (GtkWidget *widget,
if (priv->orientation == GTK_ORIENTATION_VERTICAL)
{
priv->slide_initial_slider_position = priv->slider.y;
- priv->slide_initial_coordinate = event->y;
+ priv->slide_initial_coordinate_delta = event->y - priv->slider.y;
}
else
{
priv->slide_initial_slider_position = priv->slider.x;
- priv->slide_initial_coordinate = event->x;
+ priv->slide_initial_coordinate_delta = event->x - priv->slider.x;
}
range_grab_add (range, device, MOUSE_SLIDER, event->button);
@@ -2770,11 +2773,6 @@ update_slider_position (GtkRange *range,
gdouble zoom;
gint i;
- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
- delta = mouse_y - priv->slide_initial_coordinate;
- else
- delta = mouse_x - priv->slide_initial_coordinate;
-
if (priv->zoom)
{
zoom = MIN(1.0, (priv->orientation == GTK_ORIENTATION_VERTICAL ?
@@ -2789,6 +2787,20 @@ update_slider_position (GtkRange *range,
else
zoom = 1.0;
+ /* recalculate the initial position from the current position */
+ if (priv->slide_initial_slider_position == -1)
+ {
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ priv->slide_initial_slider_position = (zoom * (mouse_y - priv->slide_initial_coordinate_delta) -
priv->slider.y) / (zoom - 1.0);
+ else
+ priv->slide_initial_slider_position = (zoom * (mouse_x - priv->slide_initial_coordinate_delta) -
priv->slider.x) / (zoom - 1.0);
+ }
+
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ delta = mouse_y - (priv->slide_initial_coordinate_delta + priv->slide_initial_slider_position);
+ else
+ delta = mouse_x - (priv->slide_initial_coordinate_delta + priv->slide_initial_slider_position);
+
c = priv->slide_initial_slider_position + zoom * delta;
new_value = coord_to_value (range, c);
@@ -2814,10 +2826,66 @@ update_slider_position (GtkRange *range,
}
static void
+remove_autoscroll (GtkRange *range)
+{
+ if (range->priv->autoscroll_id)
+ {
+ gtk_widget_remove_tick_callback (GTK_WIDGET (range),
+ range->priv->autoscroll_id);
+ range->priv->autoscroll_id = 0;
+ }
+
+ /* unset initial position so it can be calculated */
+ range->priv->slide_initial_slider_position = -1;
+
+ range->priv->autoscroll_mode = GTK_SCROLL_NONE;
+}
+
+static gboolean
+autoscroll_cb (GtkWidget *widget,
+ GdkFrameClock *frame_clock,
+ gpointer data)
+{
+ GtkRange *range;
+ gdouble increment;
+ gdouble value;
+ gboolean handled;
+
+ range = GTK_RANGE (data);
+
+ increment = gtk_adjustment_get_step_increment (range->priv->adjustment) / AUTOSCROLL_FACTOR;
+ if (range->priv->autoscroll_mode == GTK_SCROLL_STEP_BACKWARD)
+ increment *= -1;
+
+ value = gtk_adjustment_get_value (range->priv->adjustment);
+ value += increment;
+ g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, value,
+ &handled);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+add_autoscroll (GtkRange *range)
+{
+ GtkRangePrivate *priv = range->priv;
+
+ if (priv->autoscroll_id != 0
+ || priv->autoscroll_mode == GTK_SCROLL_NONE)
+ return;
+
+ priv->autoscroll_id = gtk_widget_add_tick_callback (GTK_WIDGET (range),
+ (GtkTickCallback)autoscroll_cb,
+ range,
+ NULL);
+}
+
+static void
stop_scrolling (GtkRange *range)
{
range_grab_remove (range);
gtk_range_remove_step_timer (range);
+ remove_autoscroll (range);
}
static gboolean
@@ -2873,13 +2941,12 @@ gtk_range_button_release (GtkWidget *widget,
{
if (priv->grab_location == MOUSE_SLIDER)
{
- update_slider_position (range, priv->mouse_x, priv->mouse_y);
if (priv->press_and_hold)
gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event);
}
stop_scrolling (range);
-
+
return TRUE;
}
@@ -2962,6 +3029,43 @@ gtk_range_scroll_event (GtkWidget *widget,
return TRUE;
}
+static void
+update_autoscroll_mode (GtkRange *range)
+{
+ GtkScrollType mode = GTK_SCROLL_NONE;
+
+ if (range->priv->zoom)
+ {
+ GtkAllocation allocation;
+ gint size, pos;
+
+ gtk_widget_get_allocation (GTK_WIDGET (range), &allocation);
+
+ if (range->priv->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ size = allocation.height;
+ pos = range->priv->mouse_y;
+ }
+ else
+ {
+ size = allocation.width;
+ pos = range->priv->mouse_x;
+ }
+
+ if (pos < 0)
+ mode = GTK_SCROLL_STEP_BACKWARD;
+ else if (pos > size)
+ mode = GTK_SCROLL_STEP_FORWARD;
+ }
+
+ if (mode != range->priv->autoscroll_mode)
+ {
+ remove_autoscroll (range);
+ range->priv->autoscroll_mode = mode;
+ add_autoscroll (range);
+ }
+}
+
static gboolean
gtk_range_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
@@ -2982,7 +3086,9 @@ gtk_range_motion_notify (GtkWidget *widget,
if (!priv->zoom_set && priv->press_and_hold != NULL)
gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event);
- update_slider_position (range, event->x, event->y);
+ update_autoscroll_mode (range);
+ if (priv->autoscroll_mode == GTK_SCROLL_NONE)
+ update_slider_position (range, event->x, event->y);
}
/* We handled the event if the mouse was in the range_rect */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]