updated .po files, with new plural forms
[ardour.git] / gtk2_ardour / shuttle_control.cc
1 /*
2     Copyright (C) 2011 Paul 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
19 #include <algorithm>
20
21 #include <cairo/cairo.h>
22
23 #include "ardour/ardour.h"
24 #include "ardour/audioengine.h"
25 #include "ardour/rc_configuration.h"
26 #include "ardour/session.h"
27
28 #include "gtkmm2ext/keyboard.h"
29 #include "gtkmm2ext/gui_thread.h"
30 #include "gtkmm2ext/cairocell.h"
31 #include "gtkmm2ext/utils.h"
32 #include "gtkmm2ext/rgb_macros.h"
33
34 #include "ardour_ui.h"
35 #include "rgb_macros.h"
36 #include "shuttle_control.h"
37
38 #include "i18n.h"
39
40 using namespace Gtk;
41 using namespace Gtkmm2ext;
42 using namespace ARDOUR;
43 using std::min;
44 using std::max;
45
46 gboolean qt (gboolean, gint, gint, gboolean, Gtk::Tooltip*, gpointer)
47 {
48         return FALSE;
49 }
50
51 ShuttleControl::ShuttleControl ()
52         : _controllable (new ShuttleControllable (*this))
53         , binding_proxy (_controllable)
54 {
55         ARDOUR_UI::instance()->set_tip (*this, _("Shuttle speed control (Context-click for options)"));
56
57         pattern = 0;
58         shine_pattern = 0;
59         last_shuttle_request = 0;
60         last_speed_displayed = -99999999;
61         shuttle_grabbed = false;
62         shuttle_speed_on_grab = 0;
63         shuttle_fract = 0.0;
64         shuttle_max_speed = 8.0f;
65         shuttle_style_menu = 0;
66         shuttle_unit_menu = 0;
67         shuttle_context_menu = 0;
68         _hovering = false;
69
70         set_flags (CAN_FOCUS);
71         add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
72         set_size_request (85, 20);
73         set_name (X_("ShuttleControl"));
74
75         Config->ParameterChanged.connect (parameter_connection, MISSING_INVALIDATOR, boost::bind (&ShuttleControl::parameter_changed, this, _1), gui_context());
76
77         /* gtkmm 2.4: the C++ wrapper doesn't work */
78         g_signal_connect ((GObject*) gobj(), "query-tooltip", G_CALLBACK (qt), NULL);
79         // signal_query_tooltip().connect (sigc::mem_fun (*this, &ShuttleControl::on_query_tooltip));
80 }
81
82 ShuttleControl::~ShuttleControl ()
83 {
84         cairo_pattern_destroy (pattern);
85         cairo_pattern_destroy (shine_pattern);
86 }
87
88 void
89 ShuttleControl::set_session (Session *s)
90 {
91         SessionHandlePtr::set_session (s);
92
93         if (_session) {
94                 set_sensitive (true);
95                 _session->add_controllable (_controllable);
96         } else {
97                 set_sensitive (false);
98         }
99 }
100
101 void
102 ShuttleControl::on_size_allocate (Gtk::Allocation& alloc)
103 {
104         if (pattern) {
105                 cairo_pattern_destroy (pattern);
106                 pattern = 0;
107                 cairo_pattern_destroy (shine_pattern);
108                 shine_pattern = 0;
109         }
110
111         CairoWidget::on_size_allocate ( alloc);
112
113         //background
114         pattern = cairo_pattern_create_linear (0, 0, 0, alloc.get_height());
115         uint32_t col = ARDOUR_UI::config()->canvasvar_Shuttle.get();
116         int r,b,g,a;
117         UINT_TO_RGBA(col, &r, &g, &b, &a);
118         cairo_pattern_add_color_stop_rgb (pattern, 0.0, r/400.0, g/400.0, b/400.0);
119         cairo_pattern_add_color_stop_rgb (pattern, 0.4, r/255.0, g/255.0, b/255.0);
120         cairo_pattern_add_color_stop_rgb (pattern, 1.0, r/512.0, g/512.0, b/512.0);
121
122         //reflection
123         shine_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, 10);
124         cairo_pattern_add_color_stop_rgba (shine_pattern, 0, 1,1,1,0.0);
125         cairo_pattern_add_color_stop_rgba (shine_pattern, 0.2, 1,1,1,0.4);
126         cairo_pattern_add_color_stop_rgba (shine_pattern, 1, 1,1,1,0.1);
127 }
128
129 void
130 ShuttleControl::map_transport_state ()
131 {
132         float speed = _session->transport_speed ();
133
134         if (fabs(speed) <= (2*DBL_EPSILON)) {
135                 shuttle_fract = 0;
136         } else {
137                 if (Config->get_shuttle_units() == Semitones) {
138                         bool reverse;
139                         int semi = speed_as_semitones (speed, reverse);
140                         shuttle_fract = semitones_as_fract (semi, reverse);
141                 } else {
142                         shuttle_fract = speed/shuttle_max_speed;
143                 }
144         }
145
146         queue_draw ();
147 }
148
149 void
150 ShuttleControl::build_shuttle_context_menu ()
151 {
152         using namespace Menu_Helpers;
153
154         shuttle_context_menu = new Menu();
155         MenuList& items = shuttle_context_menu->items();
156
157         Menu* speed_menu = manage (new Menu());
158         MenuList& speed_items = speed_menu->items();
159
160         Menu* units_menu = manage (new Menu);
161         MenuList& units_items = units_menu->items();
162         RadioMenuItem::Group units_group;
163
164         units_items.push_back (RadioMenuElem (units_group, _("Percent"), sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_units), Percentage)));
165         if (Config->get_shuttle_units() == Percentage) {
166                 static_cast<RadioMenuItem*>(&units_items.back())->set_active();
167         }
168         units_items.push_back (RadioMenuElem (units_group, _("Semitones"), sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_units), Semitones)));
169         if (Config->get_shuttle_units() == Semitones) {
170                 static_cast<RadioMenuItem*>(&units_items.back())->set_active();
171         }
172         items.push_back (MenuElem (_("Units"), *units_menu));
173
174         Menu* style_menu = manage (new Menu);
175         MenuList& style_items = style_menu->items();
176         RadioMenuItem::Group style_group;
177
178         style_items.push_back (RadioMenuElem (style_group, _("Sprung"), sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_style), Sprung)));
179         if (Config->get_shuttle_behaviour() == Sprung) {
180                 static_cast<RadioMenuItem*>(&style_items.back())->set_active();
181         }
182         style_items.push_back (RadioMenuElem (style_group, _("Wheel"), sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_style), Wheel)));
183         if (Config->get_shuttle_behaviour() == Wheel) {
184                 static_cast<RadioMenuItem*>(&style_items.back())->set_active();
185         }
186
187         items.push_back (MenuElem (_("Mode"), *style_menu));
188
189         RadioMenuItem::Group speed_group;
190
191         speed_items.push_back (RadioMenuElem (speed_group, "8", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 8.0f)));
192         if (shuttle_max_speed == 8.0) {
193                 static_cast<RadioMenuItem*>(&speed_items.back())->set_active ();
194         }
195         speed_items.push_back (RadioMenuElem (speed_group, "6", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 6.0f)));
196         if (shuttle_max_speed == 6.0) {
197                 static_cast<RadioMenuItem*>(&speed_items.back())->set_active ();
198         }
199         speed_items.push_back (RadioMenuElem (speed_group, "4", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 4.0f)));
200         if (shuttle_max_speed == 4.0) {
201                 static_cast<RadioMenuItem*>(&speed_items.back())->set_active ();
202         }
203         speed_items.push_back (RadioMenuElem (speed_group, "3", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 3.0f)));
204         if (shuttle_max_speed == 3.0) {
205                 static_cast<RadioMenuItem*>(&speed_items.back())->set_active ();
206         }
207         speed_items.push_back (RadioMenuElem (speed_group, "2", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 2.0f)));
208         if (shuttle_max_speed == 2.0) {
209                 static_cast<RadioMenuItem*>(&speed_items.back())->set_active ();
210         }
211         speed_items.push_back (RadioMenuElem (speed_group, "1.5", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 1.5f)));
212         if (shuttle_max_speed == 1.5) {
213                 static_cast<RadioMenuItem*>(&speed_items.back())->set_active ();
214         }
215
216         items.push_back (MenuElem (_("Maximum speed"), *speed_menu));
217
218 }
219
220 void
221 ShuttleControl::show_shuttle_context_menu ()
222 {
223         if (shuttle_context_menu == 0) {
224                 build_shuttle_context_menu ();
225         }
226
227         shuttle_context_menu->popup (1, gtk_get_current_event_time());
228 }
229
230 void
231 ShuttleControl::set_shuttle_max_speed (float speed)
232 {
233         shuttle_max_speed = speed;
234 }
235
236 bool
237 ShuttleControl::on_button_press_event (GdkEventButton* ev)
238 {
239         if (!_session) {
240                 return true;
241         }
242
243         if (binding_proxy.button_press_handler (ev)) {
244                 return true;
245         }
246
247         if (Keyboard::is_context_menu_event (ev)) {
248                 show_shuttle_context_menu ();
249                 return true;
250         }
251
252         switch (ev->button) {
253         case 1:
254                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
255                         if (_session->transport_rolling()) {
256                                 _session->request_transport_speed (1.0);
257                         }
258                 } else {
259                         add_modal_grab ();
260                         shuttle_grabbed = true;
261                         shuttle_speed_on_grab = _session->transport_speed ();
262                         mouse_shuttle (ev->x, true);
263                         gdk_pointer_grab(ev->window,false,
264                                         GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
265                                         NULL,NULL,ev->time);
266                 }
267                 break;
268
269         case 2:
270         case 3:
271                 return true;
272                 break;
273         }
274
275         return true;
276 }
277
278 bool
279 ShuttleControl::on_button_release_event (GdkEventButton* ev)
280 {
281         if (!_session) {
282                 return true;
283         }
284
285         switch (ev->button) {
286         case 1:
287                 if (shuttle_grabbed) {
288                         shuttle_grabbed = false;
289                         remove_modal_grab ();
290                         gdk_pointer_ungrab (GDK_CURRENT_TIME);
291                         
292                         if (Config->get_shuttle_behaviour() == Sprung) {
293                                 if (shuttle_speed_on_grab == 0 ) {
294                                         _session->request_transport_speed (1.0);
295                                 }
296                                 _session->request_transport_speed (shuttle_speed_on_grab);
297                         } else {
298                                 mouse_shuttle (ev->x, true);
299                         }
300                 }
301                 return true;
302
303         case 2:
304                 if (_session->transport_rolling()) {
305                         _session->request_transport_speed (1.0, Config->get_shuttle_behaviour() == Wheel);
306                 }
307                 return true;
308
309         case 3:
310         default:
311                 return true;
312
313         }
314
315         return true;
316 }
317
318 bool
319 ShuttleControl::on_query_tooltip (int, int, bool, const Glib::RefPtr<Gtk::Tooltip>&)
320 {
321         return false;
322 }
323
324 bool
325 ShuttleControl::on_scroll_event (GdkEventScroll* ev)
326 {
327         if (!_session || Config->get_shuttle_behaviour() != Wheel) {
328                 return true;
329         }
330
331         bool semis = (Config->get_shuttle_units() == Semitones);
332
333         switch (ev->direction) {
334         case GDK_SCROLL_UP:
335         case GDK_SCROLL_RIGHT:
336                 if (semis) {
337                         if (shuttle_fract == 0) {
338                                 shuttle_fract = semitones_as_fract (1, false);
339                         } else {
340                                 bool rev;
341                                 int st = fract_as_semitones (shuttle_fract, rev);
342                                 shuttle_fract = semitones_as_fract (st + 1, rev);
343                         }
344                 } else {
345                         shuttle_fract += 0.00125;
346                 }
347                 break;
348         case GDK_SCROLL_DOWN:
349         case GDK_SCROLL_LEFT:
350                 if (semis) {
351                         if (shuttle_fract == 0) {
352                                 shuttle_fract = semitones_as_fract (1, true);
353                         } else {
354                                 bool rev;
355                                 int st = fract_as_semitones (shuttle_fract, rev);
356                                 shuttle_fract = semitones_as_fract (st - 1, rev);
357                         }
358                 } else {
359                         shuttle_fract -= 0.00125;
360                 }
361                 break;
362         default:
363                 return false;
364         }
365         
366         if (semis) {
367
368                 float lower_side_of_dead_zone = semitones_as_fract (-24, true);
369                 float upper_side_of_dead_zone = semitones_as_fract (-24, false);
370
371                 /* if we entered the "dead zone" (-24 semitones in forward or reverse), jump
372                    to the far side of it.
373                 */
374
375                 if (shuttle_fract > lower_side_of_dead_zone && shuttle_fract < upper_side_of_dead_zone) {
376                         switch (ev->direction) {
377                         case GDK_SCROLL_UP:
378                         case GDK_SCROLL_RIGHT:
379                                 shuttle_fract = upper_side_of_dead_zone;
380                                 break;
381                         case GDK_SCROLL_DOWN:
382                         case GDK_SCROLL_LEFT:
383                                 shuttle_fract = lower_side_of_dead_zone;
384                                 break;
385                         default:
386                                 /* impossible, checked above */
387                                 return false;
388                         }
389                 }
390         }
391
392         use_shuttle_fract (true);
393
394         return true;
395 }
396
397 bool
398 ShuttleControl::on_motion_notify_event (GdkEventMotion* ev)
399 {
400         if (!_session || !shuttle_grabbed) {
401                 return true;
402         }
403
404         return mouse_shuttle (ev->x, false);
405 }
406
407 gint
408 ShuttleControl::mouse_shuttle (double x, bool force)
409 {
410         double const center = get_width() / 2.0;
411         double distance_from_center = x - center;
412
413         if (distance_from_center > 0) {
414                 distance_from_center = min (distance_from_center, center);
415         } else {
416                 distance_from_center = max (distance_from_center, -center);
417         }
418
419         /* compute shuttle fract as expressing how far between the center
420            and the edge we are. positive values indicate we are right of
421            center, negative values indicate left of center
422         */
423
424         shuttle_fract = distance_from_center / center; // center == half the width
425         use_shuttle_fract (force);
426         return true;
427 }
428
429 void
430 ShuttleControl::set_shuttle_fract (double f)
431 {
432         shuttle_fract = f;
433         use_shuttle_fract (false);
434 }
435
436 int
437 ShuttleControl::speed_as_semitones (float speed, bool& reverse)
438 {
439         assert (speed != 0.0);
440
441         if (speed < 0.0) {
442                 reverse = true;
443                 return (int) round (12.0 * fast_log2 (-speed));
444         } else {
445                 reverse = false;
446                 return (int) round (12.0 * fast_log2 (speed));
447         }
448 }
449
450 float
451 ShuttleControl::semitones_as_speed (int semi, bool reverse)
452 {
453         if (reverse) {
454                 return -pow (2.0, (semi / 12.0));
455         } else {
456                 return pow (2.0, (semi / 12.0));
457         }
458 }
459
460 float
461 ShuttleControl::semitones_as_fract (int semi, bool reverse)
462 {
463         float speed = semitones_as_speed (semi, reverse);
464         return speed/4.0; /* 4.0 is the maximum speed for a 24 semitone shift */
465 }
466
467 int
468 ShuttleControl::fract_as_semitones (float fract, bool& reverse)
469 {
470         assert (fract != 0.0);
471         return speed_as_semitones (fract * 4.0, reverse);
472 }
473
474 void
475 ShuttleControl::use_shuttle_fract (bool force)
476 {
477         microseconds_t now = get_microseconds();
478
479         shuttle_fract = max (-1.0f, shuttle_fract);
480         shuttle_fract = min (1.0f, shuttle_fract);
481
482         /* do not attempt to submit a motion-driven transport speed request
483            more than once per process cycle.
484         */
485
486         if (!force && (last_shuttle_request - now) < (microseconds_t) AudioEngine::instance()->usecs_per_cycle()) {
487                 return;
488         }
489
490         last_shuttle_request = now;
491
492         double speed = 0;
493
494         if (Config->get_shuttle_units() == Semitones) {
495                 if (shuttle_fract != 0.0) {
496                         bool reverse;
497                         int semi = fract_as_semitones (shuttle_fract, reverse);
498                         speed = semitones_as_speed (semi, reverse);
499                 } else {
500                         speed = 0.0;
501                 }
502         } else {
503                 speed = shuttle_max_speed * shuttle_fract;
504         }
505
506         _session->request_transport_speed_nonzero (speed, Config->get_shuttle_behaviour() == Wheel);
507 }
508
509 void
510 ShuttleControl::render (cairo_t* cr)
511 {
512         cairo_text_extents_t extents;
513
514         //black border
515         cairo_set_source_rgb (cr, 0, 0.0, 0.0);
516         rounded_rectangle (cr, 0, 0, get_width(), get_height(), 4);
517 //      cairo_fill_preserve (cr);
518 //      cairo_stroke (cr);
519         cairo_fill (cr);
520
521         float speed = 0.0;
522
523         if (_session) {
524                 speed = _session->transport_speed ();
525         }
526
527         /* Marker */
528         float visual_fraction = std::min (1.0f, speed/shuttle_max_speed);
529         float marker_size = get_height()-4;
530         float avail_width = get_width() - marker_size;
531         float x = get_width()*0.5 + visual_fraction * avail_width*0.5;
532         float offset = x - marker_size*0.5;
533 //      cairo_set_source_rgb (cr, 0, 1, 0.0);
534         cairo_set_source (cr, pattern);
535         if (speed == 1.0) {
536                 cairo_move_to( cr, offset-4, 2);
537                 cairo_line_to( cr, offset+4, 2+marker_size*0.5);
538                 cairo_line_to( cr, offset-4, 2+marker_size);
539                 cairo_line_to( cr, offset-4, 2);
540         } else if ( speed ==0.0 )
541                 rounded_rectangle (cr, offset, 4, marker_size-2, marker_size-2, 1);
542         else
543                 cairo_arc (cr, offset + marker_size*0.5, 2 + marker_size*0.5, marker_size*0.5, 0, 360);
544         cairo_set_line_width (cr, 2);
545         cairo_stroke (cr);
546
547         /* speed text */
548
549         char buf[32];
550
551         if (speed != 0) {
552
553                 if (Config->get_shuttle_units() == Percentage) {
554
555                         if (speed == 1.0) {
556                                 snprintf (buf, sizeof (buf), "%s", _("Playing"));
557                         } else {
558                                 if (speed < 0.0) {
559                                         snprintf (buf, sizeof (buf), "<<< %d%%", (int) round (-speed * 100));
560                                 } else {
561                                         snprintf (buf, sizeof (buf), ">>> %d%%", (int) round (speed * 100));
562                                 }
563                         }
564
565                 } else {
566
567                         bool reversed;
568                         int semi = speed_as_semitones (speed, reversed);
569
570                         if (reversed) {
571                                 snprintf (buf, sizeof (buf), _("<<< %+d semitones"), semi);
572                         } else {
573                                 snprintf (buf, sizeof (buf), _(">>> %+d semitones"), semi);
574                         }
575                 }
576
577         } else {
578                 snprintf (buf, sizeof (buf), "%s", _("Stopped"));
579         }
580
581         last_speed_displayed = speed;
582
583         cairo_set_source_rgb (cr, 0.6, 0.6, 0.6);
584         cairo_text_extents (cr, buf, &extents);
585         cairo_move_to (cr, 10, extents.height + 4);
586         cairo_set_font_size (cr, 13.0);
587         cairo_show_text (cr, buf);
588
589         /* style text */
590
591
592         switch (Config->get_shuttle_behaviour()) {
593         case Sprung:
594                 snprintf (buf, sizeof (buf), "%s", _("Sprung"));
595                 break;
596         case Wheel:
597                 snprintf (buf, sizeof (buf), "%s", _("Wheel"));
598                 break;
599         }
600
601         cairo_text_extents (cr, buf, &extents);
602         cairo_move_to (cr, get_width() - (fabs(extents.x_advance) + 5), extents.height + 4);
603         cairo_show_text (cr, buf);
604
605         float _corner_radius = 4.0;
606
607 /*      //reflection
608         float rheight = 10.0;
609         Gtkmm2ext::rounded_rectangle (cr, 2, 1, get_width()-4, rheight, _corner_radius);
610         cairo_set_source (cr, shine_pattern);
611         cairo_fill (cr);
612 */
613         if (ARDOUR::Config->get_widget_prelight()) {
614                 if (_hovering) {
615                         rounded_rectangle (cr, 1, 1, get_width()-2, get_height()-2, _corner_radius);
616                         cairo_set_source_rgba (cr, 1, 1, 1, 0.2);
617                         cairo_fill (cr);
618                 }
619         }
620 }
621
622 void
623 ShuttleControl::shuttle_unit_clicked ()
624 {
625         if (shuttle_unit_menu == 0) {
626                 shuttle_unit_menu = dynamic_cast<Menu*> (ActionManager::get_widget ("/ShuttleUnitPopup"));
627         }
628         shuttle_unit_menu->popup (1, gtk_get_current_event_time());
629 }
630
631 void
632 ShuttleControl::set_shuttle_style (ShuttleBehaviour s)
633 {
634         Config->set_shuttle_behaviour (s);
635 }
636
637 void
638 ShuttleControl::set_shuttle_units (ShuttleUnits s)
639 {
640         Config->set_shuttle_units (s);
641 }
642
643 void
644 ShuttleControl::update_speed_display ()
645 {
646         if (_session->transport_speed() != last_speed_displayed) {
647                 queue_draw ();
648         }
649 }
650
651 ShuttleControl::ShuttleControllable::ShuttleControllable (ShuttleControl& s)
652         : PBD::Controllable (X_("Shuttle"))
653         , sc (s)
654 {
655 }
656
657 void
658 ShuttleControl::ShuttleControllable::set_value (double val)
659 {
660         double fract;
661
662         if (val == 0.5) {
663                 fract = 0.0;
664         } else {
665                 if (val < 0.5) {
666                         fract = -((0.5 - val)/0.5);
667                 } else {
668                         fract = ((val - 0.5)/0.5);
669                 }
670         }
671
672         sc.set_shuttle_fract (fract);
673 }
674
675 double
676 ShuttleControl::ShuttleControllable::get_value () const
677 {
678         return sc.get_shuttle_fract ();
679 }
680
681 void
682 ShuttleControl::parameter_changed (std::string p)
683 {
684         if (p == "shuttle-behaviour") {
685                 switch (Config->get_shuttle_behaviour ()) {
686                 case Sprung:
687                         /* back to Sprung - reset to speed = 1.0 if playing
688                          */
689                         if (_session) {
690                                 if (_session->transport_rolling()) {
691                                         if (_session->transport_speed() == 1.0) {
692                                                 queue_draw ();
693                                         } else {
694                                                 /* reset current speed and
695                                                    revert to 1.0 as the default
696                                                 */
697                                                 _session->request_transport_speed (1.0);
698                                                 /* redraw when speed changes */
699                                         }
700                                 } else {
701                                         queue_draw ();
702                                 }
703                         }
704                         break;
705
706                 case Wheel:
707                         queue_draw ();
708                         break;
709                 }
710
711         } else if (p == "shuttle-units") {
712                 queue_draw ();
713         }
714 }
715
716
717 bool
718 ShuttleControl::on_enter_notify_event (GdkEventCrossing* ev)
719 {
720         _hovering = true;
721
722         if (ARDOUR::Config->get_widget_prelight()) {
723                 queue_draw ();
724         }
725
726         return CairoWidget::on_enter_notify_event (ev);
727 }
728
729 bool
730 ShuttleControl::on_leave_notify_event (GdkEventCrossing* ev)
731 {
732         _hovering = false;
733
734         if (ARDOUR::Config->get_widget_prelight()) {
735                 queue_draw ();
736         }
737
738         return CairoWidget::on_leave_notify_event (ev);
739 }