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