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