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