1780204321a3bfd750d01a3bcb86bc60f410cbda
[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         ignore_toggle = false;
58         wait_for_release = false;
59         route_active_menu_item = 0;
60
61         if (set_color_from_route()) {
62                 set_color (unique_random_color());
63         }
64
65         _route.GoingAway.connect (mem_fun (*this, &RouteUI::route_removed));
66         _route.active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
67
68         mute_button = manage (new BindableToggleButton (& _route.midi_mute_control(), m_name ));
69         mute_button->set_bind_button_state (2, GDK_CONTROL_MASK);
70         solo_button = manage (new BindableToggleButton (& _route.midi_solo_control(), s_name ));
71         solo_button->set_bind_button_state (2, GDK_CONTROL_MASK);
72
73         if (is_audio_track()) {
74                 AudioTrack* at = dynamic_cast<AudioTrack*>(&_route);
75
76                 get_diskstream()->record_enable_changed.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed));
77
78                 _session.RecordEnabled.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
79                 _session.RecordDisabled.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 stop_signal (*solo_button, "button-press-event");
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                         stop_signal (*solo_button, "button-release-event");
267                 }
268         }
269         return TRUE;
270 }
271
272 gint
273 RouteUI::rec_enable_press(GdkEventButton* ev)
274 {
275         if (!ignore_toggle && is_audio_track()) {
276
277                 if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
278                         // do nothing on midi bind event
279                 }
280                 else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
281
282                         _session.begin_reversible_command (_("rec-enable change"));
283                         _session.add_undo (_session.global_record_enable_memento(this));
284
285                         if (rec_enable_button->get_active()) {
286                                 _session.record_disenable_all ();
287                         } else {
288                                 _session.record_enable_all ();
289                         }
290
291                         _session.add_redo_no_execute (_session.global_record_enable_memento(this));
292                         _session.commit_reversible_command ();
293
294                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
295
296                         set_mix_group_rec_enable (_route, !_route.record_enabled());
297
298                 } else {
299
300                         reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
301
302                         ignore_toggle = true;
303                         rec_enable_button->set_active(audio_track()->record_enabled());
304                         ignore_toggle = false;
305                 }
306                 
307                 stop_signal (*rec_enable_button, "button-press-event");
308         }
309
310         return TRUE;
311 }
312
313 void
314 RouteUI::solo_changed(void* src)
315 {
316         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
317 }
318
319 void
320 RouteUI::update_solo_display ()
321 {
322         bool x;
323
324         if (solo_button->get_active() != (x = _route.soloed())){
325                 ignore_toggle = true;
326                 solo_button->set_active(x);
327                 ignore_toggle = false;
328         }
329         
330         /* show solo safe */
331
332         if (_route.solo_safe()){
333                 solo_button->set_name(safe_solo_button_name());
334         } else {
335                 solo_button->set_name(solo_button_name());
336         }
337 }
338
339 void
340 RouteUI::mute_changed(void* src)
341 {
342         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
343 }
344
345 void
346 RouteUI::update_mute_display ()
347 {
348         bool x;
349
350         if (mute_button->get_active() != (x = _route.muted())){
351                 ignore_toggle = true;
352                 mute_button->set_active(x);
353                 ignore_toggle = false;
354         }
355 }
356
357 void
358 RouteUI::route_rec_enable_changed (void *src)
359 {
360         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
361 }
362
363 void
364 RouteUI::session_rec_enable_changed ()
365 {
366         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
367 }
368
369 void
370 RouteUI::update_rec_display ()
371 {
372         bool model = _route.record_enabled();
373         bool view = rec_enable_button->get_active();
374
375         /* first make sure the button's "depressed" visual
376            is correct.
377         */
378         
379         if (model != view) {
380                 ignore_toggle = true;
381                 rec_enable_button->set_active (model);
382                 ignore_toggle = false;
383         }
384
385         /* now make sure its color state is correct */
386
387         if (model) {
388
389                 switch (_session.record_status ()) {
390                 case Session::Disabled:
391                 case Session::Enabled:
392                         if (rec_enable_button->get_state() != Gtk::STATE_ACTIVE) {
393                                 rec_enable_button->set_state (Gtk::STATE_ACTIVE);
394                         }
395                         break;
396
397                 case Session::Recording:
398                         if (rec_enable_button->get_state() != Gtk::STATE_SELECTED) {
399                                 rec_enable_button->set_state (Gtk::STATE_SELECTED);
400                         }
401                         break;
402                 }
403
404         } else {
405                 if (rec_enable_button->get_state() != Gtk::STATE_NORMAL) {
406                         rec_enable_button->set_state (Gtk::STATE_NORMAL);
407                 }
408         }
409 }
410
411 void
412 RouteUI::build_solo_menu (void)
413 {
414         using namespace Menu_Helpers;
415         
416         solo_menu = new Menu;
417         solo_menu->set_name ("ArdourContextMenu");
418         MenuList& items = solo_menu->items();
419         CheckMenuItem* check;
420
421         check = new CheckMenuItem(_("Solo-safe"));
422         check->set_active (_route.solo_safe());
423         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
424         _route.solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
425         items.push_back (CheckMenuElem(*check));
426         check->show_all();
427
428         items.push_back (SeparatorElem());
429         items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
430         
431 }
432
433 void
434 RouteUI::build_mute_menu(void)
435 {
436         using namespace Menu_Helpers;
437         
438         mute_menu = new Menu;
439         mute_menu->set_name ("ArdourContextMenu");
440         MenuList& items = mute_menu->items();
441         CheckMenuItem* check;
442         
443         check = new CheckMenuItem(_("Pre Fader"));
444         init_mute_menu(PRE_FADER, check);
445         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
446         _route.pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
447         items.push_back (CheckMenuElem(*check));
448         check->show_all();
449
450         check = new CheckMenuItem(_("Post Fader"));
451         init_mute_menu(POST_FADER, check);
452         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
453         _route.post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
454         items.push_back (CheckMenuElem(*check));
455         check->show_all();
456         
457         check = new CheckMenuItem(_("Control Outs"));
458         init_mute_menu(CONTROL_OUTS, check);
459         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
460         _route.control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
461         items.push_back (CheckMenuElem(*check));
462         check->show_all();
463
464         check = new CheckMenuItem(_("Main Outs"));
465         init_mute_menu(MAIN_OUTS, check);
466         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
467         _route.main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
468         items.push_back (CheckMenuElem(*check));
469         check->show_all();
470
471         items.push_back (SeparatorElem());
472         items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
473 }
474
475 void
476 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
477 {
478         if (_route.get_mute_config (type)) {
479                 check->set_active (true);
480         }
481 }
482
483 void
484 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
485 {
486         _route.set_mute_config(type, check->get_active(), this);
487 }
488
489 void
490 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
491 {
492         _route.set_solo_safe (check->get_active(), this);
493 }
494
495 void
496 RouteUI::set_mix_group_solo(Route& route, bool yn)
497 {
498         RouteGroup* mix_group;
499
500         if((mix_group = route.mix_group()) != 0){
501                 _session.begin_reversible_command (_("mix group solo  change"));
502                 _session.add_undo (_session.global_solo_memento (this));
503                 mix_group->apply(&Route::set_solo, yn, this);
504                 _session.add_redo_no_execute (_session.global_solo_memento(this));
505                 _session.commit_reversible_command ();
506         } else {
507                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route.soloed(), this);
508         }
509 }
510
511 void
512 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
513 {
514         _session.begin_reversible_command (name);
515         _session.add_undo (bind (mem_fun (_route, func), !yn, (void *) arg));
516         _session.add_redo (bind (mem_fun (_route, func), yn, (void *) arg));
517         _session.commit_reversible_command ();
518 }
519
520 void
521 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
522 {
523         _session.begin_reversible_command (name);
524         _session.add_undo (bind (mem_fun (*audio_track(), func), !yn, (void *) arg));
525         _session.add_redo (bind (mem_fun (*audio_track(), func), yn, (void *) arg));
526         _session.commit_reversible_command ();
527 }
528
529 void
530 RouteUI::set_mix_group_mute(Route& route, bool yn)
531 {
532         RouteGroup* mix_group;
533
534         if((mix_group = route.mix_group()) != 0){
535                 _session.begin_reversible_command (_("mix group mute change"));
536                 _session.add_undo (_session.global_mute_memento (this));
537                 mix_group->apply(&Route::set_mute, yn, this);
538                 _session.add_redo_no_execute (_session.global_mute_memento(this));
539                 _session.commit_reversible_command ();
540         } else {
541                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route.muted(), this);
542         }
543 }
544
545 void
546 RouteUI::set_mix_group_rec_enable(Route& route, bool yn)
547 {
548         RouteGroup* mix_group;
549
550         if((mix_group = route.mix_group()) != 0){
551                 _session.begin_reversible_command (_("mix group rec-enable change"));
552                 _session.add_undo (_session.global_record_enable_memento (this));
553                 mix_group->apply (&Route::set_record_enable, yn, this);
554                 _session.add_redo_no_execute (_session.global_record_enable_memento(this));
555                 _session.commit_reversible_command ();
556         } else {
557                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route.record_enabled(), this);
558         }
559 }
560
561
562 bool
563 RouteUI::choose_color()
564 {
565         bool picked;
566         Gdk::Color color;
567
568         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
569
570         if (picked) {
571                 set_color (color);
572         }
573
574         return picked;
575 }
576
577 void
578 RouteUI::set_color (const Gdk::Color & c)
579 {
580         char buf[64];
581         
582         _color = c;
583         
584         ensure_xml_node ();
585         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
586         xml_node->add_property ("color", buf);
587
588          _route.gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
589 }
590
591
592 void
593 RouteUI::ensure_xml_node ()
594 {
595         if (xml_node == 0) {
596                 if ((xml_node = _route.extra_xml ("GUI")) == 0) {
597                         xml_node = new XMLNode ("GUI");
598                         _route.add_extra_xml (*xml_node);
599                 }
600         }
601 }
602
603 XMLNode*
604 RouteUI::get_child_xml_node (const string & childname)
605 {
606         XMLNode* child;
607
608         ensure_xml_node ();
609         
610         
611         if ((child = find_named_node (*xml_node, childname)) == 0) {
612                 child = new XMLNode (childname);
613                 xml_node->add_child_nocopy (*child);
614         }
615
616         return child;
617 }
618
619 int
620 RouteUI::set_color_from_route ()
621 {
622         XMLProperty *prop;
623         
624         RouteUI::ensure_xml_node ();
625
626         if ((prop = xml_node->property ("color")) != 0) {
627                 int r, g, b;
628                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
629                 _color.set_red(r);
630                 _color.set_green(g);
631                 _color.set_blue(b);
632                 return 0;
633         } 
634         return 1;
635 }
636
637 void
638 RouteUI::remove_this_route ()
639 {
640         vector<string> choices;
641         string prompt;
642
643         if (is_audio_track()) {
644                 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());
645         } else {
646                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route.name());
647         }
648
649         choices.push_back (_("Yes, remove it."));
650         choices.push_back (_("No, do nothing."));
651
652         Choice prompter (prompt, choices);
653
654         prompter.chosen.connect(sigc::ptr_fun(Gtk::Main::quit));
655         prompter.show_all ();
656
657         Gtk::Main::run ();
658
659         if (prompter.get_choice() == 0) {
660           Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
661         }
662 }
663
664 gint
665 RouteUI::idle_remove_this_route (RouteUI *rui)
666 {
667         rui->_session.remove_route (rui->_route);
668         return FALSE;
669 }
670
671 void
672 RouteUI::route_removed ()
673 {
674         ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::route_removed));
675         
676         delete this;
677 }
678
679 void
680 RouteUI::route_rename ()
681 {
682         ArdourPrompter name_prompter (true);
683         string result;
684         name_prompter.set_prompt (_("new name: "));
685         name_prompter.set_initial_text (_route.name());
686         name_prompter.show_all ();
687
688         switch (name_prompter.run ()) {
689
690         case GTK_RESPONSE_ACCEPT:
691                 name_prompter.get_result (result);
692                 if (result.length()) {
693                         strip_whitespace_edges (result);
694                         _route.set_name (result, this);
695                 }       
696                 break;
697         }
698
699         return;
700   
701 }
702
703 void
704 RouteUI::name_changed (void *src)
705 {
706         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
707         
708         name_label.set_text (_route.name());
709 }
710
711 void
712 RouteUI::toggle_route_active ()
713 {
714         bool yn;
715
716         if (route_active_menu_item) {
717                 if (route_active_menu_item->get_active() != (yn = _route.active())) {
718                         _route.set_active (!yn);
719                 }
720         }
721 }
722
723 void
724 RouteUI::route_active_changed ()
725 {
726         if (route_active_menu_item) {
727                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route.active()));
728         }
729 }
730
731 void
732 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
733 {
734         bool yn = _route.solo_safe ();
735
736         if (check->get_active() != yn) {
737                 check->set_active (yn);
738         }
739 }
740 void
741 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
742 {
743         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
744         
745         bool yn = _route.get_mute_config(PRE_FADER);
746         if (check->get_active() != yn) {
747                 check->set_active (yn);
748         }
749 }
750
751 void
752 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
753 {
754         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
755         
756         bool yn = _route.get_mute_config(POST_FADER);
757         if (check->get_active() != yn) {
758                 check->set_active (yn);
759         }
760 }
761
762 void
763 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
764 {
765         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
766         
767         bool yn = _route.get_mute_config(CONTROL_OUTS);
768         if (check->get_active() != yn) {
769                 check->set_active (yn);
770         }
771 }
772
773 void
774 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
775 {
776         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
777         
778         bool yn = _route.get_mute_config(MAIN_OUTS);
779         if (check->get_active() != yn) {
780                 check->set_active (yn);
781         }
782 }
783
784 void
785 RouteUI::disconnect_input ()
786 {
787         _route.disconnect_inputs (this);
788 }
789
790 void
791 RouteUI::disconnect_output ()
792 {
793         _route.disconnect_outputs (this);
794 }
795
796 bool
797 RouteUI::is_audio_track () const
798 {
799         return dynamic_cast<AudioTrack*>(&_route) != 0;
800 }
801
802 DiskStream*
803 RouteUI::get_diskstream () const
804 {
805         AudioTrack *at;
806
807         if ((at = dynamic_cast<AudioTrack*>(&_route)) != 0) {
808                 return &at->disk_stream();
809         } else {
810                 return 0;
811         }
812 }
813
814 AudioTrack*
815 RouteUI::audio_track() const
816 {
817         return dynamic_cast<AudioTrack*>(&_route);
818 }
819 string
820 RouteUI::name() const
821 {
822         return _route.name();
823 }
824
825 void
826 RouteUI::map_frozen ()
827 {
828         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
829
830         AudioTrack* at = dynamic_cast<AudioTrack*>(&_route);
831
832         if (at) {
833                 switch (at->freeze_state()) {
834                 case AudioTrack::Frozen:
835                         rec_enable_button->set_sensitive (false);
836                         break;
837                 default:
838                         rec_enable_button->set_sensitive (true);
839                         break;
840                 }
841         }
842 }