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