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