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