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