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