rename all GTK signals
[ardour.git] / gtk2_ardour / ardour_ui2.cc
1 /*
2     Copyright (C) 1999 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     $Id$
19 */
20
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <cerrno>
25 #include <iostream>
26 #include <cmath>
27
28 #include <gtkmm.h>
29 #include <pbd/error.h>
30 #include <pbd/basename.h>
31 #include <pbd/fastlog.h>
32 #include <gtkmm2ext/pix.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/click_box.h>
35 #include <gtkmm2ext/tearoff.h>
36
37 #include <ardour/audioengine.h>
38 #include <ardour/ardour.h>
39 #include <ardour/route.h>
40
41 #include "ardour_ui.h"
42 #include "public_editor.h"
43 #include "audio_clock.h"
44 #include "extra_bind.h"
45
46 #include "i18n.h"
47
48 using namespace std;
49 using namespace ARDOUR;
50 using namespace Gtkmm2ext;
51 using namespace Gtk;
52 using namespace sigc;
53
54 int     
55 ARDOUR_UI::setup_windows ()
56 {
57         using namespace Menu_Helpers;
58
59         if (create_editor ()) {
60                 error << _("UI: cannot setup editor") << endmsg;
61                 return -1;
62         }
63
64         if (create_mixer ()) {
65                 error << _("UI: cannot setup mixer") << endmsg;
66                 return -1;
67         }
68
69         if (create_meter_bridge ()) {
70                 error << _("UI: cannot setup meter_bridge") << endmsg;
71                 return -1;
72         }
73
74         /* all other dialogs are created conditionally */
75
76         we_have_dependents ();
77
78         setup_clock ();
79         setup_transport();
80         setup_adjustables ();
81         build_menu_bar ();
82
83         top_packer.pack_start (menu_bar_base, false, false);
84         top_packer.pack_start (transport_frame, false, false);
85
86         editor->add_toplevel_controls (top_packer);
87
88         return 0;
89 }
90
91
92 void
93 ARDOUR_UI::setup_adjustables ()
94
95 {
96         adjuster_table.set_homogeneous (true);
97
98         online_control_strings.push_back (_("MMC + Local"));
99         online_control_strings.push_back (_("MMC"));
100         online_control_strings.push_back (_("Local"));
101
102         online_control_button = new GlobalClickBox ("CONTROL",
103                                                     online_control_strings);
104
105         online_control_button->adjustment.value_changed.connect(mem_fun(*this,&ARDOUR_UI::control_methods_adjusted));
106
107         mmc_id_strings.push_back ("1");
108         mmc_id_strings.push_back ("2");
109         mmc_id_strings.push_back ("3");
110         mmc_id_strings.push_back ("4");
111         mmc_id_strings.push_back ("5");
112         mmc_id_strings.push_back ("6");
113         mmc_id_strings.push_back ("7");
114         mmc_id_strings.push_back ("8");
115         mmc_id_strings.push_back ("9");
116
117         mmc_id_button = new GlobalClickBox (_("MMC ID"), mmc_id_strings);
118
119         mmc_id_button->adjustment.value_changed.connect (mem_fun(*this,&ARDOUR_UI::mmc_device_id_adjusted));
120
121         adjuster_table.attach (*online_control_button, 0, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, 0, 5, 5);
122         adjuster_table.attach (*mmc_id_button, 2, 3, 1, 2, 0, 0, 5, 5);
123 }
124
125 #include "transport_xpms"
126
127 void
128 ARDOUR_UI::transport_stopped ()
129 {
130         roll_button.set_active (false);
131         play_selection_button.set_active (false);
132         auto_loop_button.set_active (false);
133
134         shuttle_fract = 0;
135         shuttle_box.queue_draw ();
136
137         update_disk_space ();
138 }
139
140 static const double SHUTTLE_FRACT_SPEED1=0.48412291827; /* derived from A1,A2 */
141
142 void
143 ARDOUR_UI::transport_rolling ()
144 {
145         if (session->get_play_range()) {
146
147                 play_selection_button.set_active (true);
148                 roll_button.set_active (false);
149                 auto_loop_button.set_active (false);
150
151         } else if (session->get_auto_loop ()) {
152
153                 auto_loop_button.set_active (true);
154                 play_selection_button.set_active (false);
155                 roll_button.set_active (false);
156
157         } else {
158
159                 roll_button.set_active (true);
160                 play_selection_button.set_active (false);
161                 auto_loop_button.set_active (false);
162         }
163
164         /* reset shuttle controller */
165
166         shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
167         shuttle_box.queue_draw ();
168 }
169
170 void
171 ARDOUR_UI::transport_rewinding ()
172 {
173         roll_button.set_active (true);
174         play_selection_button.set_active (false);
175         auto_loop_button.set_active (false);
176 }
177
178 void
179 ARDOUR_UI::transport_forwarding ()
180 {
181         roll_button.set_active (true);
182         play_selection_button.set_active (false);
183         auto_loop_button.set_active (false);
184 }
185
186 void
187 ARDOUR_UI::setup_transport ()
188 {
189         transport_tearoff = manage (new TearOff (transport_tearoff_hbox));
190         transport_tearoff->set_name ("TransportBase");
191
192         transport_hbox.pack_start (*transport_tearoff, true, false);
193
194         transport_base.set_name ("TransportBase");
195         transport_base.add (transport_hbox);
196
197         transport_frame.set_shadow_type (Gtk::SHADOW_OUT);
198         transport_frame.set_name ("BaseFrame");
199         transport_frame.add (transport_base);
200
201         transport_tearoff->Detach.connect (bind (mem_fun(*this, &ARDOUR_UI::detach_tearoff), static_cast<Gtk::Box*>(&top_packer), 
202                                                  static_cast<Gtk::Widget*>(&transport_frame)));
203         transport_tearoff->Attach.connect (bind (mem_fun(*this, &ARDOUR_UI::reattach_tearoff), static_cast<Gtk::Box*> (&top_packer), 
204                                                  static_cast<Gtk::Widget*> (&transport_frame), 1));
205
206
207         goto_start_button.add (*(manage (new Gtk::Image (start_xpm))));
208         goto_end_button.add (*(manage (new Gtk::Image (end_xpm))));
209         roll_button.add (*(manage (new Gtk::Image (arrow_xpm))));
210         stop_button.add (*(manage (new Gtk::Image (stop_xpm))));
211         play_selection_button.add (*(manage (new Gtk::Image (play_selection_xpm))));
212         rec_button.add (*(manage (new Gtk::Image (rec_xpm))));
213         auto_loop_button.add (*(manage (new Gtk::Image (loop_xpm))));
214
215         ARDOUR_UI::instance()->tooltips().set_tip (roll_button, _("Play from playhead"));
216         ARDOUR_UI::instance()->tooltips().set_tip (stop_button, _("Stop playback"));
217         ARDOUR_UI::instance()->tooltips().set_tip (play_selection_button, _("Play range/selection"));
218         ARDOUR_UI::instance()->tooltips().set_tip (goto_start_button, _("Go to start of session"));
219         ARDOUR_UI::instance()->tooltips().set_tip (goto_end_button, _("Go to end of session"));
220         ARDOUR_UI::instance()->tooltips().set_tip (auto_loop_button, _("Play loop range"));
221         ARDOUR_UI::instance()->tooltips().set_tip (auto_return_button, _("Return to last playback start when stopped"));
222         ARDOUR_UI::instance()->tooltips().set_tip (auto_play_button, _("Start playback after any locate"));
223         ARDOUR_UI::instance()->tooltips().set_tip (auto_input_button, _("Be sensible about input monitoring"));
224         ARDOUR_UI::instance()->tooltips().set_tip (punch_in_button, _("Start recording at auto-punch start"));
225         ARDOUR_UI::instance()->tooltips().set_tip (punch_out_button, _("Stop recording at auto-punch end"));
226         ARDOUR_UI::instance()->tooltips().set_tip (click_button, _("Enable/Disable audio click"));
227         ARDOUR_UI::instance()->tooltips().set_tip (follow_button, _("Enable/Disable follow playhead"));
228         ARDOUR_UI::instance()->tooltips().set_tip (shuttle_box, _("Shuttle speed control"));
229         ARDOUR_UI::instance()->tooltips().set_tip (shuttle_units_button, _("Select semitones or %%-age for speed display"));
230         ARDOUR_UI::instance()->tooltips().set_tip (shuttle_style_button, _("Select sprung or wheel behaviour"));
231         ARDOUR_UI::instance()->tooltips().set_tip (speed_display_box, _("Current transport speed"));
232         
233         shuttle_box.set_flags (Gtk::CAN_FOCUS);
234         shuttle_box.signal_set_events (shuttle_box.signal_get_events() | GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::POINTER_MOTION_MASK);
235         shuttle_box.set_size_request (100, 15);
236
237         shuttle_box.set_name ("TransportButton");
238         goto_start_button.set_name ("TransportButton");
239         goto_end_button.set_name ("TransportButton");
240         roll_button.set_name ("TransportButton");
241         stop_button.set_name ("TransportButton");
242         play_selection_button.set_name ("TransportButton");
243         rec_button.set_name ("TransportRecButton");
244         auto_loop_button.set_name ("TransportButton");
245         auto_return_button.set_name ("TransportButton");
246         auto_play_button.set_name ("TransportButton");
247         auto_input_button.set_name ("TransportButton");
248         punch_in_button.set_name ("TransportButton");
249         punch_out_button.set_name ("TransportButton");
250         click_button.set_name ("TransportButton");
251         follow_button.set_name ("TransportButton");
252         
253         goto_start_button.unset_flags (Gtk::CAN_FOCUS);
254         goto_end_button.unset_flags (Gtk::CAN_FOCUS);
255         roll_button.unset_flags (Gtk::CAN_FOCUS);
256         stop_button.unset_flags (Gtk::CAN_FOCUS);
257         play_selection_button.unset_flags (Gtk::CAN_FOCUS);
258         rec_button.unset_flags (Gtk::CAN_FOCUS);
259         auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
260         auto_return_button.unset_flags (Gtk::CAN_FOCUS);
261         auto_play_button.unset_flags (Gtk::CAN_FOCUS);
262         auto_input_button.unset_flags (Gtk::CAN_FOCUS);
263         punch_out_button.unset_flags (Gtk::CAN_FOCUS);
264         punch_in_button.unset_flags (Gtk::CAN_FOCUS);
265         click_button.unset_flags (Gtk::CAN_FOCUS);
266         follow_button.unset_flags (Gtk::CAN_FOCUS);
267         
268         goto_start_button.signal_set_events (goto_start_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
269         goto_end_button.signal_set_events (goto_end_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
270         roll_button.signal_set_events (roll_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
271         stop_button.signal_set_events (stop_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
272         play_selection_button.signal_set_events (play_selection_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
273         rec_button.signal_set_events (rec_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
274         auto_loop_button.signal_set_events (auto_loop_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
275         auto_return_button.signal_set_events (auto_return_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
276         auto_play_button.signal_set_events (auto_play_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
277         auto_input_button.signal_set_events (auto_input_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
278         click_button.signal_set_events (click_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
279         follow_button.signal_set_events (click_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
280         punch_in_button.signal_set_events (punch_in_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
281         punch_out_button.signal_set_events (punch_out_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
282
283         goto_start_button.signal_clicked().connect (mem_fun(*this,&ARDOUR_UI::transport_goto_start));
284         goto_end_button.signal_clicked().connect (mem_fun(*this,&ARDOUR_UI::transport_goto_end));
285
286         roll_button.signal_button_release_event.connect (mem_fun(*this,&ARDOUR_UI::mouse_transport_roll));
287         play_selection_button.signal_button_release_event.connect (mem_fun(*this,&ARDOUR_UI::mouse_transport_play_selection));
288         auto_loop_button.signal_button_release_event.connect (mem_fun(*this,&ARDOUR_UI::mouse_transport_loop));
289
290         stop_button.signal_button_release_event.connect (mem_fun(*this,&ARDOUR_UI::mouse_transport_stop));
291         rec_button.signal_button_release_event.connect (mem_fun(*this,&ARDOUR_UI::mouse_transport_record));
292
293         shuttle_box.signal_signal_button_press_event.connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_button_press));
294         shuttle_box.signal_signal_button_release_event.connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_button_release));
295         shuttle_box.signal_signal_motion_notify_event.connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_motion));
296         shuttle_box.signal_signal_expose_event.connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_expose));
297
298         /* clocks, etc. */
299
300         ARDOUR_UI::Clock.connect (bind (mem_fun (primary_clock, &AudioClock::set), false));
301         ARDOUR_UI::Clock.connect (bind (mem_fun (secondary_clock, &AudioClock::set), false));
302
303         primary_clock.set_mode (AudioClock::SMPTE);
304         primary_clock.set_name ("TransportClockDisplay");
305         secondary_clock.set_mode (AudioClock::BBT);
306         secondary_clock.set_name ("TransportClockDisplay");
307
308
309         primary_clock.ValueChanged.connect (mem_fun(*this, &ARDOUR_UI::primary_clock_value_changed));
310         secondary_clock.ValueChanged.connect (mem_fun(*this, &ARDOUR_UI::secondary_clock_value_changed));
311
312         ARDOUR_UI::instance()->tooltips().set_tip (primary_clock, _("Primary clock"));
313         ARDOUR_UI::instance()->tooltips().set_tip (secondary_clock, _("secondary clock"));
314
315         /* options */
316
317         auto_return_button.toggled.connect (mem_fun(*this,&ARDOUR_UI::toggle_auto_return));
318         auto_play_button.toggled.connect (mem_fun(*this,&ARDOUR_UI::toggle_auto_play));
319         auto_input_button.toggled.connect (mem_fun(*this,&ARDOUR_UI::toggle_auto_input));
320         click_button.toggled.connect (mem_fun(*this,&ARDOUR_UI::toggle_click));
321         follow_button.toggled.connect (mem_fun(*this,&ARDOUR_UI::toggle_follow));
322         punch_in_button.toggled.connect (mem_fun(*this,&ARDOUR_UI::toggle_punch_in));
323         punch_out_button.toggled.connect (mem_fun(*this,&ARDOUR_UI::toggle_punch_out));
324
325         preroll_button.unset_flags (Gtk::CAN_FOCUS);
326         preroll_button.signal_set_events (preroll_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
327         preroll_button.set_name ("TransportButton");
328
329         postroll_button.unset_flags (Gtk::CAN_FOCUS);
330         postroll_button.signal_set_events (postroll_button.signal_get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
331         postroll_button.set_name ("TransportButton");
332
333         preroll_clock.set_mode (AudioClock::MinSec);
334         preroll_clock.set_name ("TransportClockDisplay");
335         postroll_clock.set_mode (AudioClock::MinSec);
336         postroll_clock.set_name ("TransportClockDisplay");
337
338         /* alerts */
339
340         /* CANNOT bind these to clicked or toggled, must use pressed or released */
341
342         solo_alert_button.set_name ("TransportSoloAlert");
343         solo_alert_button.pressed.connect (mem_fun(*this,&ARDOUR_UI::solo_alert_toggle));
344         auditioning_alert_button.set_name ("TransportAuditioningAlert");
345         auditioning_alert_button.pressed.connect (mem_fun(*this,&ARDOUR_UI::audition_alert_toggle));
346
347         alert_box.pack_start (solo_alert_button);
348         alert_box.pack_start (auditioning_alert_button);
349
350         transport_tearoff_hbox.set_border_width (5);
351
352         transport_tearoff_hbox.pack_start (goto_start_button, false, false);
353         transport_tearoff_hbox.pack_start (goto_end_button, false, false);
354
355         Gtk::Frame* sframe = manage (new Frame);
356         Gtk::VBox*  svbox = manage (new VBox);
357         Gtk::HBox*  shbox = manage (new HBox);
358
359         sframe->set_shadow_type (Gtk::SHADOW_IN);
360         sframe->add (shuttle_box);
361
362         shuttle_box.set_name (X_("ShuttleControl"));
363
364         speed_display_box.add (speed_display_label);
365         set_size_request_to_display_given_text (speed_display_box, _("stopped"), 2, 2);
366         speed_display_box.set_name (X_("ShuttleDisplay"));
367
368         shuttle_units_button.set_name (X_("ShuttleButton"));
369         shuttle_units_button.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::shuttle_unit_clicked));
370         
371         shuttle_style_button.set_name (X_("ShuttleButton"));
372         shuttle_style_button.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::shuttle_style_clicked));
373
374         Gtk::Frame* sdframe = manage (new Frame);
375
376         sdframe->set_shadow_type (Gtk::SHADOW_IN);
377         sdframe->add (speed_display_box);
378
379         shbox->pack_start (*sdframe, false, false);
380         shbox->pack_start (shuttle_units_button, true, true);
381         shbox->pack_start (shuttle_style_button, false, false);
382         
383         svbox->pack_start (*sframe, false, false);
384         svbox->pack_start (*shbox, false, false);
385
386         transport_tearoff_hbox.pack_start (*svbox, false, false, 5);
387
388         transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
389         transport_tearoff_hbox.pack_start (play_selection_button, false, false);
390         transport_tearoff_hbox.pack_start (roll_button, false, false);
391         transport_tearoff_hbox.pack_start (stop_button, false, false);
392         transport_tearoff_hbox.pack_start (rec_button, false, false, 10);
393
394         transport_tearoff_hbox.pack_start (primary_clock, false, false, 5);
395         transport_tearoff_hbox.pack_start (secondary_clock, false, false, 5);
396
397         transport_tearoff_hbox.pack_start (punch_in_button, false, false);
398         transport_tearoff_hbox.pack_start (punch_out_button, false, false);
399         transport_tearoff_hbox.pack_start (auto_input_button, false, false);
400         transport_tearoff_hbox.pack_start (auto_return_button, false, false);
401         transport_tearoff_hbox.pack_start (auto_play_button, false, false);
402         transport_tearoff_hbox.pack_start (click_button, false, false);
403         transport_tearoff_hbox.pack_start (follow_button, false, false);
404         
405         /* desensitize */
406
407         set_transport_sensitivity (false);
408
409         /* catch up with editor state */
410
411         follow_changed ();
412
413 //      transport_tearoff_hbox.pack_start (preroll_button, false, false);
414 //      transport_tearoff_hbox.pack_start (preroll_clock, false, false);
415
416 //      transport_tearoff_hbox.pack_start (postroll_button, false, false);
417 //      transport_tearoff_hbox.pack_start (postroll_clock, false, false);
418
419         transport_tearoff_hbox.pack_start (alert_box, false, false, 5);
420 }
421
422 void
423 ARDOUR_UI::setup_clock ()
424 {
425         ARDOUR_UI::Clock.connect (bind (mem_fun (big_clock, &AudioClock::set), false));
426         
427         big_clock_window = new BigClockWindow;
428         
429         big_clock_window->set_border_width (0);
430         big_clock_window->add  (big_clock);
431         big_clock_window->set_title (_("ardour: clock"));
432         
433         big_clock_window->signal_delete_event.connect (bind (ptr_fun (just_hide_it), static_cast<Gtk::Window*>(big_clock_window)));
434         big_clock_window->realize.connect (mem_fun(*this, &ARDOUR_UI::big_clock_realize));
435         big_clock_window->size_allocate.connect (mem_fun(*this, &ARDOUR_UI::big_clock_size_event));
436
437         big_clock_window->Hiding.connect (mem_fun(*this, &ARDOUR_UI::big_clock_hiding));
438 }
439
440 void
441 ARDOUR_UI::big_clock_size_event (GtkAllocation *alloc)
442 {
443         return;
444 }
445
446 void
447 ARDOUR_UI::big_clock_realize ()
448 {
449         big_clock_window->get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH|GDK_DECOR_MAXIMIZE|GDK_DECOR_MINIMIZE));
450 }
451
452 void
453 ARDOUR_UI::detach_tearoff (Gtk::Box* b, Gtk::Widget* w)
454 {
455         editor->ensure_float (*transport_tearoff->tearoff_window());
456         b->remove (*w);
457 }
458
459 void
460 ARDOUR_UI::reattach_tearoff (Gtk::Box* b, Gtk::Widget* w, int32_t n)
461 {
462         b->pack_start (*w);
463         b->reorder_child (*w, n);
464 }
465
466 void
467 ARDOUR_UI::soloing_changed (bool onoff)
468 {
469         if (solo_alert_button.get_active() != onoff) {
470                 solo_alert_button.set_active (onoff);
471         }
472 }
473
474 void
475 ARDOUR_UI::_auditioning_changed (bool onoff)
476 {
477         if (auditioning_alert_button.get_active() != onoff) {
478                 auditioning_alert_button.set_active (onoff);
479                 set_transport_sensitivity (!onoff);
480         }
481 }
482
483 void
484 ARDOUR_UI::auditioning_changed (bool onoff)
485 {
486         Gtkmm2ext::UI::instance()->call_slot(bind (mem_fun(*this, &ARDOUR_UI::_auditioning_changed), onoff));
487 }
488
489 void
490 ARDOUR_UI::audition_alert_toggle ()
491 {
492         if (session) {
493                 session->cancel_audition();
494         }
495 }
496
497 void
498 ARDOUR_UI::solo_alert_toggle ()
499 {
500         if (session) {
501                 session->set_all_solo (!session->soloing());
502         }
503 }
504
505 void
506 ARDOUR_UI::solo_blink (bool onoff)
507 {
508         if (session == 0) {
509                 return;
510         }
511         
512         if (session->soloing()) {
513                 if (onoff) {
514                         solo_alert_button.set_state (GTK_STATE_ACTIVE);
515                 } else {
516                         solo_alert_button.set_state (Gtk::STATE_NORMAL);
517                 }
518         } else {
519                 solo_alert_button.set_active (false);
520                 solo_alert_button.set_state (Gtk::STATE_NORMAL);
521         }
522 }
523
524 void
525 ARDOUR_UI::audition_blink (bool onoff)
526 {
527         if (session == 0) {
528                 return;
529         }
530         
531         if (session->is_auditioning()) {
532                 if (onoff) {
533                         auditioning_alert_button.set_state (GTK_STATE_ACTIVE);
534                 } else {
535                         auditioning_alert_button.set_state (Gtk::STATE_NORMAL);
536                 }
537         } else {
538                 auditioning_alert_button.set_active (false);
539                 auditioning_alert_button.set_state (Gtk::STATE_NORMAL);
540         }
541 }
542
543
544 gint
545 ARDOUR_UI::shuttle_box_button_press (GdkEventButton* ev)
546 {
547         if (!session) {
548                 return TRUE;
549         }
550
551         switch (ev->button) {
552         case 1:
553                 Gtk::Main::grab_add (shuttle_box);
554                 shuttle_grabbed = true;
555                 mouse_shuttle (ev->x, true);
556                 break;
557
558         case 2:
559         case 3:
560                 return TRUE;
561                 break;
562
563         case 4:
564                 break;
565         case 5:
566                 break;
567         }
568
569         return TRUE;
570 }
571
572 gint
573 ARDOUR_UI::shuttle_box_button_release (GdkEventButton* ev)
574 {
575         if (!session) {
576                 return TRUE;
577         }
578
579         switch (ev->button) {
580         case 1:
581                 mouse_shuttle (ev->x, true);
582                 shuttle_grabbed = false;
583                 Gtk::Main::grab_remove (shuttle_box);
584                 if (shuttle_behaviour == Sprung) {
585                         shuttle_fract = SHUTTLE_FRACT_SPEED1;
586                         session->request_transport_speed (1.0);
587                         shuttle_box.queue_draw ();
588                 }
589                 return TRUE;
590
591         case 2:
592                 if (session->transport_rolling()) {
593                         shuttle_fract = SHUTTLE_FRACT_SPEED1;
594                         session->request_transport_speed (1.0);
595                 } else {
596                         shuttle_fract = 0;
597                 }
598                 shuttle_box.queue_draw ();
599                 return TRUE;
600
601         case 3:
602                 return TRUE;
603                 
604         case 4:
605                 shuttle_fract += 0.005;
606                 break;
607         case 5:
608                 shuttle_fract -= 0.005;
609                 break;
610         }
611
612         use_shuttle_fract (true);
613
614         return TRUE;
615 }
616
617 gint
618 ARDOUR_UI::shuttle_box_motion (GdkEventMotion* ev)
619 {
620         if (!session || !shuttle_grabbed) {
621                 return TRUE;
622         }
623
624         return mouse_shuttle (ev->x, false);
625 }
626
627 gint
628 ARDOUR_UI::mouse_shuttle (double x, bool force)
629 {
630         double half_width = shuttle_box.width() / 2.0;
631         double distance = x - half_width;
632
633         if (distance > 0) {
634                 distance = min (distance, half_width);
635         } else {
636                 distance = max (distance, -half_width);
637         }
638
639         shuttle_fract = distance / half_width;
640         use_shuttle_fract (force);
641         return TRUE;
642 }
643
644 void
645 ARDOUR_UI::use_shuttle_fract (bool force)
646 {
647         struct timeval now;
648         struct timeval diff;
649         
650         /* do not attempt to submit a motion-driven transport speed request
651            more than once per process cycle.
652          */
653
654         gettimeofday (&now, 0);
655         timersub (&now, &last_shuttle_request, &diff);
656
657         if (!force && (diff.tv_usec + (diff.tv_sec * 1000000)) < engine->usecs_per_cycle()) {
658                 return;
659         }
660         
661         last_shuttle_request = now;
662
663         bool neg = (shuttle_fract < 0.0);
664
665         double fract = 1 - sqrt (1 - (shuttle_fract * shuttle_fract)); // Formula A1
666
667         if (neg) {
668                 fract = -fract;
669         }
670
671         session->request_transport_speed (8.0 * fract); // Formula A2
672         shuttle_box.queue_draw ();
673 }
674
675 gint
676 ARDOUR_UI::shuttle_box_expose (GdkEventExpose* event)
677 {
678         gint x;
679         Gdk_Window win (shuttle_box.get_window());
680
681         /* redraw the background */
682
683         win.draw_rectangle (shuttle_box.get_style()->get_bg_gc (shuttle_box.get_state()),
684                             true,
685                             event->area.x, event->area.y,
686                             event->area.width, event->area.height);
687
688
689         x = (gint) floor ((shuttle_box.width() / 2.0) + (0.5 * (shuttle_box.width() * shuttle_fract)));
690
691         /* draw line */
692
693         win.draw_line (shuttle_box.get_style()->get_fg_gc (shuttle_box.get_state()),
694                        x,
695                        0,
696                        x,
697                        shuttle_box.height());
698         return TRUE;
699 }
700
701 void
702 ARDOUR_UI::shuttle_style_clicked ()
703 {
704         shuttle_style_menu.popup (1, 0);
705 }
706
707 void
708 ARDOUR_UI::shuttle_unit_clicked ()
709 {
710         shuttle_unit_menu.popup (1, 0);
711 }
712
713 void
714 ARDOUR_UI::set_shuttle_units (ShuttleUnits u)
715 {
716         switch ((shuttle_units = u)) {
717         case Percentage:
718                 static_cast<Gtk::Label*>(shuttle_units_button.get_child())->set_text ("% ");
719                 break;
720         case Semitones:
721                 static_cast<Gtk::Label*>(shuttle_units_button.get_child())->set_text (_("st"));
722                 break;
723         }
724 }
725
726 void
727 ARDOUR_UI::set_shuttle_behaviour (ShuttleBehaviour b)
728 {
729         switch ((shuttle_behaviour = b)) {
730         case Sprung:
731                 static_cast<Gtk::Label*>(shuttle_style_button.get_child())->set_text (_("sprung"));
732                 shuttle_fract = 0.0;
733                 shuttle_box.queue_draw ();
734                 if (session) {
735                         if (session->transport_rolling()) {
736                                 shuttle_fract = SHUTTLE_FRACT_SPEED1;
737                                 session->request_transport_speed (1.0);
738                         }
739                 }
740                 break;
741         case Wheel:
742                 static_cast<Gtk::Label*>(shuttle_style_button.get_child())->set_text (_("wheel"));
743                 break;
744         }
745 }
746
747 void
748 ARDOUR_UI::update_speed_display ()
749 {
750         if (!session) {
751                 speed_display_label.set_text (_("stopped"));
752                 return;
753         }
754
755         char buf[32];
756         float x = session->transport_speed ();
757
758         if (x != 0) {
759                 if (shuttle_units == Percentage) {
760                         snprintf (buf, sizeof (buf), "%.4f", x);
761                 } else {
762                         if (x < 0) {
763                                 snprintf (buf, sizeof (buf), "< %.1f", 12.0 * fast_log2 (-x));
764                         } else {
765                                 snprintf (buf, sizeof (buf), "> %.1f", 12.0 * fast_log2 (x));
766                         }
767                 }
768                 speed_display_label.set_text (buf);
769         } else {
770                 speed_display_label.set_text (_("stopped"));
771         }
772 }       
773         
774 void
775 ARDOUR_UI::set_transport_sensitivity (bool yn)
776 {
777         goto_start_button.set_sensitive (yn);
778         goto_end_button.set_sensitive (yn);
779         roll_button.set_sensitive (yn);
780         stop_button.set_sensitive (yn);
781         play_selection_button.set_sensitive (yn);
782         rec_button.set_sensitive (yn);
783         auto_loop_button.set_sensitive (yn);
784         shuttle_box.set_sensitive (yn);
785 }