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