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