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