RCU-ification of AudioEngine port list, and DiskStreams. not well tested, but basical...
[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 #include <pbd/memento_command.h>
29
30 #include "route_ui.h"
31 #include "keyboard.h"
32 #include "utils.h"
33 #include "prompter.h"
34 #include "gui_thread.h"
35
36 #include <ardour/route.h>
37 #include <ardour/audio_track.h>
38 #include <ardour/audio_diskstream.h>
39
40 #include "i18n.h"
41 using namespace sigc;
42 using namespace Gtk;
43 using namespace Gtkmm2ext;
44 using namespace ARDOUR;
45 using namespace PBD;
46
47
48 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name,
49                   const char* s_name, const char* r_name)
50         : AxisView(sess),
51           _route(rt),
52           mute_button(0),
53           solo_button(0),
54           rec_enable_button(0)
55 {
56         xml_node = 0;
57         mute_menu = 0;
58         solo_menu = 0;
59         remote_control_menu = 0;
60         ignore_toggle = false;
61         wait_for_release = false;
62         route_active_menu_item = 0;
63
64         if (set_color_from_route()) {
65                 set_color (unique_random_color());
66         }
67
68         _route->GoingAway.connect (mem_fun (*this, &RouteUI::route_removed));
69         _route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
70
71         mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name ));
72         solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name ));
73         
74         if (is_track()) {
75                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
76
77                 t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed));
78
79                 _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
80
81                 rec_enable_button = manage (new BindableToggleButton (t->rec_enable_control(), r_name ));
82
83                 rec_enable_button->unset_flags (Gtk::CAN_FOCUS);
84                 
85                 update_rec_display ();
86         } 
87         
88         mute_button->unset_flags (Gtk::CAN_FOCUS);
89         solo_button->unset_flags (Gtk::CAN_FOCUS);
90
91         /* map the current state */
92
93         map_frozen ();
94 }
95
96 RouteUI::~RouteUI()
97 {
98         delete mute_menu;
99 }
100
101 gint
102 RouteUI::mute_press(GdkEventButton* ev)
103 {
104         if (!ignore_toggle) {
105
106                 if (Keyboard::is_context_menu_event (ev)) {
107
108                         if (mute_menu == 0){
109                                 build_mute_menu();
110                         }
111
112                         mute_menu->popup(0,0);
113
114                 } else {
115
116                         if (ev->button == 2) {
117                                 // ctrl-button2 click is the midi binding click
118                                 // button2-click is "momentary"
119                                 
120                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control))) {
121                                         wait_for_release = true;
122                                 }
123                         }
124
125                         if (ev->button == 1 || ev->button == 2) {
126
127                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
128
129                                         /* ctrl-shift-click applies change to all routes */
130
131                                         _session.begin_reversible_command (_("mute change"));
132                                         Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
133                                         _session.set_all_mute (!_route->muted());
134                                         cmd->mark();
135                                         _session.add_command(cmd);
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::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
209                                         _session.set_all_solo (!_route->soloed());
210                                         cmd->mark();
211                                         _session.add_command (cmd);
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::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
220                                         _session.set_all_solo (false);
221                                         _route->set_solo (true, this);
222                                         cmd->mark();
223                                         _session.add_command(cmd);
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 true;
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         }
268
269         return true;
270 }
271
272 gint
273 RouteUI::rec_enable_press(GdkEventButton* ev)
274 {
275         if (!ignore_toggle && is_track() && rec_enable_button) {
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::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
284
285                         if (rec_enable_button->get_active()) {
286                                 _session.record_disenable_all ();
287                         } else {
288                                 _session.record_enable_all ();
289                         }
290
291                         cmd->mark();
292                         _session.add_command(cmd);
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 ()
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         rc_items.push_back (RadioMenuElem (rc_group, _("None")));
439         if (_route->remote_control_id() == 0) {
440                 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
441                 rc_active->set_active ();
442         }
443                 
444         for (uint32_t i = 1; i < limit; ++i) {
445                 snprintf (buf, sizeof (buf), "%u", i);
446                 rc_items.push_back (RadioMenuElem (rc_group, buf));
447                 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
448                 if (_route->remote_control_id() == i) {
449                         rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
450                         rc_active->set_active ();
451                 }
452                 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
453         }
454 }
455
456 void
457 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
458 {
459         /* this is called when the radio menu item is toggled, and so 
460            is actually invoked twice per menu selection. we only
461            care about the invocation for the item that was being
462            marked active.
463         */
464
465         if (item->get_active()) {
466                 _route->set_remote_control_id (id);
467         }
468 }
469
470 void
471 RouteUI::build_solo_menu (void)
472 {
473         using namespace Menu_Helpers;
474         
475         solo_menu = new Menu;
476         solo_menu->set_name ("ArdourContextMenu");
477         MenuList& items = solo_menu->items();
478         CheckMenuItem* check;
479
480         check = new CheckMenuItem(_("Solo-safe"));
481         check->set_active (_route->solo_safe());
482         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
483         _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
484         items.push_back (CheckMenuElem(*check));
485         check->show_all();
486
487         items.push_back (SeparatorElem());
488         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
489         
490 }
491
492 void
493 RouteUI::build_mute_menu(void)
494 {
495         using namespace Menu_Helpers;
496         
497         mute_menu = new Menu;
498         mute_menu->set_name ("ArdourContextMenu");
499         MenuList& items = mute_menu->items();
500         CheckMenuItem* check;
501         
502         check = new CheckMenuItem(_("Pre Fader"));
503         init_mute_menu(PRE_FADER, check);
504         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
505         _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
506         items.push_back (CheckMenuElem(*check));
507         check->show_all();
508
509         check = new CheckMenuItem(_("Post Fader"));
510         init_mute_menu(POST_FADER, check);
511         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
512         _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
513         items.push_back (CheckMenuElem(*check));
514         check->show_all();
515         
516         check = new CheckMenuItem(_("Control Outs"));
517         init_mute_menu(CONTROL_OUTS, check);
518         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
519         _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
520         items.push_back (CheckMenuElem(*check));
521         check->show_all();
522
523         check = new CheckMenuItem(_("Main Outs"));
524         init_mute_menu(MAIN_OUTS, check);
525         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
526         _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
527         items.push_back (CheckMenuElem(*check));
528         check->show_all();
529
530         items.push_back (SeparatorElem());
531         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
532 }
533
534 void
535 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
536 {
537         if (_route->get_mute_config (type)) {
538                 check->set_active (true);
539         }
540 }
541
542 void
543 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
544 {
545         _route->set_mute_config(type, check->get_active(), this);
546 }
547
548 void
549 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
550 {
551         _route->set_solo_safe (check->get_active(), this);
552 }
553
554 void
555 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
556 {
557         RouteGroup* mix_group;
558
559         if((mix_group = route->mix_group()) != 0){
560                 _session.begin_reversible_command (_("mix group solo  change"));
561                 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
562                 mix_group->apply(&Route::set_solo, yn, this);
563                 cmd->mark();
564                 _session.add_command (cmd);
565                 _session.commit_reversible_command ();
566         } else {
567                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
568         }
569 }
570
571 void
572 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
573 {
574         _session.begin_reversible_command (name);
575         XMLNode &before = _route->get_state();
576         bind(mem_fun(*_route, func), yn, arg)();
577         XMLNode &after = _route->get_state();
578         _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
579         _session.commit_reversible_command ();
580 }
581
582 void
583 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
584 {
585         _session.begin_reversible_command (name);
586         XMLNode &before = audio_track()->get_state();
587         bind (mem_fun (*audio_track(), func), yn, arg)();
588         XMLNode &after = audio_track()->get_state();
589         _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), &before, &after));
590         _session.commit_reversible_command ();
591 }
592
593 void
594 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
595 {
596         RouteGroup* mix_group;
597
598         if((mix_group = route->mix_group()) != 0){
599                 _session.begin_reversible_command (_("mix group mute change"));
600                 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
601                 mix_group->apply(&Route::set_mute, yn, this);
602                 cmd->mark();
603                 _session.add_command(cmd);
604                 _session.commit_reversible_command ();
605         } else {
606                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
607         }
608 }
609
610 void
611 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
612 {
613         RouteGroup* mix_group;
614
615         if((mix_group = route->mix_group()) != 0){
616                 _session.begin_reversible_command (_("mix group rec-enable change"));
617                 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
618                 mix_group->apply (&Route::set_record_enable, yn, this);
619                 cmd->mark();
620                 _session.add_command(cmd);
621                 _session.commit_reversible_command ();
622         } else {
623                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
624         }
625 }
626
627
628 bool
629 RouteUI::choose_color()
630 {
631         bool picked;
632         Gdk::Color color;
633
634         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
635
636         if (picked) {
637                 set_color (color);
638         }
639
640         return picked;
641 }
642
643 void
644 RouteUI::set_color (const Gdk::Color & c)
645 {
646         char buf[64];
647         
648         _color = c;
649         
650         ensure_xml_node ();
651         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
652         xml_node->add_property ("color", buf);
653
654          _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
655 }
656
657
658 void
659 RouteUI::ensure_xml_node ()
660 {
661         if (xml_node == 0) {
662                 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
663                         xml_node = new XMLNode ("GUI");
664                         _route->add_extra_xml (*xml_node);
665                 }
666         }
667 }
668
669 XMLNode*
670 RouteUI::get_child_xml_node (const string & childname)
671 {
672         XMLNode* child;
673
674         ensure_xml_node ();
675         
676         
677         if ((child = find_named_node (*xml_node, childname)) == 0) {
678                 child = new XMLNode (childname);
679                 xml_node->add_child_nocopy (*child);
680         }
681
682         return child;
683 }
684
685 int
686 RouteUI::set_color_from_route ()
687 {
688         XMLProperty *prop;
689         
690         RouteUI::ensure_xml_node ();
691
692         if ((prop = xml_node->property ("color")) != 0) {
693                 int r, g, b;
694                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
695                 _color.set_red(r);
696                 _color.set_green(g);
697                 _color.set_blue(b);
698                 return 0;
699         } 
700         return 1;
701 }
702
703 void
704 RouteUI::remove_this_route ()
705 {
706         vector<string> choices;
707         string prompt;
708
709         if (is_track()) {
710                 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());
711         } else {
712                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
713         }
714
715         choices.push_back (_("No, do nothing."));
716         choices.push_back (_("Yes, remove it."));
717
718         Choice prompter (prompt, choices);
719
720         if (prompter.run () == 1) {
721                 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
722         }
723 }
724
725 gint
726 RouteUI::idle_remove_this_route (RouteUI *rui)
727 {
728         rui->_session.remove_route (rui->_route);
729         return FALSE;
730 }
731
732 void
733 RouteUI::route_removed ()
734 {
735         ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::route_removed));
736         cerr << "Route UI @ " << this << " destroyed by impending end of route\n";
737         delete this;
738 }
739
740 void
741 RouteUI::route_rename ()
742 {
743         ArdourPrompter name_prompter (true);
744         string result;
745         name_prompter.set_prompt (_("New Name: "));
746         name_prompter.set_initial_text (_route->name());
747         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
748         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
749         name_prompter.show_all ();
750
751         switch (name_prompter.run ()) {
752
753         case Gtk::RESPONSE_ACCEPT:
754         name_prompter.get_result (result);
755         if (result.length()) {
756                         _route->set_name (result, this);
757                 }       
758                 break;
759         }
760
761         return;
762   
763 }
764
765 void
766 RouteUI::name_changed (void *src)
767 {
768         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
769
770         name_label.set_text (_route->name());
771 }
772
773 void
774 RouteUI::toggle_route_active ()
775 {
776         bool yn;
777
778         if (route_active_menu_item) {
779                 if (route_active_menu_item->get_active() != (yn = _route->active())) {
780                         _route->set_active (!yn);
781                 }
782         }
783 }
784
785 void
786 RouteUI::route_active_changed ()
787 {
788         if (route_active_menu_item) {
789                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
790         }
791 }
792
793 void
794 RouteUI::toggle_polarity ()
795 {
796         if (polarity_menu_item) {
797
798                 bool x;
799
800                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
801                 
802                 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
803                         _route->set_phase_invert (x, this);
804                         if (x) {
805                                 name_label.set_text (X_("Ø ") + name_label.get_text());
806                         } else {
807                                 name_label.set_text (_route->name());
808                         }
809                 }
810         }
811 }
812
813 void
814 RouteUI::polarity_changed ()
815 {
816         /* no signal for this yet */
817 }
818
819 void
820 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
821 {
822         bool yn = _route->solo_safe ();
823
824         if (check->get_active() != yn) {
825                 check->set_active (yn);
826         }
827 }
828 void
829 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
830 {
831         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
832         
833         bool yn = _route->get_mute_config(PRE_FADER);
834         if (check->get_active() != yn) {
835                 check->set_active (yn);
836         }
837 }
838
839 void
840 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
841 {
842         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
843         
844         bool yn = _route->get_mute_config(POST_FADER);
845         if (check->get_active() != yn) {
846                 check->set_active (yn);
847         }
848 }
849
850 void
851 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
852 {
853         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
854         
855         bool yn = _route->get_mute_config(CONTROL_OUTS);
856         if (check->get_active() != yn) {
857                 check->set_active (yn);
858         }
859 }
860
861 void
862 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
863 {
864         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
865         
866         bool yn = _route->get_mute_config(MAIN_OUTS);
867         if (check->get_active() != yn) {
868                 check->set_active (yn);
869         }
870 }
871
872 void
873 RouteUI::disconnect_input ()
874 {
875         _route->disconnect_inputs (this);
876 }
877
878 void
879 RouteUI::disconnect_output ()
880 {
881         _route->disconnect_outputs (this);
882 }
883
884 bool
885 RouteUI::is_track () const
886 {
887         return dynamic_cast<Track*>(_route.get()) != 0;
888 }
889
890 Track*
891 RouteUI::track() const
892 {
893         return dynamic_cast<Track*>(_route.get());
894 }
895
896 bool
897 RouteUI::is_audio_track () const
898 {
899         return dynamic_cast<AudioTrack*>(_route.get()) != 0;
900 }
901
902 AudioTrack*
903 RouteUI::audio_track() const
904 {
905         return dynamic_cast<AudioTrack*>(_route.get());
906 }
907
908 boost::shared_ptr<Diskstream>
909 RouteUI::get_diskstream () const
910 {
911         boost::shared_ptr<Track> t;
912
913         if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
914                 return t->diskstream();
915         } else {
916                 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
917         }
918 }
919
920 string
921 RouteUI::name() const
922 {
923         return _route->name();
924 }
925
926 void
927 RouteUI::map_frozen ()
928 {
929         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
930
931         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
932
933         if (at) {
934                 switch (at->freeze_state()) {
935                 case AudioTrack::Frozen:
936                         rec_enable_button->set_sensitive (false);
937                         break;
938                 default:
939                         rec_enable_button->set_sensitive (true);
940                         break;
941                 }
942         }
943 }
944