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