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