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