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