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