a long tricky day of playing with ArdourStartup and session naming/loading etc.
[ardour.git] / gtk2_ardour / route_ui.cc
1 /*
2     Copyright (C) 2002-2006 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/stop_signal.h>
22 #include <gtkmm2ext/choice.h>
23 #include <gtkmm2ext/doi.h>
24 #include <gtkmm2ext/bindable_button.h>
25 #include <gtkmm2ext/barcontroller.h>
26 #include <gtkmm2ext/gtk_ui.h>
27
28 #include "ardour/route_group.h"
29 #include "pbd/memento_command.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/shiva.h"
32 #include "pbd/controllable.h"
33
34 #include "route_ui.h"
35 #include "keyboard.h"
36 #include "utils.h"
37 #include "prompter.h"
38 #include "gui_thread.h"
39 #include "ardour_dialog.h"
40 #include "latency_gui.h"
41 #include "automation_time_axis.h"
42
43 #include "ardour/route.h"
44 #include "ardour/session.h"
45 #include "ardour/audioengine.h"
46 #include "ardour/audio_track.h"
47 #include "ardour/audio_diskstream.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/midi_diskstream.h"
50 #include "ardour/template_utils.h"
51 #include "ardour/filename_extensions.h"
52 #include "ardour/directory_names.h"
53 #include "ardour/profile.h"
54
55 #include "i18n.h"
56 using namespace sigc;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59 using namespace ARDOUR;
60 using namespace PBD;
61
62 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
63         : AxisView(sess)
64 {
65         init ();
66         set_button_names (mute_name, solo_name, rec_name);
67 }
68
69 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, 
70                   ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
71         : AxisView(sess)
72 {
73         init ();
74         set_button_names (mute_name, solo_name, rec_name);
75         set_route (rt);
76 }
77
78 RouteUI::~RouteUI()
79 {
80        /* derived classes should emit GoingAway so that they receive the signal
81           when the object is still a legal derived instance.
82        */
83         
84         delete solo_menu;
85         delete mute_menu;
86         delete remote_control_menu;
87 }
88
89 void
90 RouteUI::init ()
91 {
92         self_destruct = true;
93         xml_node = 0;
94         mute_menu = 0;
95         solo_menu = 0;
96         remote_control_menu = 0;
97         ignore_toggle = false;
98         wait_for_release = false;
99         route_active_menu_item = 0;
100         was_solo_safe = false;
101         polarity_menu_item = 0;
102         denormal_menu_item = 0;
103         multiple_mute_change = false;
104         multiple_solo_change = false;
105
106         mute_button = manage (new BindableToggleButton (""));
107         mute_button->set_self_managed (true);
108         mute_button->set_name ("MuteButton");
109         UI::instance()->set_tip (mute_button, _("Mute this track"), "");
110
111         solo_button = manage (new BindableToggleButton (""));
112         solo_button->set_self_managed (true);
113         solo_button->set_name ("SoloButton");
114         UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
115
116         rec_enable_button = manage (new BindableToggleButton (""));
117         rec_enable_button->set_name ("RecordEnableButton");
118         rec_enable_button->set_self_managed (true);
119         UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
120
121         _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
122 }
123
124 void
125 RouteUI::reset ()
126 {
127         connections.clear ();
128
129         delete solo_menu;
130         solo_menu = 0;
131
132         delete mute_menu;
133         mute_menu = 0;
134         
135         if (xml_node) {
136                 /* do not delete the node - its owned by the route */
137                 xml_node = 0;
138         }
139
140         route_active_menu_item = 0;
141         polarity_menu_item = 0;
142         denormal_menu_item = 0;
143 }
144
145 void
146 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
147 {
148         m_name = mute;
149         s_name = solo;
150         r_name = rec;
151 }
152
153 void
154 RouteUI::set_route (boost::shared_ptr<Route> rp)
155 {
156         reset ();
157
158         _route = rp;
159
160         if (set_color_from_route()) {
161                 set_color (unique_random_color());
162         }
163
164         /* no, there is no memory leak here. This object cleans itself (and other stuff)
165            up when the route is destroyed.
166         */
167
168         if (self_destruct) {
169                 new PairedShiva<Route,RouteUI> (*_route, *this);
170         }
171
172         mute_button->set_controllable (_route->mute_control());
173         mute_button->set_label (m_name);
174         
175         solo_button->set_controllable (_route->solo_control());
176         solo_button->set_label (s_name);
177   
178         connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
179         connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
180         connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
181         connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
182   
183         /* when solo changes, update mute state too, in case the user wants us to display it */
184
185         _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
186         
187         if (is_track()) {
188                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
189
190                 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
191                 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
192
193                 rec_enable_button->show();
194                 rec_enable_button->set_controllable (t->rec_enable_control());
195                 rec_enable_button->set_label (r_name);
196
197                 update_rec_display ();
198         } 
199
200         mute_button->unset_flags (Gtk::CAN_FOCUS);
201         solo_button->unset_flags (Gtk::CAN_FOCUS);
202         
203         mute_button->show();
204         solo_button->show();
205
206         connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
207
208         /* map the current state */
209
210         map_frozen ();
211 }
212
213 bool
214 RouteUI::mute_press(GdkEventButton* ev)
215 {
216         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
217                 return true;
218         }
219         multiple_mute_change = false;
220         if (!ignore_toggle) {
221
222                 if (Keyboard::is_context_menu_event (ev)) {
223
224                         if (mute_menu == 0){
225                                 build_mute_menu();
226                         }
227
228                         mute_menu->popup(0,ev->time);
229
230                 } else {
231
232                         if (Keyboard::is_button2_event (ev)) {
233                                 // Primary-button2 click is the midi binding click
234                                 // button2-click is "momentary"
235                                 
236                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
237                                         wait_for_release = true;
238                                 } else {
239                                         return false;
240                                 }
241                         }
242
243                         if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
244
245                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
246
247                                         /* Primary-Tertiary-click applies change to all routes */
248
249                                         _session.begin_reversible_command (_("mute change"));
250                                         Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
251                                         _session.set_all_mute (!_route->muted());
252                                         cmd->mark();
253                                         _session.add_command(cmd);
254                                         _session.commit_reversible_command ();
255                                         multiple_mute_change = true;
256
257                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
258
259                                         /* Primary-button1 applies change to the mix group.
260                                            NOTE: Primary-button2 is MIDI learn.
261                                         */
262
263                                         if (ev->button == 1) {
264                                                 set_mix_group_mute (_route, !_route->muted());
265                                         }
266                                         
267                                 } else {
268
269                                         /* plain click applies change to this route */
270                                         if (wait_for_release) {
271                                                 _route->set_mute (!_route->muted(), this);
272                                         } else {
273                                                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
274                                         }
275                                 }
276                         }
277                 }
278
279         }
280
281         return true;
282 }
283
284 bool
285 RouteUI::mute_release(GdkEventButton* ev)
286 {
287         if (!ignore_toggle) {
288                 if (wait_for_release){
289                         wait_for_release = false;
290                         if (multiple_mute_change) {
291                                 multiple_mute_change = false;
292                                 // undo the last op
293                                 // because the press was the last undoable thing we did
294                                 _session.undo (1U);
295                         } else {
296                                 _route->set_mute (!_route->muted(), this);
297                         }
298                 }
299         }
300         return true;
301 }
302
303 bool
304 RouteUI::solo_press(GdkEventButton* ev)
305 {
306         /* ignore double/triple clicks */
307
308         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
309                 return true;
310         }
311         multiple_solo_change = false;
312         if (!ignore_toggle) {
313
314                 if (Keyboard::is_context_menu_event (ev)) {
315
316                         if (solo_menu == 0) {
317                                 build_solo_menu ();
318                         }
319
320                         solo_menu->popup (1, ev->time);
321
322                 } else {
323
324                         if (Keyboard::is_button2_event (ev)) {
325
326                                 // Primary-button2 click is the midi binding click
327                                 // button2-click is "momentary"
328                                 
329                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
330                                         wait_for_release = true;
331                                 } else {
332                                         return false;
333                                 }
334                         }
335
336                         if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
337
338                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
339
340                                         /* Primary-Tertiary-click applies change to all routes */
341                                         bool was_not_latched = false;
342                                         if (!Config->get_solo_latched ()) {
343                                                 was_not_latched = true;
344                                                 /*
345                                                   XXX it makes no sense to solo all tracks if we're 
346                                                   not in latched mode, but doing nothing feels like a bug, 
347                                                   so do it anyway 
348                                                 */
349                                                 Config->set_solo_latched (true);
350                                         }
351                                         _session.begin_reversible_command (_("solo change"));
352                                         Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
353                                         _session.set_all_solo (!_route->soloed());
354                                         cmd->mark();
355                                         _session.add_command (cmd);
356                                         _session.commit_reversible_command ();
357                                         multiple_solo_change = true;
358                                         if (was_not_latched) {
359                                                 Config->set_solo_latched (false);
360                                         }
361                                         
362                                 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
363
364                                         // Primary-Secondary-click: exclusively solo this track, not a toggle */
365
366                                         _session.begin_reversible_command (_("solo change"));
367                                         Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
368                                         _session.set_all_solo (false);
369                                         _route->set_solo (true, this);
370                                         cmd->mark();
371                                         _session.add_command(cmd);
372                                         _session.commit_reversible_command ();
373
374                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
375
376                                         // shift-click: set this route to solo safe
377
378                                         if (Profile->get_sae() && ev->button == 1) {
379                                                 // button 1 and shift-click: disables solo_latched for this click
380                                                 if (!Config->get_solo_latched ()) {
381                                                         Config->set_solo_latched (true);
382                                                         reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
383                                                         Config->set_solo_latched (false);
384                                                 }
385                                         } else {
386                                                 _route->set_solo_safe (!_route->solo_safe(), this);
387                                                 wait_for_release = false;
388                                         }
389
390                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
391
392                                         /* Primary-button1: solo mix group.
393                                            NOTE: Primary-button2 is MIDI learn.
394                                         */
395
396                                         if (ev->button == 1) {
397                                                 set_mix_group_solo (_route, !_route->soloed());
398                                         }
399
400                                 } else {
401
402                                         /* click: solo this route */
403                                         if (wait_for_release) {
404                                                 _route->set_solo (!_route->soloed(), this);
405                                         } else {
406                                                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
407                                         }
408                                 }
409                         }
410                 }
411         }
412
413         return true;
414 }
415
416 bool
417 RouteUI::solo_release(GdkEventButton* ev)
418 {
419         if (!ignore_toggle) {
420                 if (wait_for_release) {
421                         wait_for_release = false;
422                         if (multiple_solo_change) {
423                                 multiple_solo_change = false;
424                                 // undo the last op
425                                 // because the press was the last undoable thing we did
426                                 _session.undo (1U);
427                         } else {
428                                 // we don't use "undo the last op"
429                                 // here because its expensive for the GUI
430                                 _route->set_solo (!_route->soloed(), this);
431                         }
432                 }
433         }
434
435         return true;
436 }
437
438 bool
439 RouteUI::rec_enable_press(GdkEventButton* ev)
440 {
441         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
442                 return true;
443         }
444
445         if (!_session.engine().connected()) {
446                 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
447                 msg.run ();
448                 return true;
449         }
450
451         if (!ignore_toggle && is_track() && rec_enable_button) {
452
453                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
454
455                         // do nothing on midi bind event
456                         return false;
457
458                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
459
460                         _session.begin_reversible_command (_("rec-enable change"));
461                         Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
462
463                         if (rec_enable_button->get_active()) {
464                                 _session.record_disenable_all ();
465                         } else {
466                                 _session.record_enable_all ();
467                         }
468
469                         cmd->mark();
470                         _session.add_command(cmd);
471                         _session.commit_reversible_command ();
472
473                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
474
475                         /* Primary-button1 applies change to the mix group.
476                            NOTE: Primary-button2 is MIDI learn.
477                         */
478
479                         set_mix_group_rec_enable (_route, !_route->record_enabled());
480
481                 } else {
482
483                         reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
484                 }
485         }
486
487         return true;
488 }
489
490 bool
491 RouteUI::rec_enable_release (GdkEventButton* ev)
492 {
493         return true;
494 }
495
496 void
497 RouteUI::solo_changed(void* src)
498 {
499
500         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
501 }
502
503 void
504 RouteUI::update_solo_display ()
505 {
506         bool x;
507         vector<Gdk::Color> fg_colors;
508         Gdk::Color c;
509         
510         if (solo_button->get_active() != (x = _route->soloed())){
511                 ignore_toggle = true;
512                 solo_button->set_active(x);
513                 ignore_toggle = false;
514         } 
515         
516         if (_route->solo_safe()) {
517                 solo_button->set_visual_state (2);
518         } else if (_route->soloed()) {
519                 solo_button->set_visual_state (1);
520         } else {
521                 solo_button->set_visual_state (0);
522         }
523 }
524
525 void
526 RouteUI::solo_changed_so_update_mute ()
527 {
528         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
529 }
530
531 void
532 RouteUI::mute_changed(void* src)
533 {
534         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
535 }
536
537 void
538 RouteUI::update_mute_display ()
539 {
540         bool model = _route->muted();
541         bool view = mute_button->get_active();
542
543         /* first make sure the button's "depressed" visual
544            is correct.
545         */
546
547         if (model != view) {
548                 ignore_toggle = true;
549                 mute_button->set_active (model);
550                 ignore_toggle = false;
551         }
552
553         /* now attend to visual state */
554         
555         if (Config->get_show_solo_mutes()) {
556                 if (_route->muted()) {
557                         mute_button->set_visual_state (2);
558                 } else if (!_route->soloed() && _route->solo_muted()) {
559                         
560                         mute_button->set_visual_state (1);
561                 } else {
562                         mute_button->set_visual_state (0);
563                 }
564         } else {
565                 if (_route->muted()) {
566                         mute_button->set_visual_state (2);
567                 } else {
568                         mute_button->set_visual_state (0);
569                 }
570         }
571
572 }
573
574 void
575 RouteUI::route_rec_enable_changed ()
576 {
577         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
578 }
579
580 void
581 RouteUI::session_rec_enable_changed ()
582 {
583         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
584 }
585
586 void
587 RouteUI::update_rec_display ()
588 {
589         bool model = _route->record_enabled();
590         bool view = rec_enable_button->get_active();
591
592         /* first make sure the button's "depressed" visual
593            is correct.
594         */
595
596         if (model != view) {
597                 ignore_toggle = true;
598                 rec_enable_button->set_active (model);
599                 ignore_toggle = false;
600         }
601         
602         /* now make sure its color state is correct */
603
604         if (model) {
605
606                 switch (_session.record_status ()) {
607                 case Session::Recording:
608                         rec_enable_button->set_visual_state (1);
609                         break;
610
611                 case Session::Disabled:
612                 case Session::Enabled:
613                         rec_enable_button->set_visual_state (2);
614                         break;
615
616                 }
617
618         } else {
619                 rec_enable_button->set_visual_state (0);
620         }
621 }
622
623 void
624 RouteUI::build_remote_control_menu ()
625 {
626         remote_control_menu = new Menu;
627         refresh_remote_control_menu ();
628 }
629
630 void
631 RouteUI::refresh_remote_control_menu ()
632 {
633         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
634
635         // only refresh the menu if it has been instantiated
636
637         if (remote_control_menu == 0) {
638                 return;
639         }
640
641         using namespace Menu_Helpers;
642
643         RadioMenuItem::Group rc_group;
644         CheckMenuItem* rc_active;
645         uint32_t limit = _session.ntracks() + _session.nbusses();
646         char buf[32];
647
648         MenuList& rc_items = remote_control_menu->items();
649         rc_items.clear ();
650
651         /* note that this menu list starts at zero, not 1, because zero
652            is a valid, if useless, ID.
653         */
654
655         limit += 4; /* leave some breathing room */
656         
657         rc_items.push_back (RadioMenuElem (rc_group, _("None")));
658         if (_route->remote_control_id() == 0) {
659                 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
660                 rc_active->set_active ();
661         }
662                 
663         for (uint32_t i = 1; i < limit; ++i) {
664                 snprintf (buf, sizeof (buf), "%u", i);
665                 rc_items.push_back (RadioMenuElem (rc_group, buf));
666                 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
667                 if (_route->remote_control_id() == i) {
668                         rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
669                         rc_active->set_active ();
670                 }
671                 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
672         }
673 }
674
675 void
676 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
677 {
678         /* this is called when the radio menu item is toggled, and so 
679            is actually invoked twice per menu selection. we only
680            care about the invocation for the item that was being
681            marked active.
682         */
683
684         if (item->get_active()) {
685                 _route->set_remote_control_id (id);
686         }
687 }
688
689 void
690 RouteUI::build_solo_menu (void)
691 {
692         using namespace Menu_Helpers;
693         
694         solo_menu = new Menu;
695         solo_menu->set_name ("ArdourContextMenu");
696         MenuList& items = solo_menu->items();
697         CheckMenuItem* check;
698
699         check = new CheckMenuItem(_("Solo-safe"));
700         check->set_active (_route->solo_safe());
701         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
702         _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
703         items.push_back (CheckMenuElem(*check));
704         check->show_all();
705
706         //items.push_back (SeparatorElem());
707         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
708         
709 }
710
711 void
712 RouteUI::build_mute_menu(void)
713 {
714         using namespace Menu_Helpers;
715         
716         mute_menu = new Menu;
717         mute_menu->set_name ("ArdourContextMenu");
718         MenuList& items = mute_menu->items();
719         CheckMenuItem* check;
720         
721         check = new CheckMenuItem(_("Pre Fader"));
722         init_mute_menu(PRE_FADER, check);
723         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
724         _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
725         items.push_back (CheckMenuElem(*check));
726         check->show_all();
727
728         check = new CheckMenuItem(_("Post Fader"));
729         init_mute_menu(POST_FADER, check);
730         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
731         _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
732         items.push_back (CheckMenuElem(*check));
733         check->show_all();
734         
735         check = new CheckMenuItem(_("Control Outs"));
736         init_mute_menu(CONTROL_OUTS, check);
737         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
738         _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
739         items.push_back (CheckMenuElem(*check));
740         check->show_all();
741
742         check = new CheckMenuItem(_("Main Outs"));
743         init_mute_menu(MAIN_OUTS, check);
744         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
745         _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
746         items.push_back (CheckMenuElem(*check));
747         check->show_all();
748
749         //items.push_back (SeparatorElem());
750         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
751 }
752
753 void
754 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
755 {
756         if (_route->get_mute_config (type)) {
757                 check->set_active (true);
758         }
759 }
760
761 void
762 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
763 {
764         _route->set_mute_config(type, check->get_active(), this);
765 }
766
767 void
768 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
769 {
770         _route->set_solo_safe (check->get_active(), this);
771 }
772
773 void
774 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
775 {
776         RouteGroup* mix_group;
777
778         if((mix_group = route->mix_group()) != 0){
779                 _session.begin_reversible_command (_("mix group solo  change"));
780                 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
781                 mix_group->apply(&Route::set_solo, yn, this);
782                 cmd->mark();
783                 _session.add_command (cmd);
784                 _session.commit_reversible_command ();
785         } else {
786                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
787         }
788 }
789
790 void
791 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
792 {
793         _session.begin_reversible_command (name);
794         XMLNode &before = _route->get_state();
795         bind(mem_fun(*_route, func), yn, arg)();
796         XMLNode &after = _route->get_state();
797         _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
798         _session.commit_reversible_command ();
799 }
800
801 void
802 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
803 {
804         _session.begin_reversible_command (name);
805         XMLNode &before = track()->get_state();
806         bind (mem_fun (*track(), func), yn, arg)();
807         XMLNode &after = track()->get_state();
808         _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
809         _session.commit_reversible_command ();
810 }
811
812 void
813 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
814 {
815         RouteGroup* mix_group;
816
817         if((mix_group = route->mix_group()) != 0){
818                 _session.begin_reversible_command (_("mix group mute change"));
819                 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
820                 mix_group->apply(&Route::set_mute, yn, this);
821                 cmd->mark();
822                 _session.add_command(cmd);
823                 _session.commit_reversible_command ();
824         } else {
825                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
826         }
827 }
828
829 void
830 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
831 {
832         RouteGroup* mix_group;
833
834         if((mix_group = route->mix_group()) != 0){
835                 _session.begin_reversible_command (_("mix group rec-enable change"));
836                 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
837                 mix_group->apply (&Route::set_record_enable, yn, this);
838                 cmd->mark();
839                 _session.add_command(cmd);
840                 _session.commit_reversible_command ();
841         } else {
842                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
843         }
844 }
845
846
847 bool
848 RouteUI::choose_color()
849 {
850         bool picked;
851         Gdk::Color color;
852
853         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
854
855         if (picked) {
856                 set_color (color);
857         }
858
859         return picked;
860 }
861
862 void
863 RouteUI::set_color (const Gdk::Color & c)
864 {
865         char buf[64];
866         
867         _color = c;
868         
869         ensure_xml_node ();
870         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
871         xml_node->add_property ("color", buf);
872
873         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
874 }
875
876
877 void
878 RouteUI::ensure_xml_node ()
879 {
880         if (xml_node == 0) {
881                 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
882                         xml_node = new XMLNode ("GUI");
883                         _route->add_extra_xml (*xml_node);
884                 }
885         }
886 }
887
888 XMLNode*
889 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
890 {
891         ensure_xml_node ();
892         
893         XMLNodeList kids = xml_node->children();
894         XMLNodeConstIterator iter;
895
896         const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
897
898         for (iter = kids.begin(); iter != kids.end(); ++iter) {
899                 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
900                         XMLProperty* type = (*iter)->property("automation-id");
901                         if (type && type->value() == sym)
902                                 return *iter;
903                 }
904         }
905
906         // Didn't find it, make a new one
907         XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
908         child->add_property("automation-id", sym);
909         xml_node->add_child_nocopy (*child);
910
911         return child;
912 }
913
914 int
915 RouteUI::set_color_from_route ()
916 {
917         XMLProperty *prop;
918         
919         RouteUI::ensure_xml_node ();
920
921         if ((prop = xml_node->property ("color")) != 0) {
922                 int r, g, b;
923                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
924                 _color.set_red(r);
925                 _color.set_green(g);
926                 _color.set_blue(b);
927                 return 0;
928         } 
929         return 1;
930 }
931
932 void
933 RouteUI::remove_this_route ()
934 {
935         vector<string> choices;
936         string prompt;
937
938         if (is_track()) {
939                 prompt  = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n(cannot be undone)"), _route->name());
940         } else {
941                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
942         }
943
944         choices.push_back (_("No, do nothing."));
945         choices.push_back (_("Yes, remove it."));
946
947         Choice prompter (prompt, choices);
948
949         if (prompter.run () == 1) {
950                 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
951         }
952 }
953
954 gint
955 RouteUI::idle_remove_this_route (RouteUI *rui)
956 {
957         rui->_session.remove_route (rui->_route);
958         return false;
959 }
960
961 void
962 RouteUI::route_rename ()
963 {
964         ArdourPrompter name_prompter (true);
965         string result;
966         name_prompter.set_prompt (_("New Name: "));
967         name_prompter.set_initial_text (_route->name());
968         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
969         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
970         name_prompter.show_all ();
971
972         switch (name_prompter.run ()) {
973
974         case Gtk::RESPONSE_ACCEPT:
975         name_prompter.get_result (result);
976         if (result.length()) {
977                         _route->set_name (result);
978                 }       
979                 break;
980         }
981
982         return;
983   
984 }
985
986 void
987 RouteUI::name_changed ()
988 {
989         ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
990
991         name_label.set_text (_route->name());
992 }
993
994 void
995 RouteUI::toggle_route_active ()
996 {
997         bool yn;
998
999         if (route_active_menu_item) {
1000                 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1001                         _route->set_active (!yn);
1002                 }
1003         }
1004 }
1005
1006 void
1007 RouteUI::route_active_changed ()
1008 {
1009         if (route_active_menu_item) {
1010                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1011         }
1012 }
1013
1014 void
1015 RouteUI::toggle_polarity ()
1016 {
1017         if (polarity_menu_item) {
1018
1019                 bool x;
1020
1021                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1022                 
1023                 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1024                         _route->set_phase_invert (x, this);
1025                         if (x) {
1026                                 name_label.set_text (X_("Ø ") + name_label.get_text());
1027                         } else {
1028                                 name_label.set_text (_route->name());
1029                         }
1030                 }
1031         }
1032 }
1033
1034 void
1035 RouteUI::polarity_changed ()
1036 {
1037         /* no signal for this yet */
1038 }
1039
1040 void
1041 RouteUI::toggle_denormal_protection ()
1042 {
1043         if (denormal_menu_item) {
1044
1045                 bool x;
1046
1047                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1048                 
1049                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1050                         _route->set_denormal_protection (x, this);
1051                 }
1052         }
1053 }
1054
1055 void
1056 RouteUI::denormal_protection_changed ()
1057 {
1058         /* no signal for this yet */
1059 }
1060
1061
1062 void
1063 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1064 {
1065         bool yn = _route->solo_safe ();
1066
1067         if (check->get_active() != yn) {
1068                 check->set_active (yn);
1069         }
1070 }
1071 void
1072 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1073 {
1074         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1075         
1076         bool yn = _route->get_mute_config(PRE_FADER);
1077         if (check->get_active() != yn) {
1078                 check->set_active (yn);
1079         }
1080 }
1081
1082 void
1083 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1084 {
1085         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1086         
1087         bool yn = _route->get_mute_config(POST_FADER);
1088         if (check->get_active() != yn) {
1089                 check->set_active (yn);
1090         }
1091 }
1092
1093 void
1094 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1095 {
1096         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1097         
1098         bool yn = _route->get_mute_config(CONTROL_OUTS);
1099         if (check->get_active() != yn) {
1100                 check->set_active (yn);
1101         }
1102 }
1103
1104 void
1105 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1106 {
1107         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1108         
1109         bool yn = _route->get_mute_config(MAIN_OUTS);
1110         if (check->get_active() != yn) {
1111                 check->set_active (yn);
1112         }
1113 }
1114
1115 void
1116 RouteUI::disconnect_input ()
1117 {
1118         _route->disconnect_inputs (this);
1119 }
1120
1121 void
1122 RouteUI::disconnect_output ()
1123 {
1124         _route->disconnect_outputs (this);
1125 }
1126
1127 bool
1128 RouteUI::is_track () const
1129 {
1130         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1131 }
1132
1133 boost::shared_ptr<Track>
1134 RouteUI::track() const
1135 {
1136         return boost::dynamic_pointer_cast<Track>(_route);
1137 }
1138
1139 bool
1140 RouteUI::is_audio_track () const
1141 {
1142         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1143 }
1144
1145 boost::shared_ptr<AudioTrack>
1146 RouteUI::audio_track() const
1147 {
1148         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1149 }
1150
1151 bool
1152 RouteUI::is_midi_track () const
1153 {
1154         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1155 }
1156
1157 boost::shared_ptr<MidiTrack>
1158 RouteUI::midi_track() const
1159 {
1160         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1161 }
1162
1163 boost::shared_ptr<Diskstream>
1164 RouteUI::get_diskstream () const
1165 {
1166         boost::shared_ptr<Track> t;
1167
1168         if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1169                 return t->diskstream();
1170         } else {
1171                 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1172         }
1173 }
1174
1175 string
1176 RouteUI::name() const
1177 {
1178         return _route->name();
1179 }
1180
1181 void
1182 RouteUI::map_frozen ()
1183 {
1184         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1185
1186         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1187
1188         if (at) {
1189                 switch (at->freeze_state()) {
1190                 case AudioTrack::Frozen:
1191                         rec_enable_button->set_sensitive (false);
1192                         break;
1193                 default:
1194                         rec_enable_button->set_sensitive (true);
1195                         break;
1196                 }
1197         }
1198 }
1199
1200 void
1201 RouteUI::adjust_latency ()
1202 {
1203         LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());
1204 }
1205
1206 void
1207 RouteUI::save_as_template ()
1208 {
1209         sys::path path;
1210         Glib::ustring safe_name;
1211         string name;
1212         
1213         path = ARDOUR::user_route_template_directory ();
1214         
1215         if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1216                 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1217                 return;
1218         }
1219         
1220         Prompter p (true); // modal
1221         
1222         p.set_prompt (_("Template name:"));
1223         switch (p.run()) {
1224         case RESPONSE_ACCEPT:
1225                 break;
1226         default:
1227                 return;
1228         }
1229         
1230         p.hide ();
1231         p.get_result (name, true);
1232         
1233         safe_name = legalize_for_path (name);
1234         safe_name += template_suffix;
1235         
1236         path /= safe_name;
1237         
1238         _route->save_as_template (path.to_string(), name);
1239 }