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