miscellaneous fixes post-jesse's 24 bit file format changes
[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 void
89 ARDOUR_UI::setup_adjustables ()
90 {
91         adjuster_table.set_homogeneous (true);
92
93         online_control_strings.push_back (_("MMC + Local"));
94         online_control_strings.push_back (_("MMC"));
95         online_control_strings.push_back (_("Local"));
96
97         online_control_button = new GlobalClickBox ("CONTROL",
98                                                     online_control_strings);
99
100         online_control_button->adjustment.signal_value_changed().connect(mem_fun(*this,&ARDOUR_UI::control_methods_adjusted));
101
102         mmc_id_strings.push_back ("1");
103         mmc_id_strings.push_back ("2");
104         mmc_id_strings.push_back ("3");
105         mmc_id_strings.push_back ("4");
106         mmc_id_strings.push_back ("5");
107         mmc_id_strings.push_back ("6");
108         mmc_id_strings.push_back ("7");
109         mmc_id_strings.push_back ("8");
110         mmc_id_strings.push_back ("9");
111
112         mmc_id_button = new GlobalClickBox (_("MMC ID"), mmc_id_strings);
113
114         mmc_id_button->adjustment.signal_value_changed().connect (mem_fun(*this,&ARDOUR_UI::mmc_device_id_adjusted));
115
116         adjuster_table.attach (*online_control_button, 0, 2, 1, 2, FILL|EXPAND, FILL, 5, 5);
117         adjuster_table.attach (*mmc_id_button, 2, 3, 1, 2, FILL, FILL, 5, 5);
118 }
119
120 #define NEW_LOOP_XPM
121 #ifdef NEW_LOOP_XPM
122
123 /* XPM */
124 static const gchar * loop_xpm[] = {
125 "17 25 94 2",
126 "       c None",
127 ".      c #4C4C4C",
128 "+      c #555555",
129 "@      c #454545",
130 "#      c #242424",
131 "$      c #5E5E5E",
132 "%      c #000000",
133 "&      c #6B6B6B",
134 "*      c #484848",
135 "=      c #4E4E4E",
136 "-      c #6A6A6A",
137 ";      c #717171",
138 ">      c #686868",
139 ",      c #838383",
140 "'      c #888888",
141 ")      c #676767",
142 "!      c #4A4A4A",
143 "~      c #474747",
144 "{      c #939393",
145 "]      c #949494",
146 "^      c #9E9E9E",
147 "/      c #4B4B4B",
148 "(      c #A1A1A1",
149 "_      c #A0A0A0",
150 ":      c #A5A5A5",
151 "<      c #B2B2B2",
152 "[      c #646464",
153 "}      c #ADADAD",
154 "|      c #AAAAAA",
155 "1      c #B1B1B1",
156 "2      c #494949",
157 "3      c #9A9A9A",
158 "4      c #A2A2A2",
159 "5      c #A7A7A7",
160 "6      c #A8A8A8",
161 "7      c #C1C1C1",
162 "8      c #696969",
163 "9      c #656565",
164 "0      c #B6B6B6",
165 "a      c #404040",
166 "b      c #989898",
167 "c      c #9D9D9D",
168 "d      c #999999",
169 "e      c #A3A3A3",
170 "f      c #C4C4C4",
171 "g      c #707070",
172 "h      c #C2C2C2",
173 "i      c #9C9C9C",
174 "j      c #969696",
175 "k      c #A4A4A4",
176 "l      c #777777",
177 "m      c #979797",
178 "n      c #2F2F2F",
179 "o      c #A9A9A9",
180 "p      c #7D7D7D",
181 "q      c #6D6D6D",
182 "r      c #959595",
183 "s      c #AFAFAF",
184 "t      c #848484",
185 "u      c #7F7F7F",
186 "v      c #3B3B3B",
187 "w      c #9B9B9B",
188 "x      c #2B2B2B",
189 "y      c #BFBFBF",
190 "z      c #B3B3B3",
191 "A      c #8A8A8A",
192 "B      c #858585",
193 "C      c #2E2E2E",
194 "D      c #C3C3C3",
195 "E      c #B8B8B8",
196 "F      c #464646",
197 "G      c #8E8E8E",
198 "H      c #898989",
199 "I      c #8D8D8D",
200 "J      c #797979",
201 "K      c #BCBCBC",
202 "L      c #909090",
203 "M      c #8C8C8C",
204 "N      c #2A2A2A",
205 "O      c #747474",
206 "P      c #818181",
207 "Q      c #808080",
208 "R      c #C6C6C6",
209 "S      c #C0C0C0",
210 "T      c #787878",
211 "U      c #868686",
212 "V      c #878787",
213 "W      c #8B8B8B",
214 "X      c #666666",
215 "Y      c #BDBDBD",
216 "Z      c #929292",
217 "`      c #6C6C6C",
218 " .     c #505050",
219 "..     c #C8C8C8",
220 "      . +                         ",
221 "      @ # $                       ",
222 "      @ % @ &                     ",
223 "      * % % = -                   ",
224 "      * % ; % = >                 ",
225 "      * % , ' % = )               ",
226 "* ! ! ~ % { ] ^ % / . ! * ~ * +   ",
227 "~ % % % % ( _ : < % % % % % % % ) ",
228 "* % $ [ % } | 1 % 2 3 ^ 4 5 6 % 7 ",
229 "* % 8 9 % 0 0 % a b c d c _ e % f ",
230 "* % g 8 % h % a b i b j c 4 k % 7 ",
231 "* % l g % % . m i j j 3 n o o % 7 ",
232 "~ % p l % q d i j r b # % 0 s % 7 ",
233 "~ % t u v b w j r d x % % y z % 7 ",
234 "~ % A B A b j ] d C % [ % D E % 7 ",
235 "F % G H I { ] b C % q J % f K % 7 ",
236 "~ % L M G { b N % O P Q % R S % 7 ",
237 "+ % % % % % % % T U V W % % % % D ",
238 "  X 7 D 7 7 Y = % I Z b % 7 7 K 7 ",
239 "              ` = % ( : % 7       ",
240 "                8 = % z % 7       ",
241 "                  X / % % 7       ",
242 "                    X  .% ..      ",
243 "                      - 9 ..      ",
244 "                        q I       "};
245
246 #else 
247
248 static const gchar * loop_xpm[] = {
249 "19 19 3 1",
250 "       c None",
251 ".      c #000000",
252 "+      c #FFFFFF",
253 "       ...         ",
254 "       .+..        ",
255 "       .++..       ",
256 "     ...+++....    ",
257 "   ...++++++++...  ",
258 "  ..+++.+++..+++.. ",
259 " ..++...++.....++..",
260 " .++.. .+..   ..++.",
261 " .+..  ...     ..+.",
262 " .+.            .+.",
263 " .+..     ...  ..+.",
264 " .++..   ..+. ..++.",
265 " ..++.....++...++..",
266 "  ..+++..+++.+++.. ",
267 "   ...++++++++...  ",
268 "     ....+++...    ",
269 "        ..++.      ",
270 "         ..+.      ",
271 "          ...      "};
272
273 #endif
274
275 void
276 ARDOUR_UI::transport_stopped ()
277 {
278         stop_button.set_active (true);
279         
280         roll_button.set_active (false);
281         play_selection_button.set_active (false);
282         auto_loop_button.set_active (false);
283
284         shuttle_fract = 0;
285         shuttle_box.queue_draw ();
286
287         update_disk_space ();
288 }
289
290 static const double SHUTTLE_FRACT_SPEED1=0.48412291827; /* derived from A1,A2 */
291
292 void
293 ARDOUR_UI::transport_rolling ()
294 {
295         stop_button.set_active (false);
296         if (session->get_play_range()) {
297
298                 play_selection_button.set_active (true);
299                 roll_button.set_active (false);
300                 auto_loop_button.set_active (false);
301
302         } else if (session->get_auto_loop ()) {
303
304                 auto_loop_button.set_active (true);
305                 play_selection_button.set_active (false);
306                 roll_button.set_active (false);
307
308         } else {
309
310                 roll_button.set_active (true);
311                 play_selection_button.set_active (false);
312                 auto_loop_button.set_active (false);
313         }
314
315         /* reset shuttle controller */
316
317         shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
318         shuttle_box.queue_draw ();
319 }
320
321 void
322 ARDOUR_UI::transport_rewinding ()
323 {
324         stop_button.set_active(false);
325         roll_button.set_active (true);
326         play_selection_button.set_active (false);
327         auto_loop_button.set_active (false);
328 }
329
330 void
331 ARDOUR_UI::transport_forwarding ()
332 {
333         stop_button.set_active (false);
334         roll_button.set_active (true);
335         play_selection_button.set_active (false);
336         auto_loop_button.set_active (false);
337 }
338
339 void
340 ARDOUR_UI::setup_transport ()
341 {
342         transport_tearoff = manage (new TearOff (transport_tearoff_hbox));
343         transport_tearoff->set_name ("TransportBase");
344
345         transport_hbox.pack_start (*transport_tearoff, true, false);
346
347         transport_base.set_name ("TransportBase");
348         transport_base.add (transport_hbox);
349
350         transport_frame.set_shadow_type (SHADOW_OUT);
351         transport_frame.set_name ("BaseFrame");
352         transport_frame.add (transport_base);
353
354         transport_tearoff->Detach.connect (bind (mem_fun(*this, &ARDOUR_UI::detach_tearoff), static_cast<Box*>(&top_packer), 
355                                                  static_cast<Widget*>(&transport_frame)));
356         transport_tearoff->Attach.connect (bind (mem_fun(*this, &ARDOUR_UI::reattach_tearoff), static_cast<Box*> (&top_packer), 
357                                                  static_cast<Widget*> (&transport_frame), 1));
358         transport_tearoff->Hidden.connect (bind (mem_fun(*this, &ARDOUR_UI::detach_tearoff), static_cast<Box*>(&top_packer), 
359                                                  static_cast<Widget*>(&transport_frame)));
360         transport_tearoff->Visible.connect (bind (mem_fun(*this, &ARDOUR_UI::reattach_tearoff), static_cast<Box*> (&top_packer), 
361                                                   static_cast<Widget*> (&transport_frame), 1));
362         
363         shuttle_box.set_name ("TransportButton");
364         goto_start_button.set_name ("TransportButton");
365         goto_end_button.set_name ("TransportButton");
366         roll_button.set_name ("TransportButton");
367         stop_button.set_name ("TransportButton");
368         play_selection_button.set_name ("TransportButton");
369         rec_button.set_name ("TransportRecButton");
370         auto_loop_button.set_name ("TransportButton");
371         auto_return_button.set_name ("TransportButton");
372         auto_play_button.set_name ("TransportButton");
373         auto_input_button.set_name ("TransportButton");
374         punch_in_button.set_name ("TransportButton");
375         punch_out_button.set_name ("TransportButton");
376         click_button.set_name ("TransportButton");
377         time_master_button.set_name ("TransportButton");
378
379         vector<Gdk::Color> colors;
380         Gdk::Color c;
381
382         /* record button has 3 color states, so we set 2 extra here */
383         set_color(c, rgba_from_style ("TransportRecButton", 0xff, 0, 0, 0, "bg", Gtk::STATE_PRELIGHT, false ));
384         colors.push_back (c);
385         
386         set_color(c, rgba_from_style ("TransportRecButton", 0xff, 0, 0, 0, "bg", Gtk::STATE_ACTIVE, false ));
387         colors.push_back (c);
388         
389         rec_button.set_colors (colors);
390         colors.clear ();
391         
392         /* other buttons get 2 color states, so add one here */
393         set_color(c, rgba_from_style ("TransportButton", 0x7f, 0xff, 0x7f, 0, "bg", Gtk::STATE_ACTIVE, false ));
394         colors.push_back (c);
395
396         stop_button.set_colors (colors);
397         roll_button.set_colors (colors);
398         auto_loop_button.set_colors (colors);
399         play_selection_button.set_colors (colors);
400         goto_start_button.set_colors (colors);
401         goto_end_button.set_colors (colors);
402         
403         Widget* w;
404
405         stop_button.set_active (true);
406
407         w = manage (new Image (Stock::MEDIA_PREVIOUS, ICON_SIZE_BUTTON));
408         w->show();
409         goto_start_button.add (*w);
410         w = manage (new Image (Stock::MEDIA_NEXT, ICON_SIZE_BUTTON));
411         w->show();
412         goto_end_button.add (*w);
413         w = manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON));
414         w->show();
415         roll_button.add (*w);
416         w = manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON));
417         w->show();
418         stop_button.add (*w);
419         w = manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON));
420         w->show();
421         play_selection_button.add (*w);
422         w = manage (new Image (Stock::MEDIA_RECORD, ICON_SIZE_BUTTON));
423         w->show();
424         rec_button.add (*w);
425         w = manage (new Image (Gdk::Pixbuf::create_from_xpm_data(loop_xpm)));
426         w->show();
427         auto_loop_button.add (*w);
428
429         RefPtr<Action> act;
430
431         act = ActionManager::get_action (X_("Transport"), X_("Stop"));
432         act->connect_proxy (stop_button);
433         act = ActionManager::get_action (X_("Transport"), X_("Roll"));
434         act->connect_proxy (roll_button);
435         act = ActionManager::get_action (X_("Transport"), X_("Record"));
436         act->connect_proxy (rec_button);
437         act = ActionManager::get_action (X_("Transport"), X_("GotoStart"));
438         act->connect_proxy (goto_start_button);
439         act = ActionManager::get_action (X_("Transport"), X_("GotoEnd"));
440         act->connect_proxy (goto_end_button);
441         act = ActionManager::get_action (X_("Transport"), X_("Loop"));
442         act->connect_proxy (auto_loop_button);
443         act = ActionManager::get_action (X_("Transport"), X_("PlaySelection"));
444         act->connect_proxy (play_selection_button);
445         act = ActionManager::get_action (X_("Transport"), X_("ToggleTimeMaster"));
446         act->connect_proxy (time_master_button);
447
448         ARDOUR_UI::instance()->tooltips().set_tip (roll_button, _("Play from playhead"));
449         ARDOUR_UI::instance()->tooltips().set_tip (stop_button, _("Stop playback"));
450         ARDOUR_UI::instance()->tooltips().set_tip (play_selection_button, _("Play range/selection"));
451         ARDOUR_UI::instance()->tooltips().set_tip (goto_start_button, _("Go to start of session"));
452         ARDOUR_UI::instance()->tooltips().set_tip (goto_end_button, _("Go to end of session"));
453         ARDOUR_UI::instance()->tooltips().set_tip (auto_loop_button, _("Play loop range"));
454         ARDOUR_UI::instance()->tooltips().set_tip (auto_return_button, _("Return to last playback start when stopped"));
455         ARDOUR_UI::instance()->tooltips().set_tip (auto_play_button, _("Start playback after any locate"));
456         ARDOUR_UI::instance()->tooltips().set_tip (auto_input_button, _("Be sensible about input monitoring"));
457         ARDOUR_UI::instance()->tooltips().set_tip (punch_in_button, _("Start recording at auto-punch start"));
458         ARDOUR_UI::instance()->tooltips().set_tip (punch_out_button, _("Stop recording at auto-punch end"));
459         ARDOUR_UI::instance()->tooltips().set_tip (click_button, _("Enable/Disable audio click"));
460         ARDOUR_UI::instance()->tooltips().set_tip (sync_option_combo, _("Positional sync source"));
461         ARDOUR_UI::instance()->tooltips().set_tip (time_master_button, _("Does Ardour control the time?"));
462         ARDOUR_UI::instance()->tooltips().set_tip (shuttle_box, _("Shuttle speed control"));
463         ARDOUR_UI::instance()->tooltips().set_tip (shuttle_units_button, _("Select semitones or %%-age for speed display"));
464         ARDOUR_UI::instance()->tooltips().set_tip (speed_display_box, _("Current transport speed"));
465         
466         shuttle_box.set_flags (CAN_FOCUS);
467         shuttle_box.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::POINTER_MOTION_MASK);
468         shuttle_box.set_size_request (100, 15);
469
470         shuttle_box.signal_button_press_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_button_press));
471         shuttle_box.signal_button_release_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_button_release));
472         shuttle_box.signal_motion_notify_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_motion));
473         shuttle_box.signal_expose_event().connect (mem_fun(*this, &ARDOUR_UI::shuttle_box_expose));
474
475         /* clocks, etc. */
476
477         ARDOUR_UI::Clock.connect (bind (mem_fun (primary_clock, &AudioClock::set), false));
478         ARDOUR_UI::Clock.connect (bind (mem_fun (secondary_clock, &AudioClock::set), false));
479
480         primary_clock.set_mode (AudioClock::SMPTE);
481         secondary_clock.set_mode (AudioClock::BBT);
482
483         primary_clock.ValueChanged.connect (mem_fun(*this, &ARDOUR_UI::primary_clock_value_changed));
484         secondary_clock.ValueChanged.connect (mem_fun(*this, &ARDOUR_UI::secondary_clock_value_changed));
485
486         ARDOUR_UI::instance()->tooltips().set_tip (primary_clock, _("Primary clock"));
487         ARDOUR_UI::instance()->tooltips().set_tip (secondary_clock, _("secondary clock"));
488
489         ActionManager::get_action ("Transport", "ToggleAutoReturn")->connect_proxy (auto_return_button);
490         ActionManager::get_action ("Transport", "ToggleAutoPlay")->connect_proxy (auto_play_button);
491         ActionManager::get_action ("Transport", "ToggleAutoInput")->connect_proxy (auto_input_button);
492         ActionManager::get_action ("Transport", "ToggleClick")->connect_proxy (click_button);
493         ActionManager::get_action ("Transport", "TogglePunchIn")->connect_proxy (punch_in_button);
494         ActionManager::get_action ("Transport", "TogglePunchOut")->connect_proxy (punch_out_button);
495
496         preroll_button.unset_flags (CAN_FOCUS);
497         preroll_button.set_events (preroll_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
498         preroll_button.set_name ("TransportButton");
499
500         postroll_button.unset_flags (CAN_FOCUS);
501         postroll_button.set_events (postroll_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
502         postroll_button.set_name ("TransportButton");
503
504         preroll_clock.set_mode (AudioClock::MinSec);
505         preroll_clock.set_name ("TransportClockDisplay");
506         postroll_clock.set_mode (AudioClock::MinSec);
507         postroll_clock.set_name ("TransportClockDisplay");
508
509         /* alerts */
510
511         /* CANNOT bind these to clicked or toggled, must use pressed or released */
512
513         solo_alert_button.set_name ("TransportSoloAlert");
514         solo_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::solo_alert_toggle));
515         auditioning_alert_button.set_name ("TransportAuditioningAlert");
516         auditioning_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::audition_alert_toggle));
517
518         alert_box.pack_start (solo_alert_button);
519         alert_box.pack_start (auditioning_alert_button);
520
521         transport_tearoff_hbox.set_border_width (5);
522
523         transport_tearoff_hbox.pack_start (goto_start_button, false, false);
524         transport_tearoff_hbox.pack_start (goto_end_button, false, false);
525
526         Frame* sframe = manage (new Frame);
527         VBox*  svbox = manage (new VBox);
528         HBox*  shbox = manage (new HBox);
529
530         sframe->set_shadow_type (SHADOW_IN);
531         sframe->add (shuttle_box);
532
533         shuttle_box.set_name (X_("ShuttleControl"));
534
535         speed_display_box.add (speed_display_label);
536         speed_display_box.set_name (X_("ShuttleDisplay"));
537
538         shuttle_units_button.set_name (X_("ShuttleButton"));
539         shuttle_units_button.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::shuttle_unit_clicked));
540         
541         shuttle_style_button.set_name (X_("ShuttleButton"));
542
543         vector<string> shuttle_strings;
544         shuttle_strings.push_back (_("sprung"));
545         shuttle_strings.push_back (_("wheel"));
546         set_popdown_strings (shuttle_style_button, shuttle_strings);
547         shuttle_style_button.signal_changed().connect (mem_fun (*this, &ARDOUR_UI::shuttle_style_changed));
548
549         Frame* sdframe = manage (new Frame);
550
551         sdframe->set_shadow_type (SHADOW_IN);
552         sdframe->add (speed_display_box);
553
554         mtc_port_changed ();
555         sync_option_combo.set_active_text (positional_sync_strings.front());
556         sync_option_combo.signal_changed().connect (mem_fun (*this, &ARDOUR_UI::sync_option_changed));
557
558         shbox->pack_start (*sdframe, false, false);
559         shbox->pack_start (shuttle_units_button, true, true);
560         shbox->pack_start (shuttle_style_button, false, false);
561         
562         svbox->pack_start (*sframe, false, false);
563         svbox->pack_start (*shbox, false, false);
564
565         transport_tearoff_hbox.pack_start (*svbox, false, false, 5);
566
567         transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
568         transport_tearoff_hbox.pack_start (play_selection_button, false, false);
569         transport_tearoff_hbox.pack_start (roll_button, false, false);
570         transport_tearoff_hbox.pack_start (stop_button, false, false);
571         transport_tearoff_hbox.pack_start (rec_button, false, false, 10);
572
573         transport_tearoff_hbox.pack_start (primary_clock, false, false, 5);
574         transport_tearoff_hbox.pack_start (secondary_clock, false, false, 5);
575
576         transport_tearoff_hbox.pack_start (sync_option_combo, false, false);
577         transport_tearoff_hbox.pack_start (time_master_button, false, false);
578         transport_tearoff_hbox.pack_start (punch_in_button, false, false);
579         transport_tearoff_hbox.pack_start (punch_out_button, false, false);
580         transport_tearoff_hbox.pack_start (auto_input_button, false, false);
581         transport_tearoff_hbox.pack_start (auto_return_button, false, false);
582         transport_tearoff_hbox.pack_start (auto_play_button, false, false);
583         transport_tearoff_hbox.pack_start (click_button, false, false);
584         
585         /* desensitize */
586
587         set_transport_sensitivity (false);
588
589 //      transport_tearoff_hbox.pack_start (preroll_button, false, false);
590 //      transport_tearoff_hbox.pack_start (preroll_clock, false, false);
591
592 //      transport_tearoff_hbox.pack_start (postroll_button, false, false);
593 //      transport_tearoff_hbox.pack_start (postroll_clock, false, false);
594
595         transport_tearoff_hbox.pack_start (alert_box, false, false, 5);
596 }
597
598 void
599 ARDOUR_UI::setup_clock ()
600 {
601         ARDOUR_UI::Clock.connect (bind (mem_fun (big_clock, &AudioClock::set), false));
602         
603         big_clock_window = new Window (WINDOW_TOPLEVEL);
604         
605         big_clock_window->set_border_width (0);
606         big_clock_window->add  (big_clock);
607         big_clock_window->set_title (_("ardour: clock"));
608         big_clock_window->set_type_hint (Gdk::WINDOW_TYPE_HINT_MENU);
609         big_clock_window->signal_realize().connect (bind (sigc::ptr_fun (set_decoration), big_clock_window,  (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
610         big_clock_window->signal_unmap().connect (bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleBigClock")));
611
612         manage_window (*big_clock_window);
613 }
614
615 void
616 ARDOUR_UI::manage_window (Window& win)
617 {
618         win.signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), &win));
619         win.signal_enter_notify_event().connect (bind (mem_fun (Keyboard::the_keyboard(), &Keyboard::enter_window), &win));
620         win.signal_leave_notify_event().connect (bind (mem_fun (Keyboard::the_keyboard(), &Keyboard::leave_window), &win));
621 }
622
623 void
624 ARDOUR_UI::detach_tearoff (Box* b, Widget* w)
625 {
626 //      editor->ensure_float (transport_tearoff->tearoff_window());
627         b->remove (*w);
628 }
629
630 void
631 ARDOUR_UI::reattach_tearoff (Box* b, Widget* w, int32_t n)
632 {
633         b->pack_start (*w);
634         b->reorder_child (*w, n);
635 }
636
637 void
638 ARDOUR_UI::soloing_changed (bool onoff)
639 {
640         if (solo_alert_button.get_active() != onoff) {
641                 solo_alert_button.set_active (onoff);
642         }
643 }
644
645 void
646 ARDOUR_UI::_auditioning_changed (bool onoff)
647 {
648         if (auditioning_alert_button.get_active() != onoff) {
649                 auditioning_alert_button.set_active (onoff);
650                 set_transport_sensitivity (!onoff);
651         }
652 }
653
654 void
655 ARDOUR_UI::auditioning_changed (bool onoff)
656 {
657         Gtkmm2ext::UI::instance()->call_slot(bind (mem_fun(*this, &ARDOUR_UI::_auditioning_changed), onoff));
658 }
659
660 void
661 ARDOUR_UI::audition_alert_toggle ()
662 {
663         if (session) {
664                 session->cancel_audition();
665         }
666 }
667
668 void
669 ARDOUR_UI::solo_alert_toggle ()
670 {
671         if (session) {
672                 session->set_all_solo (!session->soloing());
673         }
674 }
675
676 void
677 ARDOUR_UI::solo_blink (bool onoff)
678 {
679         if (session == 0) {
680                 return;
681         }
682         
683         if (session->soloing()) {
684                 if (onoff) {
685                         solo_alert_button.set_state (STATE_ACTIVE);
686                 } else {
687                         solo_alert_button.set_state (STATE_NORMAL);
688                 }
689         } else {
690                 solo_alert_button.set_active (false);
691                 solo_alert_button.set_state (STATE_NORMAL);
692         }
693 }
694
695 void
696 ARDOUR_UI::audition_blink (bool onoff)
697 {
698         if (session == 0) {
699                 return;
700         }
701         
702         if (session->is_auditioning()) {
703                 if (onoff) {
704                         auditioning_alert_button.set_state (STATE_ACTIVE);
705                 } else {
706                         auditioning_alert_button.set_state (STATE_NORMAL);
707                 }
708         } else {
709                 auditioning_alert_button.set_active (false);
710                 auditioning_alert_button.set_state (STATE_NORMAL);
711         }
712 }
713
714
715 gint
716 ARDOUR_UI::shuttle_box_button_press (GdkEventButton* ev)
717 {
718         if (!session) {
719                 return TRUE;
720         }
721
722         switch (ev->button) {
723         case 1:
724                 shuttle_box.add_modal_grab ();
725                 shuttle_grabbed = true;
726                 mouse_shuttle (ev->x, true);
727                 break;
728
729         case 2:
730         case 3:
731                 return TRUE;
732                 break;
733         }
734
735         return TRUE;
736 }
737
738 gint
739 ARDOUR_UI::shuttle_box_button_release (GdkEventButton* ev)
740 {
741         if (!session) {
742                 return TRUE;
743         }
744
745         switch (ev->button) {
746         case 1:
747                 mouse_shuttle (ev->x, true);
748                 shuttle_grabbed = false;
749                 shuttle_box.remove_modal_grab ();
750                 if (shuttle_behaviour == Sprung) {
751                         shuttle_fract = SHUTTLE_FRACT_SPEED1;
752                         session->request_transport_speed (1.0);
753                         shuttle_box.queue_draw ();
754                 }
755                 return TRUE;
756
757         case 2:
758                 if (session->transport_rolling()) {
759                         shuttle_fract = SHUTTLE_FRACT_SPEED1;
760                         session->request_transport_speed (1.0);
761                 } else {
762                         shuttle_fract = 0;
763                 }
764                 shuttle_box.queue_draw ();
765                 return TRUE;
766
767         case 3:
768                 return TRUE;
769                 
770         case 4:
771                 shuttle_fract += 0.005;
772                 break;
773         case 5:
774                 shuttle_fract -= 0.005;
775                 break;
776         }
777
778         use_shuttle_fract (true);
779
780         return TRUE;
781 }
782
783 gint
784 ARDOUR_UI::shuttle_box_motion (GdkEventMotion* ev)
785 {
786         if (!session || !shuttle_grabbed) {
787                 return TRUE;
788         }
789
790         return mouse_shuttle (ev->x, false);
791 }
792
793 gint
794 ARDOUR_UI::mouse_shuttle (double x, bool force)
795 {
796         double half_width = shuttle_box.get_width() / 2.0;
797         double distance = x - half_width;
798
799         if (distance > 0) {
800                 distance = min (distance, half_width);
801         } else {
802                 distance = max (distance, -half_width);
803         }
804
805         shuttle_fract = distance / half_width;
806         use_shuttle_fract (force);
807         return TRUE;
808 }
809
810 void
811 ARDOUR_UI::use_shuttle_fract (bool force)
812 {
813         struct timeval now;
814         struct timeval diff;
815         
816         /* do not attempt to submit a motion-driven transport speed request
817            more than once per process cycle.
818          */
819
820         gettimeofday (&now, 0);
821         timersub (&now, &last_shuttle_request, &diff);
822
823         if (!force && (diff.tv_usec + (diff.tv_sec * 1000000)) < engine->usecs_per_cycle()) {
824                 return;
825         }
826         
827         last_shuttle_request = now;
828
829         bool neg = (shuttle_fract < 0.0);
830
831         double fract = 1 - sqrt (1 - (shuttle_fract * shuttle_fract)); // Formula A1
832
833         if (neg) {
834                 fract = -fract;
835         }
836
837         session->request_transport_speed (8.0 * fract); // Formula A2
838         shuttle_box.queue_draw ();
839 }
840
841 gint
842 ARDOUR_UI::shuttle_box_expose (GdkEventExpose* event)
843 {
844         gint x;
845         Glib::RefPtr<Gdk::Window> win (shuttle_box.get_window());
846
847         /* redraw the background */
848
849         win->draw_rectangle (shuttle_box.get_style()->get_bg_gc (shuttle_box.get_state()),
850                              true,
851                              event->area.x, event->area.y,
852                              event->area.width, event->area.height);
853
854
855         x = (gint) floor ((shuttle_box.get_width() / 2.0) + (0.5 * (shuttle_box.get_width() * shuttle_fract)));
856
857         /* draw line */
858
859         win->draw_line (shuttle_box.get_style()->get_fg_gc (shuttle_box.get_state()),
860                         x,
861                         0,
862                         x,
863                         shuttle_box.get_height());
864         return TRUE;
865 }
866
867 void
868 ARDOUR_UI::shuttle_unit_clicked ()
869 {
870         if (shuttle_unit_menu == 0) {
871                 shuttle_unit_menu = dynamic_cast<Menu*> (ActionManager::get_widget ("/ShuttleUnitPopup"));
872         }
873         shuttle_unit_menu->popup (1, 0);
874 }
875
876 void
877 ARDOUR_UI::set_shuttle_units (ShuttleUnits u)
878 {
879         switch ((shuttle_units = u)) {
880         case Percentage:
881                 static_cast<Label*>(shuttle_units_button.get_child())->set_text ("% ");
882                 break;
883         case Semitones:
884                 static_cast<Label*>(shuttle_units_button.get_child())->set_text (_("st"));
885                 break;
886         }
887 }
888
889 void
890 ARDOUR_UI::shuttle_style_changed ()
891 {
892         ustring str = shuttle_style_button.get_active_text ();
893
894         if (str == _("sprung")) {
895                 set_shuttle_behaviour (Sprung);
896         } else if (str == _("wheel")) {
897                 set_shuttle_behaviour (Wheel);
898         }
899 }
900
901
902 void
903 ARDOUR_UI::set_shuttle_behaviour (ShuttleBehaviour b)
904 {
905         switch ((shuttle_behaviour = b)) {
906         case Sprung:
907                 shuttle_style_button.set_active_text (_("sprung"));
908                 shuttle_fract = 0.0;
909                 shuttle_box.queue_draw ();
910                 if (session) {
911                         if (session->transport_rolling()) {
912                                 shuttle_fract = SHUTTLE_FRACT_SPEED1;
913                                 session->request_transport_speed (1.0);
914                         }
915                 }
916                 break;
917         case Wheel:
918                 shuttle_style_button.set_active_text (_("wheel"));
919                 break;
920         }
921 }
922
923 void
924 ARDOUR_UI::update_speed_display ()
925 {
926         if (!session) {
927                 if (last_speed_displayed != 0) {
928                         speed_display_label.set_text (_("stopped"));
929                         last_speed_displayed = 0;
930                 }
931                 return;
932         }
933
934         char buf[32];
935         float x = session->transport_speed ();
936
937         if (x != last_speed_displayed) {
938
939                 if (x != 0) {
940                         if (shuttle_units == Percentage) {
941                                 snprintf (buf, sizeof (buf), "%.4f", x);
942                         } else {
943                                 if (x < 0) {
944                                         snprintf (buf, sizeof (buf), "< %.1f", 12.0 * fast_log2 (-x));
945                                 } else {
946                                         snprintf (buf, sizeof (buf), "> %.1f", 12.0 * fast_log2 (x));
947                                 }
948                         }
949                         speed_display_label.set_text (buf);
950                 } else {
951                         speed_display_label.set_text (_("stopped"));
952                 }
953
954                 last_speed_displayed = x;
955         }
956 }       
957         
958 void
959 ARDOUR_UI::set_transport_sensitivity (bool yn)
960 {
961         ActionManager::set_sensitive (ActionManager::transport_sensitive_actions, yn);
962         shuttle_box.set_sensitive (yn);
963 }
964
965 void
966 ARDOUR_UI::editor_realized ()
967 {
968         set_size_request_to_display_given_text (speed_display_box, _("stopped"), 2, 2);
969         /* XXX: this should really be saved in instant.xml or something similar and restored from there */
970         shuttle_style_button.set_active_text (_("sprung"));
971         const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button
972         set_size_request_to_display_given_text (shuttle_style_button, _("sprung"), 2+FUDGE, 10);
973 }
974
975 void
976 ARDOUR_UI::sync_option_changed ()
977 {
978         string which;
979
980         if (session == 0) {
981                 return;
982         }
983
984         which = sync_option_combo.get_active_text();
985
986         if (which == positional_sync_strings[Session::None]) {
987                 session->request_slave_source (Session::None);
988         } else if (which == positional_sync_strings[Session::MTC]) {
989                 session->request_slave_source (Session::MTC);
990         } else if (which == positional_sync_strings[Session::JACK]) {
991                 session->request_slave_source (Session::JACK);
992         } 
993 }
994
995 void
996 ARDOUR_UI::maximise_editing_space ()
997 {
998         if (!editor) {
999                 return;
1000         }
1001
1002         transport_tearoff->set_visible (false);
1003         editor->maximise_editing_space ();
1004 }
1005
1006 void
1007 ARDOUR_UI::restore_editing_space ()
1008 {
1009         if (!editor) {
1010                 return;
1011         }
1012
1013         transport_tearoff->set_visible (true);
1014         editor->restore_editing_space ();
1015 }