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