Zoom session when the mouse pointer is moved up and down during a playhead drag.
[ardour2.git] / libs / gtkmm2ext / auto_spin.cc
blob5ab8852adfff03286f9764bf0b561aea83c20ec3
1 /*
2 Copyright (C) 1999 Paul Barton-Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 $Id$
21 #include <cmath>
22 #include "gtkmm2ext/auto_spin.h"
23 #include "gtkmm2ext/keyboard.h"
25 using namespace Gtkmm2ext;
26 using namespace std;
28 #define upper adjustment.get_upper()
29 #define lower adjustment.get_lower()
30 #define step_increment adjustment.get_step_increment()
31 #define page_increment adjustment.get_page_increment()
33 const unsigned int AutoSpin::initial_timer_interval = 500; /* msecs */
34 const unsigned int AutoSpin::timer_interval = 20; /* msecs */
35 const unsigned int AutoSpin::climb_timer_calls = 5; /* between climbing */
37 AutoSpin::AutoSpin (Gtk::Adjustment &adjr, gfloat cr, bool round_to_steps_yn)
38 : adjustment (adjr),
39 climb_rate (cr)
42 initial = adjustment.get_value();
43 left_is_decrement = true;
44 wrap = false;
45 have_timer = false;
46 need_timer = false;
47 timer_calls = 0;
48 round_to_steps = round_to_steps_yn;
51 void
52 AutoSpin::stop_timer ()
54 if (have_timer) {
55 g_source_remove (timeout_tag);
56 have_timer = false;
60 gint
61 AutoSpin::stop_spinning (GdkEventButton */*ev*/)
63 need_timer = false;
64 stop_timer ();
65 return FALSE;
68 gint
69 AutoSpin::button_press (GdkEventButton *ev)
71 bool shifted = false;
72 bool control = false;
73 bool with_decrement = false;
75 stop_spinning (0);
77 if (ev->state & Keyboard::TertiaryModifier) {
78 /* use page shift */
80 shifted = true;
83 if (ev->state & Keyboard::PrimaryModifier) {
84 /* go to upper/lower bound on button1/button2 */
86 control = true;
89 /* XXX should figure out which button is left/right */
91 switch (ev->button) {
92 case 1:
93 if (control) {
94 set_value (left_is_decrement ? lower : upper);
95 return TRUE;
96 } else {
97 if (left_is_decrement) {
98 with_decrement = true;
99 } else {
100 with_decrement = false;
103 break;
105 case 2:
106 if (!control) {
107 set_value (initial);
109 return TRUE;
110 break;
112 case 3:
113 if (control) {
114 set_value (left_is_decrement ? upper : lower);
115 return TRUE;
117 break;
119 case 4:
120 if (!control) {
121 adjust_value (shifted ? page_increment : step_increment);
122 } else {
123 set_value (upper);
125 return TRUE;
126 break;
128 case 5:
129 if (!control) {
130 adjust_value (shifted ? -page_increment : -step_increment);
131 } else {
132 set_value (lower);
134 return TRUE;
135 break;
138 start_spinning (with_decrement, shifted);
139 return TRUE;
142 void
143 AutoSpin::start_spinning (bool decrement, bool page)
145 timer_increment = page ? page_increment : step_increment;
147 if (decrement) {
148 timer_increment = -timer_increment;
151 adjust_value (timer_increment);
153 have_timer = true;
154 timer_calls = 0;
155 timeout_tag = g_timeout_add (initial_timer_interval,
156 AutoSpin::_timer,
157 this);
160 gint
161 AutoSpin::_timer (void *arg)
163 return ((AutoSpin *) arg)->timer ();
166 void
167 AutoSpin::set_value (gfloat value)
169 if (round_to_steps)
170 adjustment.set_value (floor((value / step_increment) + 0.5f) * step_increment);
171 else
172 adjustment.set_value (value);
175 bool
176 AutoSpin::adjust_value (gfloat increment)
178 gfloat val;
179 bool done = false;
181 val = adjustment.get_value();
183 val += increment;
185 if (val > upper) {
186 if (wrap) {
187 val = lower;
188 } else {
189 val = upper;
190 done = true;
192 } else if (val < lower) {
193 if (wrap) {
194 val = upper;
195 } else {
196 val = lower;
197 done = true;
201 set_value(val);
202 return done;
205 gint
206 AutoSpin::timer ()
208 bool done;
209 int retval = FALSE;
211 done = adjust_value (timer_increment);
213 if (need_timer) {
215 /* we're in the initial call, which happened
216 after initial_timer_interval msecs. Now
217 request a much more frequent update.
220 timeout_tag = g_timeout_add (timer_interval,
221 _timer,
222 this);
223 have_timer = true;
224 need_timer = false;
226 /* cancel this initial timeout */
228 retval = FALSE;
230 } else {
231 /* this is the regular "fast" call after each
232 timer_interval msecs.
235 if (timer_calls < climb_timer_calls) {
236 timer_calls++;
237 } else {
238 if (climb_rate > 0.0) {
239 if (timer_increment > 0) {
240 timer_increment += climb_rate;
241 } else {
242 timer_increment -= climb_rate;
245 timer_calls = 0;
248 if (!done) {
249 retval = TRUE;
253 return retval;
256 void
257 AutoSpin::set_bounds (gfloat init, gfloat up, gfloat down, bool with_reset)
259 adjustment.set_upper(up);
260 adjustment.set_lower(down);
262 initial = init;
264 adjustment.changed ();
266 if (with_reset) {
267 adjustment.set_value (init);