ba805f7d4bc23b05db266624eb8c1555ba9a8293
[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 (t->diskstream()->RecordEnableChanged.connect (mem_fun (PublicEditor::instance(), &PublicEditor::update_rec_display)));
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_master()) {
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"), mem_fun (*this, &RouteUI::create_sends)));
530         items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
531         items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
532         items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
533
534 }
535
536 void
537 RouteUI::create_sends ()
538 {
539         _session.globally_add_internal_sends (_route);
540 }
541
542 void
543 RouteUI::set_sends_gain_from_track ()
544 {
545 }
546
547 void
548 RouteUI::set_sends_gain_to_zero ()
549 {
550 }
551
552 void
553 RouteUI::set_sends_gain_to_unity ()
554 {
555 }
556
557 bool
558 RouteUI::show_sends_press(GdkEventButton* ev)
559 {
560         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
561                 return true;
562         }
563
564         if (!ignore_toggle && !is_track() && show_sends_button) {
565
566                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
567
568                         // do nothing on midi bind event
569                         return false;
570
571                 } else if (Keyboard::is_context_menu_event (ev)) {
572
573                         if (sends_menu == 0) {
574                                 build_sends_menu ();
575                         }
576
577                         sends_menu->popup (0, ev->time);
578
579                 } else {
580
581                         /* change button state */
582
583                         show_sends_button->set_active (!show_sends_button->get_active());
584
585                         /* start blinking */
586
587                         if (show_sends_button->get_active()) {
588                                 /* show sends to this bus */
589                                 MixerStrip::SwitchIO (_route);
590                                 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
591                         } else {
592                                 /* everybody back to normal */
593                                 send_blink_connection.disconnect ();
594                                 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
595                         }
596
597                 }
598         }
599
600         return true;
601 }
602
603 bool
604 RouteUI::show_sends_release (GdkEventButton* ev)
605 {
606         return true;
607 }
608
609 void
610 RouteUI::send_blink (bool onoff)
611 {
612         if (!show_sends_button) {
613                 return;
614         }
615                 
616         if (onoff) {
617                 show_sends_button->set_state (STATE_ACTIVE);
618         } else {
619                 show_sends_button->set_state (STATE_NORMAL);
620         }
621 }
622
623 void
624 RouteUI::solo_changed(void* src)
625 {
626         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
627 }
628
629
630 void
631 RouteUI::listen_changed(void* src)
632 {
633         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
634 }
635
636 void
637 RouteUI::update_solo_display ()
638 {
639         bool x;
640
641         if (Config->get_solo_control_is_listen_control()) {
642
643                 if (solo_button->get_active() != (x = _route->listening())) {
644                         ignore_toggle = true;
645                         solo_button->set_active(x);
646                         ignore_toggle = false;
647                 }
648
649         } else {
650
651                 if (solo_button->get_active() != (x = _route->soloed())){
652                         ignore_toggle = true;
653                         solo_button->set_active(x);
654                         ignore_toggle = false;
655                 } 
656                 
657                 if (_route->solo_isolated()) {
658                         solo_button->set_visual_state (2);
659                 } else if (_route->soloed()) {
660                         solo_button->set_visual_state (1);
661                 } else {
662                         solo_button->set_visual_state (0);
663                 }
664         }
665 }
666
667 void
668 RouteUI::solo_changed_so_update_mute ()
669 {
670         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
671 }
672
673 void
674 RouteUI::mute_changed(void* src)
675 {
676         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
677 }
678
679 void
680 RouteUI::update_mute_display ()
681 {
682         bool model = _route->muted();
683         bool view = mute_button->get_active();
684
685         /* first make sure the button's "depressed" visual
686            is correct.
687         */
688
689         if (model != view) {
690                 ignore_toggle = true;
691                 mute_button->set_active (model);
692                 ignore_toggle = false;
693         }
694
695         /* now attend to visual state */
696         
697         if (Config->get_show_solo_mutes()) {
698                 if (_route->muted()) {
699                         mute_button->set_visual_state (2);
700                 } else if (!_route->soloed() && _session.soloing()) {
701                         mute_button->set_visual_state (1);
702                 } else {
703                         mute_button->set_visual_state (0);
704                 }
705         } else {
706                 if (_route->muted()) {
707                         mute_button->set_visual_state (2);
708                 } else {
709                         mute_button->set_visual_state (0);
710                 }
711         }
712
713 }
714
715 void
716 RouteUI::route_rec_enable_changed ()
717 {
718         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
719 }
720
721 void
722 RouteUI::session_rec_enable_changed ()
723 {
724         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
725 }
726
727 void
728 RouteUI::update_rec_display ()
729 {
730         bool model = _route->record_enabled();
731         bool view = rec_enable_button->get_active();
732
733         /* first make sure the button's "depressed" visual
734            is correct.
735         */
736
737         if (model != view) {
738                 ignore_toggle = true;
739                 rec_enable_button->set_active (model);
740                 ignore_toggle = false;
741         }
742         else {
743                 return;
744         }
745         
746         /* now make sure its color state is correct */
747
748         if (model) {
749
750                 switch (_session.record_status ()) {
751                 case Session::Recording:
752                         rec_enable_button->set_visual_state (1);
753                         break;
754
755                 case Session::Disabled:
756                 case Session::Enabled:
757                         rec_enable_button->set_visual_state (2);
758                         break;
759
760                 }
761
762         } else {
763                 rec_enable_button->set_visual_state (0);
764         }
765 }
766
767 void
768 RouteUI::build_remote_control_menu ()
769 {
770         remote_control_menu = new Menu;
771         refresh_remote_control_menu ();
772 }
773
774 void
775 RouteUI::refresh_remote_control_menu ()
776 {
777         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
778
779         // only refresh the menu if it has been instantiated
780
781         if (remote_control_menu == 0) {
782                 return;
783         }
784
785         using namespace Menu_Helpers;
786
787         RadioMenuItem::Group rc_group;
788         CheckMenuItem* rc_active;
789         uint32_t limit = _session.ntracks() + _session.nbusses();
790         char buf[32];
791
792         MenuList& rc_items = remote_control_menu->items();
793         rc_items.clear ();
794
795         /* note that this menu list starts at zero, not 1, because zero
796            is a valid, if useless, ID.
797         */
798
799         limit += 4; /* leave some breathing room */
800         
801         rc_items.push_back (RadioMenuElem (rc_group, _("None")));
802         if (_route->remote_control_id() == 0) {
803                 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
804                 rc_active->set_active ();
805         }
806                 
807         for (uint32_t i = 1; i < limit; ++i) {
808                 snprintf (buf, sizeof (buf), "%u", i);
809                 rc_items.push_back (RadioMenuElem (rc_group, buf));
810                 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
811                 if (_route->remote_control_id() == i) {
812                         rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
813                         rc_active->set_active ();
814                 }
815                 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
816         }
817 }
818
819 void
820 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
821 {
822         /* this is called when the radio menu item is toggled, and so 
823            is actually invoked twice per menu selection. we only
824            care about the invocation for the item that was being
825            marked active.
826         */
827
828         if (item->get_active()) {
829                 _route->set_remote_control_id (id);
830         }
831 }
832
833 void
834 RouteUI::build_solo_menu (void)
835 {
836         using namespace Menu_Helpers;
837         
838         solo_menu = new Menu;
839         solo_menu->set_name ("ArdourContextMenu");
840         MenuList& items = solo_menu->items();
841         CheckMenuItem* check;
842
843         check = new CheckMenuItem(_("Solo Isolate"));
844         check->set_active (_route->solo_isolated());
845         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
846         _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
847         items.push_back (CheckMenuElem(*check));
848         check->show_all();
849
850         //items.push_back (SeparatorElem());
851         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
852         
853 }
854
855 void
856 RouteUI::build_mute_menu(void)
857 {
858         using namespace Menu_Helpers;
859         
860         mute_menu = new Menu;
861         mute_menu->set_name ("ArdourContextMenu");
862
863 #if FIX_ME_IN_3_0       
864         MenuList& items = mute_menu->items();
865         CheckMenuItem* check;
866
867         check = new CheckMenuItem(_("Pre Fader"));
868         init_mute_menu(PRE_FADER, check);
869         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
870         _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
871         items.push_back (CheckMenuElem(*check));
872         check->show_all();
873
874         check = new CheckMenuItem(_("Post Fader"));
875         init_mute_menu(POST_FADER, check);
876         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
877         _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
878         items.push_back (CheckMenuElem(*check));
879         check->show_all();
880         
881         check = new CheckMenuItem(_("Control Outs"));
882         init_mute_menu(CONTROL_OUTS, check);
883         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
884         _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
885         items.push_back (CheckMenuElem(*check));
886         check->show_all();
887
888         check = new CheckMenuItem(_("Main Outs"));
889         init_mute_menu(MAIN_OUTS, check);
890         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
891         _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
892         items.push_back (CheckMenuElem(*check));
893         check->show_all();
894 #endif
895         //items.push_back (SeparatorElem());
896         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
897 }
898
899 void
900 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
901 {
902         check->set_active (_route->mute_master()->muted_at (mp));
903 }
904
905 void
906 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
907 {
908         // _route->set_mute_config(type, check->get_active(), this);
909 }
910
911 void
912 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
913 {
914         _route->set_solo_isolated (check->get_active(), this);
915 }
916
917 void
918 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
919 {
920         RouteGroup* route_group;
921
922         if((route_group = route->route_group()) != 0){
923                 _session.begin_reversible_command (_("mix group solo  change"));
924                 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
925                 route_group->apply(&Route::set_solo, yn, this);
926                 cmd->mark();
927                 _session.add_command (cmd);
928                 _session.commit_reversible_command ();
929         } else {
930                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
931         }
932 }
933
934 void
935 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
936 {
937         _session.begin_reversible_command (name);
938         XMLNode &before = _route->get_state();
939         bind(mem_fun(*_route, func), yn, arg)();
940         XMLNode &after = _route->get_state();
941         _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
942         _session.commit_reversible_command ();
943 }
944
945 void
946 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
947 {
948         _session.begin_reversible_command (name);
949         XMLNode &before = track()->get_state();
950         bind (mem_fun (*track(), func), yn, arg)();
951         XMLNode &after = track()->get_state();
952         _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
953         _session.commit_reversible_command ();
954 }
955
956 void
957 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
958 {
959         RouteGroup* route_group;
960
961         if((route_group = route->route_group()) != 0){
962                 _session.begin_reversible_command (_("mix group mute change"));
963                 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
964                 route_group->apply(&Route::set_mute, yn, this);
965                 cmd->mark();
966                 _session.add_command(cmd);
967                 _session.commit_reversible_command ();
968         } else {
969                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
970         }
971 }
972
973 void
974 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
975 {
976         RouteGroup* route_group;
977
978         if((route_group = route->route_group()) != 0){
979                 _session.begin_reversible_command (_("mix group rec-enable change"));
980                 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
981                 route_group->apply (&Route::set_record_enable, yn, this);
982                 cmd->mark();
983                 _session.add_command(cmd);
984                 _session.commit_reversible_command ();
985         } else {
986                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
987         }
988 }
989
990
991 bool
992 RouteUI::choose_color()
993 {
994         bool picked;
995         Gdk::Color color;
996
997         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
998
999         if (picked) {
1000                 set_color (color);
1001         }
1002
1003         return picked;
1004 }
1005
1006 void
1007 RouteUI::set_color (const Gdk::Color & c)
1008 {
1009         char buf[64];
1010         
1011         _color = c;
1012         
1013         ensure_xml_node ();
1014         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1015         xml_node->add_property ("color", buf);
1016
1017         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1018 }
1019
1020
1021 void
1022 RouteUI::ensure_xml_node ()
1023 {
1024         if (xml_node == 0) {
1025                 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1026                         xml_node = new XMLNode ("GUI");
1027                         _route->add_extra_xml (*xml_node);
1028                 }
1029         }
1030 }
1031
1032 XMLNode*
1033 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1034 {
1035         ensure_xml_node ();
1036         
1037         XMLNodeList kids = xml_node->children();
1038         XMLNodeConstIterator iter;
1039
1040         const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1041
1042         for (iter = kids.begin(); iter != kids.end(); ++iter) {
1043                 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1044                         XMLProperty* type = (*iter)->property("automation-id");
1045                         if (type && type->value() == sym)
1046                                 return *iter;
1047                 }
1048         }
1049
1050         // Didn't find it, make a new one
1051         XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1052         child->add_property("automation-id", sym);
1053         xml_node->add_child_nocopy (*child);
1054
1055         return child;
1056 }
1057
1058 int
1059 RouteUI::set_color_from_route ()
1060 {
1061         XMLProperty *prop;
1062         
1063         RouteUI::ensure_xml_node ();
1064
1065         if ((prop = xml_node->property ("color")) != 0) {
1066                 int r, g, b;
1067                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1068                 _color.set_red(r);
1069                 _color.set_green(g);
1070                 _color.set_blue(b);
1071                 return 0;
1072         } 
1073         return 1;
1074 }
1075
1076 void
1077 RouteUI::remove_this_route ()
1078 {
1079         vector<string> choices;
1080         string prompt;
1081
1082         if (is_track()) {
1083                 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());
1084         } else {
1085                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1086         }
1087
1088         choices.push_back (_("No, do nothing."));
1089         choices.push_back (_("Yes, remove it."));
1090
1091         Choice prompter (prompt, choices);
1092
1093         if (prompter.run () == 1) {
1094                 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1095         }
1096 }
1097
1098 gint
1099 RouteUI::idle_remove_this_route (RouteUI *rui)
1100 {
1101         rui->_session.remove_route (rui->_route);
1102         return false;
1103 }
1104
1105 void
1106 RouteUI::route_rename ()
1107 {
1108         ArdourPrompter name_prompter (true);
1109         string result;
1110         name_prompter.set_prompt (_("New Name: "));
1111         name_prompter.set_initial_text (_route->name());
1112         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1113         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1114         name_prompter.show_all ();
1115
1116         switch (name_prompter.run ()) {
1117
1118         case Gtk::RESPONSE_ACCEPT:
1119         name_prompter.get_result (result);
1120         if (result.length()) {
1121                         _route->set_name (result);
1122                 }       
1123                 break;
1124         }
1125
1126         return;
1127   
1128 }
1129
1130 void
1131 RouteUI::name_changed ()
1132 {
1133         ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1134
1135         name_label.set_text (_route->name());
1136 }
1137
1138 void
1139 RouteUI::toggle_route_active ()
1140 {
1141         bool yn;
1142
1143         if (route_active_menu_item) {
1144                 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1145                         _route->set_active (!yn);
1146                 }
1147         }
1148 }
1149
1150 void
1151 RouteUI::route_active_changed ()
1152 {
1153         if (route_active_menu_item) {
1154                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1155         }
1156 }
1157
1158 void
1159 RouteUI::toggle_polarity ()
1160 {
1161         if (polarity_menu_item) {
1162
1163                 bool x;
1164
1165                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1166                 
1167                 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1168                         _route->set_phase_invert (x);
1169                         if (x) {
1170                                 name_label.set_text (X_("Ø ") + name_label.get_text());
1171                         } else {
1172                                 name_label.set_text (_route->name());
1173                         }
1174                 }
1175         }
1176 }
1177
1178 void
1179 RouteUI::polarity_changed ()
1180 {
1181         if (_route->phase_invert()) {
1182                 name_label.set_text (X_("Ø ") + name_label.get_text());
1183         } else {
1184                 name_label.set_text (_route->name());
1185         }
1186 }
1187
1188 void
1189 RouteUI::toggle_denormal_protection ()
1190 {
1191         if (denormal_menu_item) {
1192
1193                 bool x;
1194
1195                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1196                 
1197                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1198                         _route->set_denormal_protection (x);
1199                 }
1200         }
1201 }
1202
1203 void
1204 RouteUI::denormal_protection_changed ()
1205 {
1206         if (denormal_menu_item) {
1207                 denormal_menu_item->set_active (_route->denormal_protection());
1208         }
1209 }
1210
1211 void
1212 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1213 {
1214         bool yn = _route->solo_isolated ();
1215
1216         if (check->get_active() != yn) {
1217                 check->set_active (yn);
1218         }
1219 }
1220
1221 #ifdef FIX_THIS_FOR_3_0
1222 void
1223 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1224 {
1225         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1226         
1227         bool yn = _route->get_mute_config(PRE_FADER);
1228         if (check->get_active() != yn) {
1229                 check->set_active (yn);
1230         }
1231 }
1232
1233 void
1234 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1235 {
1236         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1237         
1238         bool yn = _route->get_mute_config(POST_FADER);
1239         if (check->get_active() != yn) {
1240                 check->set_active (yn);
1241         }
1242 }
1243
1244 void
1245 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1246 {
1247         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1248         
1249         bool yn = _route->get_mute_config(CONTROL_OUTS);
1250         if (check->get_active() != yn) {
1251                 check->set_active (yn);
1252         }
1253 }
1254
1255 void
1256 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1257 {
1258         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1259         
1260         bool yn = _route->get_mute_config(MAIN_OUTS);
1261         if (check->get_active() != yn) {
1262                 check->set_active (yn);
1263         }
1264 }
1265 #endif
1266
1267 void
1268 RouteUI::disconnect_input ()
1269 {
1270         _route->input()->disconnect (this);
1271 }
1272
1273 void
1274 RouteUI::disconnect_output ()
1275 {
1276         _route->output()->disconnect (this);
1277 }
1278
1279 bool
1280 RouteUI::is_track () const
1281 {
1282         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1283 }
1284
1285 boost::shared_ptr<Track>
1286 RouteUI::track() const
1287 {
1288         return boost::dynamic_pointer_cast<Track>(_route);
1289 }
1290
1291 bool
1292 RouteUI::is_audio_track () const
1293 {
1294         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1295 }
1296
1297 boost::shared_ptr<AudioTrack>
1298 RouteUI::audio_track() const
1299 {
1300         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1301 }
1302
1303 bool
1304 RouteUI::is_midi_track () const
1305 {
1306         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1307 }
1308
1309 boost::shared_ptr<MidiTrack>
1310 RouteUI::midi_track() const
1311 {
1312         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1313 }
1314
1315 boost::shared_ptr<Diskstream>
1316 RouteUI::get_diskstream () const
1317 {
1318         boost::shared_ptr<Track> t;
1319
1320         if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1321                 return t->diskstream();
1322         } else {
1323                 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1324         }
1325 }
1326
1327 string
1328 RouteUI::name() const
1329 {
1330         return _route->name();
1331 }
1332
1333 void
1334 RouteUI::map_frozen ()
1335 {
1336         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1337
1338         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1339
1340         if (at) {
1341                 switch (at->freeze_state()) {
1342                 case AudioTrack::Frozen:
1343                         rec_enable_button->set_sensitive (false);
1344                         break;
1345                 default:
1346                         rec_enable_button->set_sensitive (true);
1347                         break;
1348                 }
1349         }
1350 }
1351
1352 void
1353 RouteUI::adjust_latency ()
1354 {
1355         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1356 }
1357
1358 void
1359 RouteUI::save_as_template ()
1360 {
1361         sys::path path;
1362         Glib::ustring safe_name;
1363         string name;
1364         
1365         path = ARDOUR::user_route_template_directory ();
1366         
1367         if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1368                 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1369                 return;
1370         }
1371         
1372         Prompter p (true); // modal
1373         
1374         p.set_prompt (_("Template name:"));
1375         switch (p.run()) {
1376         case RESPONSE_ACCEPT:
1377                 break;
1378         default:
1379                 return;
1380         }
1381         
1382         p.hide ();
1383         p.get_result (name, true);
1384         
1385         safe_name = legalize_for_path (name);
1386         safe_name += template_suffix;
1387         
1388         path /= safe_name;
1389         
1390         _route->save_as_template (path.to_string(), name);
1391 }
1392
1393 void
1394 RouteUI::check_rec_enable_sensitivity ()
1395 {
1396         if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1397                 rec_enable_button->set_sensitive (false);
1398         } else {
1399                 rec_enable_button->set_sensitive (true);
1400         }
1401 }
1402
1403 void
1404 RouteUI::parameter_changed (string const & p)
1405 {
1406         ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1407         
1408         if (p == "disable-disarm-during-roll") {
1409                 check_rec_enable_sensitivity ();
1410         } else if (p == "solo-control-is-listen-control") {
1411                 set_button_names ();
1412         } else if (p == "listen-position") {
1413                 set_button_names ();
1414         }
1415 }
1416