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