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