6ecb4d6255de461d2cd44ee9c2e87ed03815f539
[ardour.git] / gtk2_ardour / route_ui.cc
1 /*
2     Copyright (C) 2002 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     $Id$
19 */
20
21 #include <gtkmm2ext/gtk_ui.h>
22 #include <gtkmm2ext/stop_signal.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/bindable_button.h>
25 #include <gtkmm2ext/doi.h>
26
27 #include <ardour/route_group.h>
28
29 #include "route_ui.h"
30 #include "keyboard.h"
31 #include "utils.h"
32 #include "prompter.h"
33 #include "gui_thread.h"
34
35 #include <ardour/route.h>
36 #include <ardour/audio_track.h>
37 #include <ardour/audio_diskstream.h>
38
39 #include "i18n.h"
40 using namespace sigc;
41 using namespace Gtk;
42 using namespace Gtkmm2ext;
43 using namespace ARDOUR;
44 using namespace PBD;
45
46
47 RouteUI::RouteUI (ARDOUR::Route& rt, ARDOUR::Session& sess, const char* m_name,
48                   const char* s_name, const char* r_name)
49     : AxisView(sess),
50           _route(rt),
51           mute_button(0),
52           solo_button(0),
53           rec_enable_button(0)
54 {
55         xml_node = 0;
56         mute_menu = 0;
57         solo_menu = 0;
58         remote_control_menu = 0;
59         ignore_toggle = false;
60         wait_for_release = false;
61         route_active_menu_item = 0;
62
63         if (set_color_from_route()) {
64                 set_color (unique_random_color());
65         }
66
67         _route.GoingAway.connect (mem_fun (*this, &RouteUI::route_removed));
68         _route.active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
69
70         mute_button = manage (new BindableToggleButton (& _route.midi_mute_control(), m_name ));
71         mute_button->set_bind_button_state (2, GDK_CONTROL_MASK);
72         solo_button = manage (new BindableToggleButton (& _route.midi_solo_control(), s_name ));
73         solo_button->set_bind_button_state (2, GDK_CONTROL_MASK);
74
75         if (is_audio_track()) {
76                 AudioTrack* at = dynamic_cast<AudioTrack*>(&_route);
77
78                 get_diskstream()->record_enable_changed.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed));
79
80                 _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
81
82                 rec_enable_button = manage (new BindableToggleButton (& at->midi_rec_enable_control(), r_name ));
83                 rec_enable_button->set_bind_button_state (2, GDK_CONTROL_MASK);
84
85         } else {
86                 rec_enable_button = manage (new BindableToggleButton (0, r_name ));
87         }
88         
89         mute_button->unset_flags (Gtk::CAN_FOCUS);
90         solo_button->unset_flags (Gtk::CAN_FOCUS);
91         rec_enable_button->unset_flags (Gtk::CAN_FOCUS);
92
93         /* map the current state */
94
95         update_rec_display ();
96         map_frozen ();
97 }
98
99 RouteUI::~RouteUI()
100 {
101         delete mute_menu;
102 }
103
104 gint
105 RouteUI::mute_press(GdkEventButton* ev)
106 {
107         if (!ignore_toggle) {
108
109                 if (Keyboard::is_context_menu_event (ev)) {
110
111                         if (mute_menu == 0){
112                                 build_mute_menu();
113                         }
114
115                         mute_menu->popup(0,0);
116
117                 } else {
118
119                         if (ev->button == 2) {
120                                 // ctrl-button2 click is the midi binding click
121                                 // button2-click is "momentary"
122                                 
123                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control))) {
124                                         wait_for_release = true;
125                                 }
126                         }
127
128                         if (ev->button == 1 || ev->button == 2) {
129
130                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
131
132                                         /* ctrl-shift-click applies change to all routes */
133
134                                         _session.begin_reversible_command (_("mute change"));
135                                         Session::GlobalMuteStateCommand cmd(this);
136                                         _session.set_all_mute (!_route.muted());
137                                         cmd.mark();
138                                         _session.add_command(cmd);
139                                         _session.commit_reversible_command ();
140
141                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
142
143                                         /* ctrl-click applies change to the mix group.
144                                            ctrl-button2 is MIDI learn.
145                                         */
146
147                                         if (ev->button == 1) {
148                                                 set_mix_group_mute (_route, !_route.muted());
149                                         }
150                                         
151                                 } else {
152
153                                         /* plain click applies change to this route */
154
155                                         reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route.muted(), this);
156                                 }
157                         }
158                 }
159
160         }
161
162         return true;
163 }
164
165 gint
166 RouteUI::mute_release(GdkEventButton* ev)
167 {
168         if (!ignore_toggle) {
169                 if (wait_for_release){
170                         wait_for_release = false;
171                         // undo the last op
172                         // because the press was the last undoable thing we did
173                         _session.undo (1U);
174                 }
175         }
176         return true;
177 }
178
179 gint
180 RouteUI::solo_press(GdkEventButton* ev)
181 {
182         if (!ignore_toggle) {
183
184                 if (Keyboard::is_context_menu_event (ev)) {
185                         
186                         if (solo_menu == 0) {
187                                 build_solo_menu ();
188                         }
189
190                         solo_menu->popup (1, 0);
191
192                 } else {
193
194                         if (ev->button == 2) {
195
196                                 // ctrl-button2 click is the midi binding click
197                                 // button2-click is "momentary"
198                                 
199                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control))) {
200                                         wait_for_release = true;
201                                 }
202                         }
203
204                         if (ev->button == 1 || ev->button == 2) {
205
206                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
207
208                                         /* ctrl-shift-click applies change to all routes */
209
210                                         _session.begin_reversible_command (_("solo change"));
211                                         Session::GlobalSoloStateCommand cmd(this);
212                                         _session.set_all_solo (!_route.soloed());
213                                         cmd.mark();
214                                         _session.add_command (cmd);
215                                         _session.commit_reversible_command ();
216                                         
217                                 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
218
219                                         // ctrl-alt-click: exclusively solo this track, not a toggle */
220
221                                         _session.begin_reversible_command (_("solo change"));
222                                         Session::GlobalSoloStateCommand cmd(this);
223                                         _session.set_all_solo (false);
224                                         _route.set_solo (true, this);
225                                         cmd.mark();
226                                         _session.add_command(cmd);
227                                         _session.commit_reversible_command ();
228
229                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) {
230
231                                         // shift-click: set this route to solo safe
232
233                                         _route.set_solo_safe (!_route.solo_safe(), this);
234                                         wait_for_release = false;
235
236                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
237
238                                         /* ctrl-click: solo mix group.
239                                            ctrl-button2 is MIDI learn.
240                                         */
241
242                                         if (ev->button == 1) {
243                                                 set_mix_group_solo (_route, !_route.soloed());
244                                         }
245
246                                 } else {
247
248                                         /* click: solo this route */
249
250                                         reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route.soloed(), this);
251                                 }
252                         }
253                 }
254         }
255
256         return true;
257 }
258
259 gint
260 RouteUI::solo_release(GdkEventButton* ev)
261 {
262         if (!ignore_toggle) {
263                 if (wait_for_release) {
264                         wait_for_release = false;
265                         // undo the last op
266                         // because the press was the last undoable thing we did
267
268                         _session.undo (1U);
269                 }
270         }
271
272         return true;
273 }
274
275 gint
276 RouteUI::rec_enable_press(GdkEventButton* ev)
277 {
278         if (!ignore_toggle && is_audio_track()) {
279
280                 if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
281                         // do nothing on midi bind event
282                 }
283                 else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
284
285                         _session.begin_reversible_command (_("rec-enable change"));
286                         Session::GlobalRecordEnableStateCommand cmd(this);
287
288                         if (rec_enable_button->get_active()) {
289                                 _session.record_disenable_all ();
290                         } else {
291                                 _session.record_enable_all ();
292                         }
293
294                         cmd.mark();
295                         _session.add_command(cmd);
296                         _session.commit_reversible_command ();
297
298                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
299
300                         set_mix_group_rec_enable (_route, !_route.record_enabled());
301
302                 } else {
303
304                         reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
305
306                         ignore_toggle = true;
307                         rec_enable_button->set_active(audio_track()->record_enabled());
308                         ignore_toggle = false;
309                 }
310                 
311                 stop_signal (*rec_enable_button, "button-press-event");
312         }
313
314         return TRUE;
315 }
316
317 void
318 RouteUI::solo_changed(void* src)
319 {
320         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
321 }
322
323 void
324 RouteUI::update_solo_display ()
325 {
326         bool x;
327
328         if (solo_button->get_active() != (x = _route.soloed())){
329                 ignore_toggle = true;
330                 solo_button->set_active(x);
331                 ignore_toggle = false;
332         }
333         
334         /* show solo safe */
335
336         if (_route.solo_safe()){
337                 solo_button->set_name(safe_solo_button_name());
338         } else {
339                 solo_button->set_name(solo_button_name());
340         }
341 }
342
343 void
344 RouteUI::mute_changed(void* src)
345 {
346         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
347 }
348
349 void
350 RouteUI::update_mute_display ()
351 {
352         bool x;
353
354         if (mute_button->get_active() != (x = _route.muted())){
355                 ignore_toggle = true;
356                 mute_button->set_active(x);
357                 ignore_toggle = false;
358         }
359 }
360
361 void
362 RouteUI::route_rec_enable_changed (void *src)
363 {
364         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
365 }
366
367 void
368 RouteUI::session_rec_enable_changed ()
369 {
370         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
371 }
372
373 void
374 RouteUI::update_rec_display ()
375 {
376         bool model = _route.record_enabled();
377         bool view = rec_enable_button->get_active();
378
379         /* first make sure the button's "depressed" visual
380            is correct.
381         */
382         
383         if (model != view) {
384                 ignore_toggle = true;
385                 rec_enable_button->set_active (model);
386                 ignore_toggle = false;
387         }
388
389         /* now make sure its color state is correct */
390
391         if (model) {
392
393                 switch (_session.record_status ()) {
394                 case Session::Disabled:
395                 case Session::Enabled:
396                         if (rec_enable_button->get_state() != Gtk::STATE_ACTIVE) {
397                                 rec_enable_button->set_state (Gtk::STATE_ACTIVE);
398                         }
399                         break;
400
401                 case Session::Recording:
402                         if (rec_enable_button->get_state() != Gtk::STATE_SELECTED) {
403                                 rec_enable_button->set_state (Gtk::STATE_SELECTED);
404                         }
405                         break;
406                 }
407
408         } else {
409                 if (rec_enable_button->get_state() != Gtk::STATE_NORMAL) {
410                         rec_enable_button->set_state (Gtk::STATE_NORMAL);
411                 }
412         }
413 }
414
415 void
416 RouteUI::build_remote_control_menu ()
417 {
418         remote_control_menu = manage (new Menu);
419         refresh_remote_control_menu ();
420 }
421
422 void
423 RouteUI::refresh_remote_control_menu ()
424 {
425         using namespace Menu_Helpers;
426
427         RadioMenuItem::Group rc_group;
428         CheckMenuItem* rc_active;
429         uint32_t limit = _session.ntracks();
430         char buf[32];
431
432         MenuList& rc_items = remote_control_menu->items();
433         rc_items.clear ();
434
435         /* note that this menu list starts at zero, not 1, because zero
436            is a valid, if useless, ID.
437         */
438
439         limit += 4; /* leave some breathing room */
440         
441         rc_items.push_back (RadioMenuElem (rc_group, _("None")));
442         if (_route.remote_control_id() == 0) {
443                 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
444                 rc_active->set_active ();
445         }
446                 
447         for (uint32_t i = 1; i < limit; ++i) {
448                 snprintf (buf, sizeof (buf), "%u", i);
449                 rc_items.push_back (RadioMenuElem (rc_group, buf));
450                 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
451                 if (_route.remote_control_id() == i) {
452                         rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
453                         rc_active->set_active ();
454                 }
455                 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
456         }
457 }
458
459 void
460 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
461 {
462         /* this is called when the radio menu item is toggled, and so 
463            is actually invoked twice per menu selection. we only
464            care about the invocation for the item that was being
465            marked active.
466         */
467
468         if (item->get_active()) {
469                 _route.set_remote_control_id (id);
470         }
471 }
472
473 void
474 RouteUI::build_solo_menu (void)
475 {
476         using namespace Menu_Helpers;
477         
478         solo_menu = new Menu;
479         solo_menu->set_name ("ArdourContextMenu");
480         MenuList& items = solo_menu->items();
481         CheckMenuItem* check;
482
483         check = new CheckMenuItem(_("Solo-safe"));
484         check->set_active (_route.solo_safe());
485         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
486         _route.solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
487         items.push_back (CheckMenuElem(*check));
488         check->show_all();
489
490         items.push_back (SeparatorElem());
491         items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
492         
493 }
494
495 void
496 RouteUI::build_mute_menu(void)
497 {
498         using namespace Menu_Helpers;
499         
500         mute_menu = new Menu;
501         mute_menu->set_name ("ArdourContextMenu");
502         MenuList& items = mute_menu->items();
503         CheckMenuItem* check;
504         
505         check = new CheckMenuItem(_("Pre Fader"));
506         init_mute_menu(PRE_FADER, check);
507         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
508         _route.pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
509         items.push_back (CheckMenuElem(*check));
510         check->show_all();
511
512         check = new CheckMenuItem(_("Post Fader"));
513         init_mute_menu(POST_FADER, check);
514         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
515         _route.post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
516         items.push_back (CheckMenuElem(*check));
517         check->show_all();
518         
519         check = new CheckMenuItem(_("Control Outs"));
520         init_mute_menu(CONTROL_OUTS, check);
521         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
522         _route.control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
523         items.push_back (CheckMenuElem(*check));
524         check->show_all();
525
526         check = new CheckMenuItem(_("Main Outs"));
527         init_mute_menu(MAIN_OUTS, check);
528         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
529         _route.main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
530         items.push_back (CheckMenuElem(*check));
531         check->show_all();
532
533         items.push_back (SeparatorElem());
534         items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
535 }
536
537 void
538 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
539 {
540         if (_route.get_mute_config (type)) {
541                 check->set_active (true);
542         }
543 }
544
545 void
546 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
547 {
548         _route.set_mute_config(type, check->get_active(), this);
549 }
550
551 void
552 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
553 {
554         _route.set_solo_safe (check->get_active(), this);
555 }
556
557 void
558 RouteUI::set_mix_group_solo(Route& route, bool yn)
559 {
560         RouteGroup* mix_group;
561
562         if((mix_group = route.mix_group()) != 0){
563                 _session.begin_reversible_command (_("mix group solo  change"));
564                 Session::GlobalSoloStateCommand cmd(this);
565                 mix_group->apply(&Route::set_solo, yn, this);
566                 cmd.mark();
567                 _session.add_command (cmd);
568                 _session.commit_reversible_command ();
569         } else {
570                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route.soloed(), this);
571         }
572 }
573
574 void
575 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
576 {
577         _session.begin_reversible_command (name);
578         XMLNode &before = _route.get_state();
579         bind(mem_fun(_route, func), yn, arg)();
580         XMLNode &after = _route.get_state();
581         _session.add_command (MementoCommand<Route>(_route, before, after));
582         _session.commit_reversible_command ();
583 }
584
585 void
586 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
587 {
588         _session.begin_reversible_command (name);
589         XMLNode &before = audio_track()->get_state();
590         bind (mem_fun (*audio_track(), func), yn, arg)();
591         XMLNode &after = audio_track()->get_state();
592         _session.add_command (MementoCommand<AudioTrack>(*audio_track(), before, after));
593         _session.commit_reversible_command ();
594 }
595
596 void
597 RouteUI::set_mix_group_mute(Route& route, bool yn)
598 {
599         RouteGroup* mix_group;
600
601         if((mix_group = route.mix_group()) != 0){
602                 _session.begin_reversible_command (_("mix group mute change"));
603                 Session::GlobalMuteStateCommand cmd(this);
604                 mix_group->apply(&Route::set_mute, yn, this);
605                 cmd.mark();
606                 _session.add_command(cmd);
607                 _session.commit_reversible_command ();
608         } else {
609                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route.muted(), this);
610         }
611 }
612
613 void
614 RouteUI::set_mix_group_rec_enable(Route& route, bool yn)
615 {
616         RouteGroup* mix_group;
617
618         if((mix_group = route.mix_group()) != 0){
619                 _session.begin_reversible_command (_("mix group rec-enable change"));
620                 Session::GlobalRecordEnableStateCommand cmd(this);
621                 mix_group->apply (&Route::set_record_enable, yn, this);
622                 cmd.mark();
623                 _session.add_command(cmd);
624                 _session.commit_reversible_command ();
625         } else {
626                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route.record_enabled(), this);
627         }
628 }
629
630
631 bool
632 RouteUI::choose_color()
633 {
634         bool picked;
635         Gdk::Color color;
636
637         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
638
639         if (picked) {
640                 set_color (color);
641         }
642
643         return picked;
644 }
645
646 void
647 RouteUI::set_color (const Gdk::Color & c)
648 {
649         char buf[64];
650         
651         _color = c;
652         
653         ensure_xml_node ();
654         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
655         xml_node->add_property ("color", buf);
656
657          _route.gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
658 }
659
660
661 void
662 RouteUI::ensure_xml_node ()
663 {
664         if (xml_node == 0) {
665                 if ((xml_node = _route.extra_xml ("GUI")) == 0) {
666                         xml_node = new XMLNode ("GUI");
667                         _route.add_extra_xml (*xml_node);
668                 }
669         }
670 }
671
672 XMLNode*
673 RouteUI::get_child_xml_node (const string & childname)
674 {
675         XMLNode* child;
676
677         ensure_xml_node ();
678         
679         
680         if ((child = find_named_node (*xml_node, childname)) == 0) {
681                 child = new XMLNode (childname);
682                 xml_node->add_child_nocopy (*child);
683         }
684
685         return child;
686 }
687
688 int
689 RouteUI::set_color_from_route ()
690 {
691         XMLProperty *prop;
692         
693         RouteUI::ensure_xml_node ();
694
695         if ((prop = xml_node->property ("color")) != 0) {
696                 int r, g, b;
697                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
698                 _color.set_red(r);
699                 _color.set_green(g);
700                 _color.set_blue(b);
701                 return 0;
702         } 
703         return 1;
704 }
705
706 void
707 RouteUI::remove_this_route ()
708 {
709         vector<string> choices;
710         string prompt;
711
712         if (is_audio_track()) {
713                 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());
714         } else {
715                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route.name());
716         }
717
718         choices.push_back (_("No, do nothing."));
719         choices.push_back (_("Yes, remove it."));
720
721         Choice prompter (prompt, choices);
722
723         if (prompter.run () == 1) {
724                 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
725         }
726 }
727
728 gint
729 RouteUI::idle_remove_this_route (RouteUI *rui)
730 {
731         rui->_session.remove_route (rui->_route);
732         return FALSE;
733 }
734
735 void
736 RouteUI::route_removed ()
737 {
738         ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::route_removed));
739         
740         delete this;
741 }
742
743 void
744 RouteUI::route_rename ()
745 {
746         ArdourPrompter name_prompter (true);
747         string result;
748         name_prompter.set_prompt (_("New Name: "));
749         name_prompter.set_initial_text (_route.name());
750         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
751         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
752         name_prompter.show_all ();
753
754         switch (name_prompter.run ()) {
755
756         case Gtk::RESPONSE_ACCEPT:
757         name_prompter.get_result (result);
758         if (result.length()) {
759                         _route.set_name (result, this);
760                 }       
761                 break;
762         }
763
764         return;
765   
766 }
767
768 void
769 RouteUI::name_changed (void *src)
770 {
771         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
772
773         name_label.set_text (_route.name());
774 }
775
776 void
777 RouteUI::toggle_route_active ()
778 {
779         bool yn;
780
781         if (route_active_menu_item) {
782                 if (route_active_menu_item->get_active() != (yn = _route.active())) {
783                         _route.set_active (!yn);
784                 }
785         }
786 }
787
788 void
789 RouteUI::route_active_changed ()
790 {
791         if (route_active_menu_item) {
792                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route.active()));
793         }
794 }
795
796 void
797 RouteUI::toggle_polarity ()
798 {
799         if (polarity_menu_item) {
800
801                 bool x;
802
803                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
804                 
805                 if ((x = polarity_menu_item->get_active()) != _route.phase_invert()) {
806                         _route.set_phase_invert (x, this);
807                         if (x) {
808                                 name_label.set_text (X_("Ø ") + name_label.get_text());
809                         } else {
810                                 name_label.set_text (_route.name());
811                         }
812                 }
813         }
814 }
815
816 void
817 RouteUI::polarity_changed ()
818 {
819         /* no signal for this yet */
820 }
821
822 void
823 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
824 {
825         bool yn = _route.solo_safe ();
826
827         if (check->get_active() != yn) {
828                 check->set_active (yn);
829         }
830 }
831 void
832 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
833 {
834         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
835         
836         bool yn = _route.get_mute_config(PRE_FADER);
837         if (check->get_active() != yn) {
838                 check->set_active (yn);
839         }
840 }
841
842 void
843 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
844 {
845         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
846         
847         bool yn = _route.get_mute_config(POST_FADER);
848         if (check->get_active() != yn) {
849                 check->set_active (yn);
850         }
851 }
852
853 void
854 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
855 {
856         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
857         
858         bool yn = _route.get_mute_config(CONTROL_OUTS);
859         if (check->get_active() != yn) {
860                 check->set_active (yn);
861         }
862 }
863
864 void
865 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
866 {
867         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
868         
869         bool yn = _route.get_mute_config(MAIN_OUTS);
870         if (check->get_active() != yn) {
871                 check->set_active (yn);
872         }
873 }
874
875 void
876 RouteUI::disconnect_input ()
877 {
878         _route.disconnect_inputs (this);
879 }
880
881 void
882 RouteUI::disconnect_output ()
883 {
884         _route.disconnect_outputs (this);
885 }
886
887 bool
888 RouteUI::is_audio_track () const
889 {
890         return dynamic_cast<AudioTrack*>(&_route) != 0;
891 }
892
893 AudioDiskstream*
894 RouteUI::get_diskstream () const
895 {
896         AudioTrack *at;
897
898         if ((at = dynamic_cast<AudioTrack*>(&_route)) != 0) {
899                 return &at->disk_stream();
900         } else {
901                 return 0;
902         }
903 }
904
905 AudioTrack*
906 RouteUI::audio_track() const
907 {
908         return dynamic_cast<AudioTrack*>(&_route);
909 }
910 string
911 RouteUI::name() const
912 {
913         return _route.name();
914 }
915
916 void
917 RouteUI::map_frozen ()
918 {
919         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
920
921         AudioTrack* at = dynamic_cast<AudioTrack*>(&_route);
922
923         if (at) {
924                 switch (at->freeze_state()) {
925                 case AudioTrack::Frozen:
926                         rec_enable_button->set_sensitive (false);
927                         break;
928                 default:
929                         rec_enable_button->set_sensitive (true);
930                         break;
931                 }
932         }
933 }