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