Add a stock question image to the choices dialog, other general dialog love.. Forgot...
[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/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         for (uint32_t i = 0; i < limit; ++i) {
437                 snprintf (buf, sizeof (buf), "%u", i);
438                 rc_items.push_back (RadioMenuElem (rc_group, buf));
439                 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
440                 if (_route.remote_control_id() == i) {
441                         rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
442                         rc_active->set_active ();
443                 }
444                 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
445         }
446 }
447
448 void
449 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
450 {
451         /* this is called when the radio menu item is toggled, and so 
452            is actually invoked twice per menu selection. we only
453            care about the invocation for the item that was being
454            marked active.
455         */
456
457         if (item->get_active()) {
458                 _route.set_remote_control_id (id);
459         }
460 }
461
462 void
463 RouteUI::build_solo_menu (void)
464 {
465         using namespace Menu_Helpers;
466         
467         solo_menu = new Menu;
468         solo_menu->set_name ("ArdourContextMenu");
469         MenuList& items = solo_menu->items();
470         CheckMenuItem* check;
471
472         check = new CheckMenuItem(_("Solo-safe"));
473         check->set_active (_route.solo_safe());
474         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
475         _route.solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
476         items.push_back (CheckMenuElem(*check));
477         check->show_all();
478
479         items.push_back (SeparatorElem());
480         items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
481         
482 }
483
484 void
485 RouteUI::build_mute_menu(void)
486 {
487         using namespace Menu_Helpers;
488         
489         mute_menu = new Menu;
490         mute_menu->set_name ("ArdourContextMenu");
491         MenuList& items = mute_menu->items();
492         CheckMenuItem* check;
493         
494         check = new CheckMenuItem(_("Pre Fader"));
495         init_mute_menu(PRE_FADER, check);
496         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
497         _route.pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
498         items.push_back (CheckMenuElem(*check));
499         check->show_all();
500
501         check = new CheckMenuItem(_("Post Fader"));
502         init_mute_menu(POST_FADER, check);
503         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
504         _route.post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
505         items.push_back (CheckMenuElem(*check));
506         check->show_all();
507         
508         check = new CheckMenuItem(_("Control Outs"));
509         init_mute_menu(CONTROL_OUTS, check);
510         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
511         _route.control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
512         items.push_back (CheckMenuElem(*check));
513         check->show_all();
514
515         check = new CheckMenuItem(_("Main Outs"));
516         init_mute_menu(MAIN_OUTS, check);
517         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
518         _route.main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
519         items.push_back (CheckMenuElem(*check));
520         check->show_all();
521
522         items.push_back (SeparatorElem());
523         items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
524 }
525
526 void
527 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
528 {
529         if (_route.get_mute_config (type)) {
530                 check->set_active (true);
531         }
532 }
533
534 void
535 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
536 {
537         _route.set_mute_config(type, check->get_active(), this);
538 }
539
540 void
541 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
542 {
543         _route.set_solo_safe (check->get_active(), this);
544 }
545
546 void
547 RouteUI::set_mix_group_solo(Route& route, bool yn)
548 {
549         RouteGroup* mix_group;
550
551         if((mix_group = route.mix_group()) != 0){
552                 _session.begin_reversible_command (_("mix group solo  change"));
553                 _session.add_undo (_session.global_solo_memento (this));
554                 mix_group->apply(&Route::set_solo, yn, this);
555                 _session.add_redo_no_execute (_session.global_solo_memento(this));
556                 _session.commit_reversible_command ();
557         } else {
558                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route.soloed(), this);
559         }
560 }
561
562 void
563 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
564 {
565         _session.begin_reversible_command (name);
566         _session.add_undo (bind (mem_fun (_route, func), !yn, (void *) arg));
567         _session.add_redo (bind (mem_fun (_route, func), yn, (void *) arg));
568         _session.commit_reversible_command ();
569 }
570
571 void
572 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
573 {
574         _session.begin_reversible_command (name);
575         _session.add_undo (bind (mem_fun (*audio_track(), func), !yn, (void *) arg));
576         _session.add_redo (bind (mem_fun (*audio_track(), func), yn, (void *) arg));
577         _session.commit_reversible_command ();
578 }
579
580 void
581 RouteUI::set_mix_group_mute(Route& route, bool yn)
582 {
583         RouteGroup* mix_group;
584
585         if((mix_group = route.mix_group()) != 0){
586                 _session.begin_reversible_command (_("mix group mute change"));
587                 _session.add_undo (_session.global_mute_memento (this));
588                 mix_group->apply(&Route::set_mute, yn, this);
589                 _session.add_redo_no_execute (_session.global_mute_memento(this));
590                 _session.commit_reversible_command ();
591         } else {
592                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route.muted(), this);
593         }
594 }
595
596 void
597 RouteUI::set_mix_group_rec_enable(Route& route, bool yn)
598 {
599         RouteGroup* mix_group;
600
601         if((mix_group = route.mix_group()) != 0){
602                 _session.begin_reversible_command (_("mix group rec-enable change"));
603                 _session.add_undo (_session.global_record_enable_memento (this));
604                 mix_group->apply (&Route::set_record_enable, yn, this);
605                 _session.add_redo_no_execute (_session.global_record_enable_memento(this));
606                 _session.commit_reversible_command ();
607         } else {
608                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route.record_enabled(), this);
609         }
610 }
611
612
613 bool
614 RouteUI::choose_color()
615 {
616         bool picked;
617         Gdk::Color color;
618
619         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
620
621         if (picked) {
622                 set_color (color);
623         }
624
625         return picked;
626 }
627
628 void
629 RouteUI::set_color (const Gdk::Color & c)
630 {
631         char buf[64];
632         
633         _color = c;
634         
635         ensure_xml_node ();
636         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
637         xml_node->add_property ("color", buf);
638
639          _route.gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
640 }
641
642
643 void
644 RouteUI::ensure_xml_node ()
645 {
646         if (xml_node == 0) {
647                 if ((xml_node = _route.extra_xml ("GUI")) == 0) {
648                         xml_node = new XMLNode ("GUI");
649                         _route.add_extra_xml (*xml_node);
650                 }
651         }
652 }
653
654 XMLNode*
655 RouteUI::get_child_xml_node (const string & childname)
656 {
657         XMLNode* child;
658
659         ensure_xml_node ();
660         
661         
662         if ((child = find_named_node (*xml_node, childname)) == 0) {
663                 child = new XMLNode (childname);
664                 xml_node->add_child_nocopy (*child);
665         }
666
667         return child;
668 }
669
670 int
671 RouteUI::set_color_from_route ()
672 {
673         XMLProperty *prop;
674         
675         RouteUI::ensure_xml_node ();
676
677         if ((prop = xml_node->property ("color")) != 0) {
678                 int r, g, b;
679                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
680                 _color.set_red(r);
681                 _color.set_green(g);
682                 _color.set_blue(b);
683                 return 0;
684         } 
685         return 1;
686 }
687
688 void
689 RouteUI::remove_this_route ()
690 {
691         vector<string> choices;
692         string prompt;
693
694         if (is_audio_track()) {
695                 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());
696         } else {
697                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route.name());
698         }
699
700         choices.push_back (_("No, do nothing."));
701         choices.push_back (_("Yes, remove it."));
702
703         Choice prompter (prompt, choices);
704
705         if (prompter.run () == 1) {
706                 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
707         }
708 }
709
710 gint
711 RouteUI::idle_remove_this_route (RouteUI *rui)
712 {
713         rui->_session.remove_route (rui->_route);
714         return FALSE;
715 }
716
717 void
718 RouteUI::route_removed ()
719 {
720         ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::route_removed));
721         
722         delete this;
723 }
724
725 void
726 RouteUI::route_rename ()
727 {
728         ArdourPrompter name_prompter (true);
729         string result;
730         name_prompter.set_prompt (_("new name: "));
731         name_prompter.set_initial_text (_route.name());
732         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
733         name_prompter.show_all ();
734
735         switch (name_prompter.run ()) {
736
737         case Gtk::RESPONSE_ACCEPT:
738         name_prompter.get_result (result);
739         if (result.length()) {
740                         _route.set_name (result, this);
741                 }       
742                 break;
743         }
744
745         return;
746   
747 }
748
749 void
750 RouteUI::name_changed (void *src)
751 {
752         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
753         
754         name_label.set_text (_route.name());
755 }
756
757 void
758 RouteUI::toggle_route_active ()
759 {
760         bool yn;
761
762         if (route_active_menu_item) {
763                 if (route_active_menu_item->get_active() != (yn = _route.active())) {
764                         _route.set_active (!yn);
765                 }
766         }
767 }
768
769 void
770 RouteUI::route_active_changed ()
771 {
772         if (route_active_menu_item) {
773                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route.active()));
774         }
775 }
776
777 void
778 RouteUI::toggle_polarity ()
779 {
780         if (polarity_menu_item) {
781
782                 bool x;
783
784                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
785                 
786                 if ((x = polarity_menu_item->get_active()) != _route.phase_invert()) {
787                         _route.set_phase_invert (x, this);
788                 }
789         }
790 }
791
792 void
793 RouteUI::polarity_changed ()
794 {
795         /* no signal for this yet */
796 }
797
798 void
799 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
800 {
801         bool yn = _route.solo_safe ();
802
803         if (check->get_active() != yn) {
804                 check->set_active (yn);
805         }
806 }
807 void
808 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
809 {
810         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
811         
812         bool yn = _route.get_mute_config(PRE_FADER);
813         if (check->get_active() != yn) {
814                 check->set_active (yn);
815         }
816 }
817
818 void
819 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
820 {
821         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
822         
823         bool yn = _route.get_mute_config(POST_FADER);
824         if (check->get_active() != yn) {
825                 check->set_active (yn);
826         }
827 }
828
829 void
830 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
831 {
832         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
833         
834         bool yn = _route.get_mute_config(CONTROL_OUTS);
835         if (check->get_active() != yn) {
836                 check->set_active (yn);
837         }
838 }
839
840 void
841 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
842 {
843         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
844         
845         bool yn = _route.get_mute_config(MAIN_OUTS);
846         if (check->get_active() != yn) {
847                 check->set_active (yn);
848         }
849 }
850
851 void
852 RouteUI::disconnect_input ()
853 {
854         _route.disconnect_inputs (this);
855 }
856
857 void
858 RouteUI::disconnect_output ()
859 {
860         _route.disconnect_outputs (this);
861 }
862
863 bool
864 RouteUI::is_audio_track () const
865 {
866         return dynamic_cast<AudioTrack*>(&_route) != 0;
867 }
868
869 DiskStream*
870 RouteUI::get_diskstream () const
871 {
872         AudioTrack *at;
873
874         if ((at = dynamic_cast<AudioTrack*>(&_route)) != 0) {
875                 return &at->disk_stream();
876         } else {
877                 return 0;
878         }
879 }
880
881 AudioTrack*
882 RouteUI::audio_track() const
883 {
884         return dynamic_cast<AudioTrack*>(&_route);
885 }
886 string
887 RouteUI::name() const
888 {
889         return _route.name();
890 }
891
892 void
893 RouteUI::map_frozen ()
894 {
895         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
896
897         AudioTrack* at = dynamic_cast<AudioTrack*>(&_route);
898
899         if (at) {
900                 switch (at->freeze_state()) {
901                 case AudioTrack::Frozen:
902                         rec_enable_button->set_sensitive (false);
903                         break;
904                 default:
905                         rec_enable_button->set_sensitive (true);
906                         break;
907                 }
908         }
909 }
910