c3063b6ed5bdec6eb8b817b5cb716bcb63880518
[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         shuttle_box.signal_button_press_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_button_press));
351         shuttle_box.signal_button_release_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_button_release));
352         shuttle_box.signal_motion_notify_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_motion));
353         shuttle_box.signal_expose_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_expose));
354
355         /* clocks, etc. */
356
357         ARDOUR_UI::Clock.connect (bind (mem_fun (primary_clock, &AudioClock::set), false));
358         ARDOUR_UI::Clock.connect (bind (mem_fun (secondary_clock, &AudioClock::set), false));
359
360         primary_clock.set_mode (AudioClock::SMPTE);
361         primary_clock.set_name ("TransportClockDisplay");
362         secondary_clock.set_mode (AudioClock::BBT);
363         secondary_clock.set_name ("TransportClockDisplay");
364
365
366         primary_clock.ValueChanged.connect (mem_fun(*this, &ARDOUR_UI::primary_clock_value_changed));
367         secondary_clock.ValueChanged.connect (mem_fun(*this, &ARDOUR_UI::secondary_clock_value_changed));
368
369         ARDOUR_UI::instance()->tooltips().set_tip (primary_clock, _("Primary clock"));
370         ARDOUR_UI::instance()->tooltips().set_tip (secondary_clock, _("secondary clock"));
371
372         /* options */
373
374         auto_return_button.signal_toggled().connect (mem_fun(*this,&ARDOUR_UI::toggle_auto_return));
375         auto_play_button.signal_toggled().connect (mem_fun(*this,&ARDOUR_UI::toggle_auto_play));
376         auto_input_button.signal_toggled().connect (mem_fun(*this,&ARDOUR_UI::toggle_auto_input));
377         click_button.signal_toggled().connect (mem_fun(*this,&ARDOUR_UI::toggle_click));
378         follow_button.signal_toggled().connect (mem_fun(*this,&ARDOUR_UI::toggle_follow));
379         punch_in_button.signal_toggled().connect (mem_fun(*this,&ARDOUR_UI::toggle_punch_in));
380         punch_out_button.signal_toggled().connect (mem_fun(*this,&ARDOUR_UI::toggle_punch_out));
381
382         preroll_button.unset_flags (Gtk::CAN_FOCUS);
383         preroll_button.set_events (preroll_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
384         preroll_button.set_name ("TransportButton");
385
386         postroll_button.unset_flags (Gtk::CAN_FOCUS);
387         postroll_button.set_events (postroll_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
388         postroll_button.set_name ("TransportButton");
389
390         preroll_clock.set_mode (AudioClock::MinSec);
391         preroll_clock.set_name ("TransportClockDisplay");
392         postroll_clock.set_mode (AudioClock::MinSec);
393         postroll_clock.set_name ("TransportClockDisplay");
394
395         /* alerts */
396
397         /* CANNOT bind these to clicked or toggled, must use pressed or released */
398
399         solo_alert_button.set_name ("TransportSoloAlert");
400         solo_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::solo_alert_toggle));
401         auditioning_alert_button.set_name ("TransportAuditioningAlert");
402         auditioning_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::audition_alert_toggle));
403
404         alert_box.pack_start (solo_alert_button);
405         alert_box.pack_start (auditioning_alert_button);
406
407         transport_tearoff_hbox.set_border_width (5);
408
409         transport_tearoff_hbox.pack_start (goto_start_button, false, false);
410         transport_tearoff_hbox.pack_start (goto_end_button, false, false);
411
412         Gtk::Frame* sframe = manage (new Frame);
413         Gtk::VBox*  svbox = manage (new VBox);
414         Gtk::HBox*  shbox = manage (new HBox);
415
416         sframe->set_shadow_type (Gtk::SHADOW_IN);
417         sframe->add (shuttle_box);
418
419         shuttle_box.set_name (X_("ShuttleControl"));
420
421         speed_display_box.add (speed_display_label);
422         set_size_request_to_display_given_text (speed_display_box, _("stopped"), 2, 2);
423         speed_display_box.set_name (X_("ShuttleDisplay"));
424
425         shuttle_units_button.set_name (X_("ShuttleButton"));
426         shuttle_units_button.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::shuttle_unit_clicked));
427         
428         shuttle_style_button.set_name (X_("ShuttleButton"));
429         shuttle_style_button.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::shuttle_style_clicked));
430
431         Gtk::Frame* sdframe = manage (new Frame);
432
433         sdframe->set_shadow_type (Gtk::SHADOW_IN);
434         sdframe->add (speed_display_box);
435
436         shbox->pack_start (*sdframe, false, false);
437         shbox->pack_start (shuttle_units_button, true, true);
438         shbox->pack_start (shuttle_style_button, false, false);
439         
440         svbox->pack_start (*sframe, false, false);
441         svbox->pack_start (*shbox, false, false);
442
443         transport_tearoff_hbox.pack_start (*svbox, false, false, 5);
444
445         transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
446         transport_tearoff_hbox.pack_start (play_selection_button, false, false);
447         transport_tearoff_hbox.pack_start (roll_button, false, false);
448         transport_tearoff_hbox.pack_start (stop_button, false, false);
449         transport_tearoff_hbox.pack_start (rec_button, false, false, 10);
450
451         transport_tearoff_hbox.pack_start (primary_clock, false, false, 5);
452         transport_tearoff_hbox.pack_start (secondary_clock, false, false, 5);
453
454         transport_tearoff_hbox.pack_start (punch_in_button, false, false);
455         transport_tearoff_hbox.pack_start (punch_out_button, false, false);
456         transport_tearoff_hbox.pack_start (auto_input_button, false, false);
457         transport_tearoff_hbox.pack_start (auto_return_button, false, false);
458         transport_tearoff_hbox.pack_start (auto_play_button, false, false);
459         transport_tearoff_hbox.pack_start (click_button, false, false);
460         transport_tearoff_hbox.pack_start (follow_button, false, false);
461         
462         /* desensitize */
463
464         set_transport_sensitivity (false);
465
466         /* catch up with editor state */
467
468         follow_changed ();
469
470 //      transport_tearoff_hbox.pack_start (preroll_button, false, false);
471 //      transport_tearoff_hbox.pack_start (preroll_clock, false, false);
472
473 //      transport_tearoff_hbox.pack_start (postroll_button, false, false);
474 //      transport_tearoff_hbox.pack_start (postroll_clock, false, false);
475
476         transport_tearoff_hbox.pack_start (alert_box, false, false, 5);
477 }
478
479 void
480 ARDOUR_UI::setup_clock ()
481 {
482         ARDOUR_UI::Clock.connect (bind (mem_fun (big_clock, &AudioClock::set), false));
483         
484         big_clock_window = new Gtk::Window (WINDOW_TOPLEVEL);
485         
486         big_clock_window->set_border_width (0);
487         big_clock_window->add  (big_clock);
488         big_clock_window->set_title (_("ardour: clock"));
489         big_clock_window->set_type_hint (Gdk::WINDOW_TYPE_HINT_MENU);
490         big_clock_window->signal_realize().connect (bind (sigc::ptr_fun (set_decoration), big_clock_window,  (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
491         big_clock_window->signal_unmap().connect (bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleBigClock")));
492
493         manage_window (*big_clock_window);
494 }
495
496 void
497 ARDOUR_UI::manage_window (Window& win)
498 {
499         win.signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), &win));
500         win.signal_enter_notify_event().connect (bind (mem_fun (Keyboard::the_keyboard(), &Keyboard::enter_window), &win));
501         win.signal_leave_notify_event().connect (bind (mem_fun (Keyboard::the_keyboard(), &Keyboard::leave_window), &win));
502 }
503
504 void
505 ARDOUR_UI::detach_tearoff (Gtk::Box* b, Gtk::Widget* w)
506 {
507         editor->ensure_float (*transport_tearoff->tearoff_window());
508         b->remove (*w);
509 }
510
511 void
512 ARDOUR_UI::reattach_tearoff (Gtk::Box* b, Gtk::Widget* w, int32_t n)
513 {
514         b->pack_start (*w);
515         b->reorder_child (*w, n);
516 }
517
518 void
519 ARDOUR_UI::soloing_changed (bool onoff)
520 {
521         if (solo_alert_button.get_active() != onoff) {
522                 solo_alert_button.set_active (onoff);
523         }
524 }
525
526 void
527 ARDOUR_UI::_auditioning_changed (bool onoff)
528 {
529         if (auditioning_alert_button.get_active() != onoff) {
530                 auditioning_alert_button.set_active (onoff);
531                 set_transport_sensitivity (!onoff);
532         }
533 }
534
535 void
536 ARDOUR_UI::auditioning_changed (bool onoff)
537 {
538         Gtkmm2ext::UI::instance()->call_slot(bind (mem_fun(*this, &ARDOUR_UI::_auditioning_changed), onoff));
539 }
540
541 void
542 ARDOUR_UI::audition_alert_toggle ()
543 {
544         if (session) {
545                 session->cancel_audition();
546         }
547 }
548
549 void
550 ARDOUR_UI::solo_alert_toggle ()
551 {
552         if (session) {
553                 session->set_all_solo (!session->soloing());
554         }
555 }
556
557 void
558 ARDOUR_UI::solo_blink (bool onoff)
559 {
560         if (session == 0) {
561                 return;
562         }
563         
564         if (session->soloing()) {
565                 if (onoff) {
566                         solo_alert_button.set_state (Gtk::STATE_ACTIVE);
567                 } else {
568                         solo_alert_button.set_state (Gtk::STATE_NORMAL);
569                 }
570         } else {
571                 solo_alert_button.set_active (false);
572                 solo_alert_button.set_state (Gtk::STATE_NORMAL);
573         }
574 }
575
576 void
577 ARDOUR_UI::audition_blink (bool onoff)
578 {
579         if (session == 0) {
580                 return;
581         }
582         
583         if (session->is_auditioning()) {
584                 if (onoff) {
585                         auditioning_alert_button.set_state (Gtk::STATE_ACTIVE);
586                 } else {
587                         auditioning_alert_button.set_state (Gtk::STATE_NORMAL);
588                 }
589         } else {
590                 auditioning_alert_button.set_active (false);
591                 auditioning_alert_button.set_state (Gtk::STATE_NORMAL);
592         }
593 }
594
595
596 gint
597 ARDOUR_UI::shuttle_box_button_press (GdkEventButton* ev)
598 {
599         if (!session) {
600                 return TRUE;
601         }
602
603         switch (ev->button) {
604         case 1:
605                 shuttle_box.add_modal_grab ();
606                 shuttle_grabbed = true;
607                 mouse_shuttle (ev->x, true);
608                 break;
609
610         case 2:
611         case 3:
612                 return TRUE;
613                 break;
614
615         case 4:
616                 break;
617         case 5:
618                 break;
619         }
620
621         return TRUE;
622 }
623
624 gint
625 ARDOUR_UI::shuttle_box_button_release (GdkEventButton* ev)
626 {
627         if (!session) {
628                 return TRUE;
629         }
630
631         switch (ev->button) {
632         case 1:
633                 mouse_shuttle (ev->x, true);
634                 shuttle_grabbed = false;
635                 shuttle_box.remove_modal_grab ();
636                 if (shuttle_behaviour == Sprung) {
637                         shuttle_fract = SHUTTLE_FRACT_SPEED1;
638                         session->request_transport_speed (1.0);
639                         shuttle_box.queue_draw ();
640                 }
641                 return TRUE;
642
643         case 2:
644                 if (session->transport_rolling()) {
645                         shuttle_fract = SHUTTLE_FRACT_SPEED1;
646                         session->request_transport_speed (1.0);
647                 } else {
648                         shuttle_fract = 0;
649                 }
650                 shuttle_box.queue_draw ();
651                 return TRUE;
652
653         case 3:
654                 return TRUE;
655                 
656         case 4:
657                 shuttle_fract += 0.005;
658                 break;
659         case 5:
660                 shuttle_fract -= 0.005;
661                 break;
662         }
663
664         use_shuttle_fract (true);
665
666         return TRUE;
667 }
668
669 gint
670 ARDOUR_UI::shuttle_box_motion (GdkEventMotion* ev)
671 {
672         if (!session || !shuttle_grabbed) {
673                 return TRUE;
674         }
675
676         return mouse_shuttle (ev->x, false);
677 }
678
679 gint
680 ARDOUR_UI::mouse_shuttle (double x, bool force)
681 {
682         double half_width = shuttle_box.get_width() / 2.0;
683         double distance = x - half_width;
684
685         if (distance > 0) {
686                 distance = min (distance, half_width);
687         } else {
688                 distance = max (distance, -half_width);
689         }
690
691         shuttle_fract = distance / half_width;
692         use_shuttle_fract (force);
693         return TRUE;
694 }
695
696 void
697 ARDOUR_UI::use_shuttle_fract (bool force)
698 {
699         struct timeval now;
700         struct timeval diff;
701         
702         /* do not attempt to submit a motion-driven transport speed request
703            more than once per process cycle.
704          */
705
706         gettimeofday (&now, 0);
707         timersub (&now, &last_shuttle_request, &diff);
708
709         if (!force && (diff.tv_usec + (diff.tv_sec * 1000000)) < engine->usecs_per_cycle()) {
710                 return;
711         }
712         
713         last_shuttle_request = now;
714
715         bool neg = (shuttle_fract < 0.0);
716
717         double fract = 1 - sqrt (1 - (shuttle_fract * shuttle_fract)); // Formula A1
718
719         if (neg) {
720                 fract = -fract;
721         }
722
723         session->request_transport_speed (8.0 * fract); // Formula A2
724         shuttle_box.queue_draw ();
725 }
726
727 gint
728 ARDOUR_UI::shuttle_box_expose (GdkEventExpose* event)
729 {
730         gint x;
731         Glib::RefPtr<Gdk::Window> win (shuttle_box.get_window());
732
733         /* redraw the background */
734
735         win->draw_rectangle (shuttle_box.get_style()->get_bg_gc (shuttle_box.get_state()),
736                              true,
737                              event->area.x, event->area.y,
738                              event->area.width, event->area.height);
739
740
741         x = (gint) floor ((shuttle_box.get_width() / 2.0) + (0.5 * (shuttle_box.get_width() * shuttle_fract)));
742
743         /* draw line */
744
745         win->draw_line (shuttle_box.get_style()->get_fg_gc (shuttle_box.get_state()),
746                         x,
747                         0,
748                         x,
749                         shuttle_box.get_height());
750         return TRUE;
751 }
752
753 void
754 ARDOUR_UI::shuttle_style_clicked ()
755 {
756         if (shuttle_style_menu == 0) {
757                 shuttle_style_menu = dynamic_cast<Menu*> (ActionManager::get_widget ("/ShuttleStylePopup"));
758         }
759         shuttle_style_menu->popup (1, 0);
760 }
761
762 void
763 ARDOUR_UI::shuttle_unit_clicked ()
764 {
765         if (shuttle_unit_menu == 0) {
766                 shuttle_unit_menu = dynamic_cast<Menu*> (ActionManager::get_widget ("/ShuttleUnitPopup"));
767         }
768         shuttle_unit_menu->popup (1, 0);
769 }
770
771 void
772 ARDOUR_UI::set_shuttle_units (ShuttleUnits u)
773 {
774         switch ((shuttle_units = u)) {
775         case Percentage:
776                 static_cast<Gtk::Label*>(shuttle_units_button.get_child())->set_text ("% ");
777                 break;
778         case Semitones:
779                 static_cast<Gtk::Label*>(shuttle_units_button.get_child())->set_text (_("st"));
780                 break;
781         }
782 }
783
784 void
785 ARDOUR_UI::set_shuttle_behaviour (ShuttleBehaviour b)
786 {
787         switch ((shuttle_behaviour = b)) {
788         case Sprung:
789                 static_cast<Gtk::Label*>(shuttle_style_button.get_child())->set_text (_("sprung"));
790                 shuttle_fract = 0.0;
791                 shuttle_box.queue_draw ();
792                 if (session) {
793                         if (session->transport_rolling()) {
794                                 shuttle_fract = SHUTTLE_FRACT_SPEED1;
795                                 session->request_transport_speed (1.0);
796                         }
797                 }
798                 break;
799         case Wheel:
800                 static_cast<Gtk::Label*>(shuttle_style_button.get_child())->set_text (_("wheel"));
801                 break;
802         }
803 }
804
805 void
806 ARDOUR_UI::update_speed_display ()
807 {
808         if (!session) {
809                 speed_display_label.set_text (_("stopped"));
810                 return;
811         }
812
813         char buf[32];
814         float x = session->transport_speed ();
815
816         if (x != 0) {
817                 if (shuttle_units == Percentage) {
818                         snprintf (buf, sizeof (buf), "%.4f", x);
819                 } else {
820                         if (x < 0) {
821                                 snprintf (buf, sizeof (buf), "< %.1f", 12.0 * fast_log2 (-x));
822                         } else {
823                                 snprintf (buf, sizeof (buf), "> %.1f", 12.0 * fast_log2 (x));
824                         }
825                 }
826                 speed_display_label.set_text (buf);
827         } else {
828                 speed_display_label.set_text (_("stopped"));
829         }
830 }       
831         
832 void
833 ARDOUR_UI::set_transport_sensitivity (bool yn)
834 {
835         goto_start_button.set_sensitive (yn);
836         goto_end_button.set_sensitive (yn);
837         roll_button.set_sensitive (yn);
838         stop_button.set_sensitive (yn);
839         play_selection_button.set_sensitive (yn);
840         rec_button.set_sensitive (yn);
841         auto_loop_button.set_sensitive (yn);
842         shuttle_box.set_sensitive (yn);
843 }