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