** requires svn jack ** Hardware monitoring should work, some canvas scrolling speed...
[ardour.git] / libs / gtkmm2ext / auto_spin.cc
1 /*
2     Copyright (C) 1999 Paul Barton-Davis 
3
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.
8
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.
13
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.
17
18     $Id$
19 */
20
21 #include <gtkmm2ext/auto_spin.h>
22 #include <cmath>
23
24 using namespace Gtkmm2ext;
25 using namespace std;
26
27 #define upper          adjustment.get_upper()
28 #define lower          adjustment.get_lower()
29 #define step_increment adjustment.get_step_increment()
30 #define page_increment adjustment.get_page_increment()
31
32 const unsigned int AutoSpin::initial_timer_interval = 500;   /* msecs */
33 const unsigned int AutoSpin::timer_interval = 20;            /* msecs */
34 const unsigned int AutoSpin::climb_timer_calls = 5;    /* between climbing */
35
36 AutoSpin::AutoSpin (Gtk::Adjustment &adjr, gfloat cr, bool round_to_steps_yn) 
37         : adjustment (adjr),
38           climb_rate (cr)
39
40 {
41         initial = adjustment.get_value();
42         left_is_decrement = true;
43         wrap = false;
44         have_timer = false;
45         need_timer = false;
46         timer_calls = 0;
47         round_to_steps = round_to_steps_yn;
48 }
49
50 void
51 AutoSpin::stop_timer ()
52 {
53         if (have_timer) {
54                 g_source_remove (timeout_tag);
55                 have_timer = false;     
56         }
57 }
58
59 gint
60 AutoSpin::stop_spinning (GdkEventButton *ev)
61 {
62         need_timer = false;
63         stop_timer ();
64         return FALSE;
65 }
66
67 gint
68 AutoSpin::button_press (GdkEventButton *ev)
69 {
70         bool shifted = false;
71         bool control = false;
72         bool with_decrement = false;
73
74         stop_spinning (0);
75
76         if (ev->state & GDK_SHIFT_MASK) {
77                 /* use page shift */
78
79                 shifted = true;
80         }
81
82         if (ev->state & GDK_CONTROL_MASK) {
83                 /* go to upper/lower bound on button1/button2 */
84
85                 control = true;
86         }
87
88         /* XXX should figure out which button is left/right */
89
90         switch (ev->button) {
91         case 1:
92                 if (control) {
93                         set_value (left_is_decrement ? lower : upper);
94                         return TRUE;
95                 } else {
96                         if (left_is_decrement) {
97                                 with_decrement = true;
98                         } else {
99                                 with_decrement = false;
100                         }
101                 }
102                 break;
103
104         case 2:
105                 if (!control) {
106                         set_value (initial);
107                 }
108                 return TRUE;
109                 break;
110
111         case 3:
112                 if (control) {
113                         set_value (left_is_decrement ? upper : lower);
114                         return TRUE;
115                 }
116                 break;
117
118         case 4:
119                 if (!control) {
120                         adjust_value (shifted ? page_increment : step_increment);
121                 } else {
122                         set_value (upper);
123                 }
124                 return TRUE;
125                 break;
126
127         case 5:
128                 if (!control) {
129                         adjust_value (shifted ? -page_increment : -step_increment);
130                 } else {
131                         set_value (lower);
132                 }
133                 return TRUE;
134                 break;
135         } 
136
137         start_spinning (with_decrement, shifted);
138         return TRUE;
139 }
140
141 void
142 AutoSpin::start_spinning (bool decrement, bool page)
143 {
144         timer_increment = page ? page_increment : step_increment;
145
146         if (decrement) { 
147                 timer_increment = -timer_increment;
148         }
149
150         adjust_value (timer_increment);
151         
152         have_timer = true;
153         timer_calls = 0;
154         timeout_tag = g_timeout_add (initial_timer_interval,
155                                        AutoSpin::_timer,
156                                        this);
157 }
158
159 gint
160 AutoSpin::_timer (void *arg)
161 {
162         return ((AutoSpin *) arg)->timer ();
163 }
164
165 void
166 AutoSpin::set_value (gfloat value)
167 {
168         if (round_to_steps)
169                 adjustment.set_value (floor((value / step_increment) + 0.5f) * step_increment);
170         else
171                 adjustment.set_value (value);
172 }
173
174 bool
175 AutoSpin::adjust_value (gfloat increment)
176 {
177         gfloat val;
178         bool done = false;
179
180         val = adjustment.get_value();
181
182         val += increment;
183
184         if (val > upper) {
185                 if (wrap) {
186                         val = lower;
187                 } else {
188                         val = upper;
189                         done = true;
190                 }
191         } else if (val < lower) {
192                 if (wrap) {
193                         val = upper;
194                 } else {
195                         val = lower;
196                         done = true;
197                 }
198         }
199
200         set_value(val);
201         return done;
202 }
203
204 gint
205 AutoSpin::timer ()
206 {
207         bool done;
208         int retval = FALSE;
209
210         done = adjust_value (timer_increment);
211
212         if (need_timer) {
213
214                 /* we're in the initial call, which happened
215                    after initial_timer_interval msecs. Now
216                    request a much more frequent update.
217                 */
218                 
219                 timeout_tag = g_timeout_add (timer_interval,
220                                                _timer,
221                                                this);
222                 have_timer = true;
223                 need_timer = false;
224
225                 /* cancel this initial timeout */
226                 
227                 retval = FALSE;
228
229         } else { 
230                 /* this is the regular "fast" call after each
231                    timer_interval msecs. 
232                 */
233
234                 if (timer_calls < climb_timer_calls) {
235                         timer_calls++;
236                 } else {
237                         if (climb_rate > 0.0) {
238                                 if (timer_increment > 0) {
239                                         timer_increment += climb_rate;
240                                 } else {
241                                         timer_increment -= climb_rate;
242                                 }
243                         }
244                         timer_calls = 0;
245                 }
246
247                 if (!done) {
248                         retval = TRUE;
249                 }
250         }
251
252         return retval;
253 }       
254
255 void
256 AutoSpin::set_bounds (gfloat init, gfloat up, gfloat down, bool with_reset)
257 {
258         adjustment.set_upper(up);
259         adjustment.set_lower(down);
260
261         initial = init;
262         
263         adjustment.changed ();
264         
265         if (with_reset) {
266                 adjustment.set_value (init);
267         }
268