Merge lp:~cimi/overlay-scrollbar/new-scrolling-modes into lp:overlay-scrollbar

Proposed by Andrea Cimitan
Status: Merged
Approved by: Ted Gould
Approved revision: 319
Merged at revision: 319
Proposed branch: lp:~cimi/overlay-scrollbar/new-scrolling-modes
Merge into: lp:overlay-scrollbar
Diff against target: 516 lines (+228/-67)
1 file modified
os/os-scrollbar.c (+228/-67)
To merge this branch: bzr merge lp:~cimi/overlay-scrollbar/new-scrolling-modes
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Review via email: mp+84294@code.launchpad.net

Description of the change

Use modifier keys (right now, control), to allow new scrolling modes.

To post a comment you must log in.
Revision history for this message
Ted Gould (ted) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'os/os-scrollbar.c'
2--- os/os-scrollbar.c 2011-11-30 21:15:01 +0000
3+++ os/os-scrollbar.c 2011-12-02 17:10:28 +0000
4@@ -46,6 +46,9 @@
5 /* Min duration of the scrolling. */
6 #define MIN_DURATION_SCROLLING 250
7
8+/* Modifier key used to slow down actions. */
9+#define MODIFIER_KEY GDK_CONTROL_MASK
10+
11 /* Timeout assumed for PropertyNotify _NET_ACTIVE_WINDOW event. */
12 #define TIMEOUT_PRESENT_WINDOW 400
13
14@@ -61,6 +64,11 @@
15 /* Timeout before hiding in ms, after leaving the toplevel. */
16 #define TIMEOUT_TOPLEVEL_HIDE 200
17
18+typedef enum {
19+ OS_SCROLL_PAGE,
20+ OS_SCROLL_STEP
21+} OsScrollType;
22+
23 typedef enum
24 {
25 OS_SIDE_TOP,
26@@ -74,10 +82,11 @@
27 OS_STATE_NONE = 0,
28 OS_STATE_CONNECTED = 1,
29 OS_STATE_DETACHED = 2,
30- OS_STATE_FULLSIZE = 4,
31- OS_STATE_INTERNAL = 8,
32- OS_STATE_LOCKED = 16,
33- OS_STATE_RECONNECTING = 32
34+ OS_STATE_FINE_SCROLL = 4,
35+ OS_STATE_FULLSIZE = 8,
36+ OS_STATE_INTERNAL = 16,
37+ OS_STATE_LOCKED = 32,
38+ OS_STATE_RECONNECTING = 64
39 } OsStateFlags;
40
41 typedef enum
42@@ -119,8 +128,9 @@
43 gboolean hidable_thumb;
44 gboolean window_button_press; /* FIXME(Cimi) to replace with X11 input events. */
45 gdouble value;
46- gint slide_initial_slider_position;
47- gint slide_initial_coordinate;
48+ gfloat fine_scroll_multiplier;
49+ gfloat slide_initial_slider_position;
50+ gfloat slide_initial_coordinate;
51 gint64 present_time;
52 guint32 source_deactivate_bar_id;
53 guint32 source_hide_thumb_id;
54@@ -171,6 +181,97 @@
55 static void os_scrollbar_dispose (GObject *object);
56 static void os_scrollbar_finalize (GObject *object);
57
58+/* Calculate slide_initial_slider_position with more precision. */
59+static void
60+calc_precise_slide_values (OsScrollbar *scrollbar,
61+ gfloat x_coordinate,
62+ gfloat y_coordinate)
63+{
64+ OsScrollbarPrivate *priv;
65+ gdouble adjustment_value;
66+
67+ priv = scrollbar->priv;
68+
69+ adjustment_value = gtk_adjustment_get_value (priv->adjustment);
70+
71+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
72+ {
73+ gdouble y1, y2, trough_length, height;
74+
75+ y1 = 0;
76+ trough_length = priv->trough.height;
77+
78+ if (gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_lower (priv->adjustment) != 0)
79+ height = (trough_length * (gtk_adjustment_get_page_size (priv->adjustment) /
80+ (gtk_adjustment_get_upper (priv->adjustment) -
81+ gtk_adjustment_get_lower (priv->adjustment))));
82+ else
83+ height = gtk_range_get_min_slider_size (GTK_RANGE (scrollbar));
84+
85+ height = MAX (height, gtk_range_get_min_slider_size (GTK_RANGE (scrollbar)));
86+
87+ if (gtk_adjustment_get_upper (priv->adjustment) -
88+ gtk_adjustment_get_lower (priv->adjustment) -
89+ gtk_adjustment_get_page_size (priv->adjustment) != 0)
90+ y1 = (trough_length - height) * ((adjustment_value - gtk_adjustment_get_lower (priv->adjustment)) /
91+ (gtk_adjustment_get_upper (priv->adjustment) -
92+ gtk_adjustment_get_lower (priv->adjustment) -
93+ gtk_adjustment_get_page_size (priv->adjustment)));
94+
95+ y2 = 0;
96+ height = priv->slider.height;
97+
98+ if (gtk_adjustment_get_upper (priv->adjustment) -
99+ gtk_adjustment_get_lower (priv->adjustment) -
100+ gtk_adjustment_get_page_size (priv->adjustment) != 0)
101+ y2 = (trough_length - height) * ((adjustment_value - gtk_adjustment_get_lower (priv->adjustment)) /
102+ (gtk_adjustment_get_upper (priv->adjustment) -
103+ gtk_adjustment_get_lower (priv->adjustment) -
104+ gtk_adjustment_get_page_size (priv->adjustment)));
105+
106+ priv->slide_initial_slider_position = CLAMP (MIN (y1, y2), 0, trough_length);
107+ priv->slide_initial_coordinate = y_coordinate;
108+ }
109+ else
110+ {
111+ gdouble x1, x2, trough_length, width;
112+
113+ x1 = 0;
114+ trough_length = priv->trough.width;
115+
116+ if (gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_lower (priv->adjustment) != 0)
117+ width = (trough_length * (gtk_adjustment_get_page_size (priv->adjustment) /
118+ (gtk_adjustment_get_upper (priv->adjustment) -
119+ gtk_adjustment_get_lower (priv->adjustment))));
120+ else
121+ width = gtk_range_get_min_slider_size (GTK_RANGE (scrollbar));
122+
123+ width = MAX (width, gtk_range_get_min_slider_size (GTK_RANGE (scrollbar)));
124+
125+ if (gtk_adjustment_get_upper (priv->adjustment) -
126+ gtk_adjustment_get_lower (priv->adjustment) -
127+ gtk_adjustment_get_page_size (priv->adjustment) != 0)
128+ x1 = (trough_length - width) * ((adjustment_value - gtk_adjustment_get_lower (priv->adjustment)) /
129+ (gtk_adjustment_get_upper (priv->adjustment) -
130+ gtk_adjustment_get_lower (priv->adjustment) -
131+ gtk_adjustment_get_page_size (priv->adjustment)));
132+
133+ x2 = 0;
134+ width = priv->slider.width;
135+
136+ if (gtk_adjustment_get_upper (priv->adjustment) -
137+ gtk_adjustment_get_lower (priv->adjustment) -
138+ gtk_adjustment_get_page_size (priv->adjustment) != 0)
139+ x2 = (trough_length - width) * ((adjustment_value - gtk_adjustment_get_lower (priv->adjustment)) /
140+ (gtk_adjustment_get_upper (priv->adjustment) -
141+ gtk_adjustment_get_lower (priv->adjustment) -
142+ gtk_adjustment_get_page_size (priv->adjustment)));
143+
144+ priv->slide_initial_slider_position = CLAMP (MIN (x1, x2), 0, trough_length);
145+ priv->slide_initial_coordinate = x_coordinate;
146+ }
147+}
148+
149 /* Calculate bar layout info. */
150 static void
151 calc_layout_bar (OsScrollbar *scrollbar,
152@@ -393,9 +494,9 @@
153 }
154
155 /* Traduce coordinates into GtkRange values. */
156-static gdouble
157+static inline gdouble
158 coord_to_value (OsScrollbar *scrollbar,
159- gint coord)
160+ gfloat coord)
161 {
162 OsScrollbarPrivate *priv;
163 gdouble frac;
164@@ -1010,6 +1111,24 @@
165
166 /* Adjustment functions. */
167
168+/* Calculate fine_scroll_multiplier. */
169+static void
170+calc_fine_scroll_multiplier (OsScrollbar *scrollbar)
171+{
172+ OsScrollbarPrivate *priv;
173+
174+ priv = scrollbar->priv;
175+
176+ /* FIXME(Cimi) Not sure about this calculation...
177+ * However seems to work "enough" well. */
178+ priv->fine_scroll_multiplier = MIN ((priv->orientation == GTK_ORIENTATION_VERTICAL ?
179+ priv->trough.height : priv->trough.width) /
180+ (gtk_adjustment_get_upper (priv->adjustment) -
181+ gtk_adjustment_get_lower (priv->adjustment) -
182+ gtk_adjustment_get_page_size (priv->adjustment)),
183+ 1);
184+}
185+
186 static void
187 adjustment_changed_cb (GtkAdjustment *adjustment,
188 gpointer user_data)
189@@ -1046,6 +1165,7 @@
190
191 calc_layout_bar (scrollbar, gtk_adjustment_get_value (adjustment));
192 calc_layout_slider (scrollbar, gtk_adjustment_get_value (adjustment));
193+ calc_fine_scroll_multiplier (scrollbar);
194
195 if (!(priv->event & OS_EVENT_ENTER_NOTIFY) &&
196 !(priv->event & OS_EVENT_MOTION_NOTIFY))
197@@ -1395,7 +1515,9 @@
198 priv->event |= OS_EVENT_BUTTON_PRESS;
199 priv->event &= ~(OS_EVENT_MOTION_NOTIFY);
200
201- if (event->button == 2)
202+ /* Middle-click or shift+left-click for "jump to" action. */
203+ if (event->button == 2 ||
204+ (event->button == 1 && (event->state & GDK_SHIFT_MASK)))
205 {
206 /* Reconnect the thumb with the bar. */
207 gdouble new_value;
208@@ -1450,16 +1572,7 @@
209 }
210 }
211
212- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
213- {
214- priv->slide_initial_slider_position = MIN (priv->slider.y, priv->overlay.y);
215- priv->slide_initial_coordinate = event->y_root;
216- }
217- else
218- {
219- priv->slide_initial_slider_position = MIN (priv->slider.x, priv->overlay.x);
220- priv->slide_initial_coordinate = event->x_root;
221- }
222+ calc_precise_slide_values (scrollbar, event->x_root, event->y_root);
223
224 priv->pointer.x = event->x;
225 priv->pointer.y = event->y;
226@@ -1469,26 +1582,32 @@
227 return FALSE;
228 }
229
230-/* Page down, with animation. */
231+/* Scroll down, with animation. */
232 static void
233-page_down (OsScrollbar *scrollbar)
234+scroll_down (OsScrollbar *scrollbar,
235+ OsScrollType scroll_type)
236 {
237 OsScrollbarPrivate *priv;
238- gdouble new_value;
239+ gdouble new_value, increment;
240 gint32 duration;
241
242 priv = scrollbar->priv;
243
244+ /* Either step down or page down. */
245+ if (scroll_type == OS_SCROLL_STEP)
246+ increment = gtk_adjustment_get_step_increment (priv->adjustment);
247+ else
248+ increment = gtk_adjustment_get_page_increment (priv->adjustment);
249+
250 /* If a scrolling animation is running,
251 * stop it and add the new value. */
252 if (os_animation_is_running (priv->animation))
253 {
254 os_animation_stop (priv->animation, NULL);
255- new_value = priv->value + gtk_adjustment_get_page_increment (priv->adjustment);
256+ new_value = priv->value + increment;
257 }
258 else
259- new_value = gtk_adjustment_get_value (priv->adjustment) +
260- gtk_adjustment_get_page_increment (priv->adjustment);
261+ new_value = gtk_adjustment_get_value (priv->adjustment) + increment;
262
263 priv->value = CLAMP (new_value,
264 gtk_adjustment_get_lower (priv->adjustment),
265@@ -1499,8 +1618,10 @@
266 return;
267
268 /* Calculate and set the duration. */
269- duration = MIN_DURATION_SCROLLING + ((priv->value - gtk_adjustment_get_value (priv->adjustment)) /
270- gtk_adjustment_get_page_increment (priv->adjustment)) *
271+ if (scroll_type == OS_SCROLL_STEP)
272+ duration = MIN_DURATION_SCROLLING;
273+ else
274+ duration = MIN_DURATION_SCROLLING + ((priv->value - gtk_adjustment_get_value (priv->adjustment)) / increment) *
275 (MAX_DURATION_SCROLLING - MIN_DURATION_SCROLLING);
276 os_animation_set_duration (priv->animation, duration);
277
278@@ -1508,26 +1629,32 @@
279 os_animation_start (priv->animation);
280 }
281
282-/* Page up, with animation. */
283+/* Scroll up, with animation. */
284 static void
285-page_up (OsScrollbar *scrollbar)
286+scroll_up (OsScrollbar *scrollbar,
287+ OsScrollType scroll_type)
288 {
289 OsScrollbarPrivate *priv;
290- gdouble new_value;
291+ gdouble new_value, increment;
292 gint32 duration;
293
294 priv = scrollbar->priv;
295
296+ /* Either step up or page up. */
297+ if (scroll_type == OS_SCROLL_STEP)
298+ increment = gtk_adjustment_get_step_increment (priv->adjustment);
299+ else
300+ increment = gtk_adjustment_get_page_increment (priv->adjustment);
301+
302 /* If a scrolling animation is running,
303 * stop it and subtract the new value. */
304 if (os_animation_is_running (priv->animation))
305 {
306 os_animation_stop (priv->animation, NULL);
307- new_value = priv->value - gtk_adjustment_get_page_increment (priv->adjustment);
308+ new_value = priv->value - increment;
309 }
310 else
311- new_value = gtk_adjustment_get_value (priv->adjustment) -
312- gtk_adjustment_get_page_increment (priv->adjustment);
313+ new_value = gtk_adjustment_get_value (priv->adjustment) - increment;
314
315 priv->value = CLAMP (new_value,
316 gtk_adjustment_get_lower (priv->adjustment),
317@@ -1538,9 +1665,11 @@
318 return;
319
320 /* Calculate and set the duration. */
321- duration = MIN_DURATION_SCROLLING + ((gtk_adjustment_get_value (priv->adjustment) - priv->value) /
322- gtk_adjustment_get_page_increment (priv->adjustment)) *
323- (MAX_DURATION_SCROLLING - MIN_DURATION_SCROLLING);
324+ if (scroll_type == OS_SCROLL_STEP)
325+ duration = MIN_DURATION_SCROLLING;
326+ else
327+ duration = MIN_DURATION_SCROLLING + ((gtk_adjustment_get_value (priv->adjustment) - priv->value) / increment) *
328+ (MAX_DURATION_SCROLLING - MIN_DURATION_SCROLLING);
329 os_animation_set_duration (priv->animation, duration);
330
331 /* Start the scrolling animation. */
332@@ -1565,22 +1694,32 @@
333
334 gtk_window_set_transient_for (GTK_WINDOW (widget), NULL);
335
336+ /* Don't trigger actions on thumb dragging or jump-to scrolling. */
337 if (event->button == 1 &&
338+ !(event->state & GDK_SHIFT_MASK) &&
339 !(priv->event & OS_EVENT_MOTION_NOTIFY))
340 {
341+ OsScrollType scroll_type;
342+
343+ /* Type of the scroll to perform. */
344+ if (event->state & MODIFIER_KEY)
345+ scroll_type = OS_SCROLL_STEP;
346+ else
347+ scroll_type = OS_SCROLL_PAGE;
348+
349 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
350 {
351 if (priv->pointer.y < priv->slider.height / 2)
352- page_up (scrollbar);
353+ scroll_up (scrollbar, scroll_type);
354 else
355- page_down (scrollbar);
356+ scroll_down (scrollbar, scroll_type);
357 }
358 else
359 {
360 if (priv->pointer.x < priv->slider.width / 2)
361- page_up (scrollbar);
362+ scroll_up (scrollbar, scroll_type);
363 else
364- page_down (scrollbar);
365+ scroll_down (scrollbar, scroll_type);
366 }
367 }
368
369@@ -1746,8 +1885,8 @@
370 gint mouse_y)
371 {
372 OsScrollbarPrivate *priv;
373+ gfloat c;
374 gint delta;
375- gint c;
376 gdouble new_value;
377
378 priv = scrollbar->priv;
379@@ -1757,7 +1896,11 @@
380 else
381 delta = mouse_x - priv->slide_initial_coordinate;
382
383- c = priv->slide_initial_slider_position + delta;
384+ /* With fine scroll, slow down the scroll. */
385+ if (priv->state & OS_STATE_FINE_SCROLL)
386+ c = priv->slide_initial_slider_position + delta * priv->fine_scroll_multiplier;
387+ else
388+ c = priv->slide_initial_slider_position + delta;
389
390 new_value = coord_to_value (scrollbar, c);
391
392@@ -1802,16 +1945,7 @@
393 if (priv->state & OS_STATE_RECONNECTING)
394 {
395 /* It's a reconnecting animation. */
396- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
397- {
398- priv->slide_initial_slider_position = MIN (priv->slider.y, priv->overlay.y);
399- priv->slide_initial_coordinate = event->y_root;
400- }
401- else
402- {
403- priv->slide_initial_slider_position = MIN (priv->slider.x, priv->overlay.x);
404- priv->slide_initial_coordinate = event->x_root;
405- }
406+ calc_precise_slide_values (scrollbar, event->x_root, event->y_root);
407 }
408 else
409 {
410@@ -1820,6 +1954,34 @@
411 }
412 }
413
414+ /* Check for modifier keys. */
415+ if (event->state & MODIFIER_KEY)
416+ {
417+ /* You pressed the modifier key for the first time,
418+ * let's deal with it. */
419+ if (!(priv->state & OS_STATE_FINE_SCROLL))
420+ {
421+ calc_fine_scroll_multiplier (scrollbar);
422+ calc_precise_slide_values (scrollbar, event->x_root, event->y_root);
423+
424+ priv->state |= OS_STATE_FINE_SCROLL;
425+ }
426+
427+ priv->state &= ~(OS_STATE_CONNECTED);
428+ }
429+ else
430+ {
431+ /* You released the modifier key for the first time,
432+ * let's deal with it. */
433+ if (priv->state & OS_STATE_FINE_SCROLL)
434+ {
435+ /* Recalculate slider positions. */
436+ calc_precise_slide_values (scrollbar, event->x_root, event->y_root);
437+
438+ priv->state &= ~(OS_STATE_FINE_SCROLL);
439+ }
440+ }
441+
442 /* Behave differently when the thumb is connected or not. */
443 if (priv->state & OS_STATE_CONNECTED)
444 {
445@@ -1867,7 +2029,7 @@
446 }
447 else
448 {
449- /* This is a fine scroll, works subtly different.
450+ /* This is a disconnected scroll, works subtly different.
451 * It has to take care of reconnection,
452 * and scrolling is not allowed when hitting an edge. */
453
454@@ -1887,7 +2049,7 @@
455 y = priv->thumb_win.y;
456 }
457
458- /* Fine scroll while detached,
459+ /* Disconnected scroll while detached,
460 * do not scroll when hitting an edge. */
461 if ((priv->orientation == GTK_ORIENTATION_VERTICAL &&
462 y > priv->thumb_win.y &&
463@@ -1905,9 +2067,10 @@
464 capture_movement (scrollbar, event->x_root, event->y_root);
465 }
466 else if (!os_animation_is_running (priv->animation) &&
467- !(priv->state & OS_STATE_DETACHED))
468+ !(priv->state & OS_STATE_DETACHED) &&
469+ !(priv->state & OS_STATE_FINE_SCROLL))
470 {
471- /* Animate scrolling till reaches the edge. */
472+ /* Animate scrolling till reaches the edge. */
473 if ((priv->orientation == GTK_ORIENTATION_VERTICAL && y <= priv->thumb_win.y) ||
474 (priv->orientation == GTK_ORIENTATION_HORIZONTAL && x <= priv->thumb_win.x))
475 priv->value = gtk_adjustment_get_lower (priv->adjustment);
476@@ -2026,7 +2189,12 @@
477 /* Stop the scrolling animation if it's running. */
478 os_animation_stop (priv->animation, NULL);
479
480- delta = get_wheel_delta (scrollbar, event->direction);
481+ /* Slow down scroll wheel with the modifier key pressed,
482+ * by a 0.2 factor. */
483+ if (event->state & MODIFIER_KEY)
484+ delta = get_wheel_delta (scrollbar, event->direction) * 0.2;
485+ else
486+ delta = get_wheel_delta (scrollbar, event->direction);
487
488 gtk_adjustment_set_value (priv->adjustment,
489 CLAMP (gtk_adjustment_get_value (priv->adjustment) + delta,
490@@ -2041,16 +2209,7 @@
491
492 /* we need to update the slide values
493 * with the current position. */
494- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
495- {
496- priv->slide_initial_slider_position = MIN (priv->slider.y, priv->overlay.y);
497- priv->slide_initial_coordinate = event->y_root;
498- }
499- else
500- {
501- priv->slide_initial_slider_position = MIN (priv->slider.x, priv->overlay.x);
502- priv->slide_initial_coordinate = event->x_root;
503- }
504+ calc_precise_slide_values (scrollbar, event->x_root, event->y_root);
505 }
506
507 return FALSE;
508@@ -2793,6 +2952,8 @@
509 priv->thumb_win.x = 0;
510 priv->thumb_win.y = 0;
511
512+ priv->fine_scroll_multiplier = 1.0;
513+
514 priv->source_deactivate_bar_id = 0;
515 priv->source_hide_thumb_id = 0;
516 priv->source_show_thumb_id = 0;

Subscribers

People subscribed via source and target branches