2 Copyright (C) 2002-2006 Paul Davis
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.
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.
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.
20 #include <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/stop_signal.h>
22 #include <gtkmm2ext/choice.h>
23 #include <gtkmm2ext/doi.h>
24 #include <gtkmm2ext/bindable_button.h>
25 #include <gtkmm2ext/gtk_ui.h>
27 #include <ardour/route_group.h>
28 #include <pbd/memento_command.h>
29 #include <pbd/stacktrace.h>
30 #include <pbd/shiva.h>
36 #include "gui_thread.h"
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/profile.h>
48 using namespace Gtkmm2ext;
49 using namespace ARDOUR;
52 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
56 set_button_names (mute_name, solo_name, rec_name);
59 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
60 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
64 set_button_names (mute_name, solo_name, rec_name);
74 remote_control_menu = 0;
75 ignore_toggle = false;
76 wait_for_release = false;
77 route_active_menu_item = 0;
78 was_solo_safe = false;
79 polarity_menu_item = 0;
80 denormal_menu_item = 0;
81 multiple_mute_change = false;
82 multiple_solo_change = false;
84 mute_button = manage (new BindableToggleButton (0, ""));
85 mute_button->set_self_managed (true);
86 mute_button->set_name ("MuteButton");
87 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
89 solo_button = manage (new BindableToggleButton (0, ""));
90 solo_button->set_self_managed (true);
91 solo_button->set_name ("SoloButton");
92 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
94 rec_enable_button = manage (new BindableToggleButton (0, ""));
95 rec_enable_button->set_name ("RecordEnableButton");
96 rec_enable_button->set_self_managed (true);
97 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
99 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
105 connections.clear ();
117 if (remote_control_menu) {
118 delete remote_control_menu;
119 remote_control_menu = 0;
123 /* do not delete the node - its owned by the route */
127 route_active_menu_item = 0;
128 polarity_menu_item = 0;
129 denormal_menu_item = 0;
133 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
141 RouteUI::set_route (boost::shared_ptr<Route> rp)
147 if (set_color_from_route()) {
148 set_color (unique_random_color());
151 /* no, there is no memory leak here. This object cleans itself (and other stuff)
152 up when the route is destroyed.
155 new PairedShiva<Route,RouteUI> (*_route, *this);
157 mute_button->set_controllable (&_route->mute_control());
158 mute_button->set_label (m_name);
160 solo_button->set_controllable (&_route->solo_control());
161 solo_button->set_label (s_name);
163 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
164 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
165 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
166 connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
168 /* when solo changes, update mute state too, in case the user wants us to display it */
170 update_solo_display ();
171 update_mute_display ();
174 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
176 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
178 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
180 rec_enable_button->set_controllable (&t->rec_enable_control());
181 rec_enable_button->set_label (r_name);
183 update_rec_display ();
186 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
188 /* map the current state */
195 GoingAway (); /* EMIT SIGNAL */
204 if (remote_control_menu) {
205 delete remote_control_menu;
210 RouteUI::mute_press(GdkEventButton* ev)
212 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
215 multiple_mute_change = false;
216 if (!ignore_toggle) {
218 if (Keyboard::is_context_menu_event (ev)) {
224 mute_menu->popup(0,ev->time);
228 if (Keyboard::is_button2_event (ev)) {
229 // Primary-button2 click is the midi binding click
230 // button2-click is "momentary"
232 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
233 wait_for_release = true;
239 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
241 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
243 /* Primary-Tertiary-click applies change to all routes */
245 _session.begin_reversible_command (_("mute change"));
246 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
247 _session.set_all_mute (!_route->muted());
249 _session.add_command(cmd);
250 _session.commit_reversible_command ();
251 multiple_mute_change = true;
253 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
255 /* Primary-button1 applies change to the mix group.
256 NOTE: Primary-button2 is MIDI learn.
259 if (ev->button == 1) {
260 set_mix_group_mute (_route, !_route->muted());
265 /* plain click applies change to this route */
266 if (wait_for_release) {
267 _route->set_mute (!_route->muted(), this);
269 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
281 RouteUI::mute_release(GdkEventButton* ev)
283 if (!ignore_toggle) {
284 if (wait_for_release){
285 wait_for_release = false;
286 if (multiple_mute_change) {
287 multiple_mute_change = false;
289 // because the press was the last undoable thing we did
292 _route->set_mute (!_route->muted(), this);
300 RouteUI::solo_press(GdkEventButton* ev)
302 /* ignore double/triple clicks */
304 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
307 multiple_solo_change = false;
308 if (!ignore_toggle) {
310 if (Keyboard::is_context_menu_event (ev)) {
312 if (solo_menu == 0) {
316 solo_menu->popup (1, ev->time);
320 if (Keyboard::is_button2_event (ev)) {
322 // Primary-button2 click is the midi binding click
323 // button2-click is "momentary"
325 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
326 wait_for_release = true;
332 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
334 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
336 /* Primary-Tertiary-click applies change to all routes */
337 bool was_not_latched = false;
338 if (!Config->get_solo_latched ()) {
339 was_not_latched = true;
341 XXX it makes no sense to solo all tracks if we're
342 not in latched mode, but doing nothing feels like a bug,
345 Config->set_solo_latched (true);
347 _session.begin_reversible_command (_("solo change"));
348 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
349 _session.set_all_solo (!_route->soloed());
351 _session.add_command (cmd);
352 _session.commit_reversible_command ();
353 multiple_solo_change = true;
354 if (was_not_latched) {
355 Config->set_solo_latched (false);
358 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
360 // Primary-Secondary-click: exclusively solo this track, not a toggle */
362 _session.begin_reversible_command (_("solo change"));
363 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
364 _session.set_all_solo (false);
365 _route->set_solo (true, this);
367 _session.add_command(cmd);
368 _session.commit_reversible_command ();
370 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
372 // shift-click: set this route to solo safe
374 if (Profile->get_sae() && ev->button == 1) {
375 // button 1 and shift-click: disables solo_latched for this click
376 if (!Config->get_solo_latched ()) {
377 Config->set_solo_latched (true);
378 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
379 Config->set_solo_latched (false);
382 _route->set_solo_safe (!_route->solo_safe(), this);
383 wait_for_release = false;
386 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
388 /* Primary-button1: solo mix group.
389 NOTE: Primary-button2 is MIDI learn.
392 if (ev->button == 1) {
393 set_mix_group_solo (_route, !_route->soloed());
398 /* click: solo this route */
399 if (wait_for_release) {
400 _route->set_solo (!_route->soloed(), this);
402 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
413 RouteUI::solo_release(GdkEventButton* ev)
415 if (!ignore_toggle) {
416 if (wait_for_release) {
417 wait_for_release = false;
418 if (multiple_solo_change) {
419 multiple_solo_change = false;
421 // because the press was the last undoable thing we did
424 // we don't use "undo the last op"
425 // here because its expensive for the GUI
426 _route->set_solo (!_route->soloed(), this);
435 RouteUI::rec_enable_press(GdkEventButton* ev)
437 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
441 if (!_session.engine().connected()) {
442 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
447 if (!ignore_toggle && is_track() && rec_enable_button) {
449 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
451 // do nothing on midi bind event
454 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
456 _session.begin_reversible_command (_("rec-enable change"));
457 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
459 if (rec_enable_button->get_active()) {
460 _session.record_disenable_all ();
462 _session.record_enable_all ();
466 _session.add_command(cmd);
467 _session.commit_reversible_command ();
469 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
471 /* Primary-button1 applies change to the mix group.
472 NOTE: Primary-button2 is MIDI learn.
475 set_mix_group_rec_enable (_route, !_route->record_enabled());
479 reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
487 RouteUI::rec_enable_release (GdkEventButton* ev)
493 RouteUI::solo_changed(void* src)
496 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
500 RouteUI::update_solo_display ()
503 vector<Gdk::Color> fg_colors;
506 if (solo_button->get_active() != (x = _route->soloed())){
507 ignore_toggle = true;
508 solo_button->set_active(x);
509 ignore_toggle = false;
512 if (_route->solo_safe()) {
513 solo_button->set_visual_state (2);
514 } else if (_route->soloed()) {
515 solo_button->set_visual_state (1);
517 solo_button->set_visual_state (0);
522 RouteUI::solo_changed_so_update_mute ()
524 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
528 RouteUI::mute_changed(void* src)
530 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
534 RouteUI::update_mute_display ()
536 bool model = _route->muted();
537 bool view = mute_button->get_active();
539 /* first make sure the button's "depressed" visual
544 ignore_toggle = true;
545 mute_button->set_active (model);
546 ignore_toggle = false;
549 /* now attend to visual state */
551 if (Config->get_show_solo_mutes()) {
552 if (_route->muted()) {
553 mute_button->set_visual_state (2);
554 } else if (!_route->soloed() && _route->solo_muted()) {
556 mute_button->set_visual_state (1);
558 mute_button->set_visual_state (0);
561 if (_route->muted()) {
562 mute_button->set_visual_state (2);
564 mute_button->set_visual_state (0);
571 RouteUI::route_rec_enable_changed ()
573 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
577 RouteUI::session_rec_enable_changed ()
579 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
583 RouteUI::update_rec_display ()
585 bool model = _route->record_enabled();
586 bool view = rec_enable_button->get_active();
588 /* first make sure the button's "depressed" visual
593 ignore_toggle = true;
594 rec_enable_button->set_active (model);
595 ignore_toggle = false;
598 /* now make sure its color state is correct */
602 switch (_session.record_status ()) {
603 case Session::Recording:
604 rec_enable_button->set_visual_state (1);
607 case Session::Disabled:
608 case Session::Enabled:
609 rec_enable_button->set_visual_state (2);
615 rec_enable_button->set_visual_state (0);
620 RouteUI::build_remote_control_menu ()
622 remote_control_menu = new Menu;
623 refresh_remote_control_menu ();
627 RouteUI::refresh_remote_control_menu ()
629 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
631 // only refresh the menu if it has been instantiated
633 if (remote_control_menu == 0) {
637 using namespace Menu_Helpers;
639 RadioMenuItem::Group rc_group;
640 CheckMenuItem* rc_active;
641 uint32_t limit = _session.ntracks() + _session.nbusses();
644 MenuList& rc_items = remote_control_menu->items();
647 /* note that this menu list starts at zero, not 1, because zero
648 is a valid, if useless, ID.
651 limit += 4; /* leave some breathing room */
653 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
654 if (_route->remote_control_id() == 0) {
655 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
656 rc_active->set_active ();
659 for (uint32_t i = 1; i < limit; ++i) {
660 snprintf (buf, sizeof (buf), "%u", i);
661 rc_items.push_back (RadioMenuElem (rc_group, buf));
662 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
663 if (_route->remote_control_id() == i) {
664 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
665 rc_active->set_active ();
667 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
672 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
674 /* this is called when the radio menu item is toggled, and so
675 is actually invoked twice per menu selection. we only
676 care about the invocation for the item that was being
680 if (item->get_active()) {
681 _route->set_remote_control_id (id);
686 RouteUI::build_solo_menu (void)
688 using namespace Menu_Helpers;
690 solo_menu = new Menu;
691 solo_menu->set_name ("ArdourContextMenu");
692 MenuList& items = solo_menu->items();
693 CheckMenuItem* check;
695 check = new CheckMenuItem(_("Solo-safe"));
696 check->set_active (_route->solo_safe());
697 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
698 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
699 items.push_back (CheckMenuElem(*check));
702 //items.push_back (SeparatorElem());
703 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
708 RouteUI::build_mute_menu(void)
710 using namespace Menu_Helpers;
712 mute_menu = new Menu;
713 mute_menu->set_name ("ArdourContextMenu");
714 MenuList& items = mute_menu->items();
715 CheckMenuItem* check;
717 check = new CheckMenuItem(_("Pre Fader"));
718 init_mute_menu(PRE_FADER, check);
719 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
720 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
721 items.push_back (CheckMenuElem(*check));
724 check = new CheckMenuItem(_("Post Fader"));
725 init_mute_menu(POST_FADER, check);
726 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
727 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
728 items.push_back (CheckMenuElem(*check));
731 check = new CheckMenuItem(_("Control Outs"));
732 init_mute_menu(CONTROL_OUTS, check);
733 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
734 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
735 items.push_back (CheckMenuElem(*check));
738 check = new CheckMenuItem(_("Main Outs"));
739 init_mute_menu(MAIN_OUTS, check);
740 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
741 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
742 items.push_back (CheckMenuElem(*check));
745 //items.push_back (SeparatorElem());
746 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
750 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
752 if (_route->get_mute_config (type)) {
753 check->set_active (true);
758 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
760 _route->set_mute_config(type, check->get_active(), this);
764 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
766 _route->set_solo_safe (check->get_active(), this);
770 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
772 RouteGroup* mix_group;
774 if((mix_group = route->mix_group()) != 0){
775 _session.begin_reversible_command (_("mix group solo change"));
776 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
777 mix_group->apply(&Route::set_solo, yn, this);
779 _session.add_command (cmd);
780 _session.commit_reversible_command ();
782 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
787 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
789 _session.begin_reversible_command (name);
790 XMLNode &before = _route->get_state();
791 bind(mem_fun(*_route, func), yn, arg)();
792 XMLNode &after = _route->get_state();
793 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
794 _session.commit_reversible_command ();
798 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
800 _session.begin_reversible_command (name);
801 XMLNode &before = audio_track()->get_state();
802 bind (mem_fun (*audio_track(), func), yn, arg)();
803 XMLNode &after = audio_track()->get_state();
804 _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), &before, &after));
805 _session.commit_reversible_command ();
809 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
811 RouteGroup* mix_group;
813 if((mix_group = route->mix_group()) != 0){
814 _session.begin_reversible_command (_("mix group mute change"));
815 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
816 mix_group->apply(&Route::set_mute, yn, this);
818 _session.add_command(cmd);
819 _session.commit_reversible_command ();
821 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
826 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
828 RouteGroup* mix_group;
830 if((mix_group = route->mix_group()) != 0){
831 _session.begin_reversible_command (_("mix group rec-enable change"));
832 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
833 mix_group->apply (&Route::set_record_enable, yn, this);
835 _session.add_command(cmd);
836 _session.commit_reversible_command ();
838 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
844 RouteUI::choose_color()
849 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
859 RouteUI::set_color (const Gdk::Color & c)
866 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
867 xml_node->add_property ("color", buf);
869 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
874 RouteUI::ensure_xml_node ()
877 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
878 xml_node = new XMLNode ("GUI");
879 _route->add_extra_xml (*xml_node);
885 RouteUI::get_child_xml_node (const string & childname)
892 if ((child = find_named_node (*xml_node, childname)) == 0) {
893 child = new XMLNode (childname);
894 xml_node->add_child_nocopy (*child);
901 RouteUI::set_color_from_route ()
905 RouteUI::ensure_xml_node ();
907 if ((prop = xml_node->property ("color")) != 0) {
909 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
919 RouteUI::remove_this_route ()
921 vector<string> choices;
925 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());
927 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
930 choices.push_back (_("No, do nothing."));
931 choices.push_back (_("Yes, remove it."));
933 Choice prompter (prompt, choices);
935 if (prompter.run () == 1) {
936 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
941 RouteUI::idle_remove_this_route (RouteUI *rui)
943 rui->_session.remove_route (rui->_route);
948 RouteUI::route_rename ()
950 ArdourPrompter name_prompter (true);
952 name_prompter.set_prompt (_("New Name: "));
953 name_prompter.set_initial_text (_route->name());
954 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
955 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
956 name_prompter.show_all ();
958 switch (name_prompter.run ()) {
960 case Gtk::RESPONSE_ACCEPT:
961 name_prompter.get_result (result);
962 if (result.length()) {
963 _route->set_name (result, this);
973 RouteUI::name_changed (void *src)
975 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
977 name_label.set_text (_route->name());
981 RouteUI::toggle_route_active ()
985 if (route_active_menu_item) {
986 if (route_active_menu_item->get_active() != (yn = _route->active())) {
987 _route->set_active (!yn);
993 RouteUI::route_active_changed ()
995 if (route_active_menu_item) {
996 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1001 RouteUI::toggle_polarity ()
1003 if (polarity_menu_item) {
1007 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1009 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1010 _route->set_phase_invert (x, this);
1012 name_label.set_text (X_("Ø ") + name_label.get_text());
1014 name_label.set_text (_route->name());
1021 RouteUI::polarity_changed ()
1023 /* no signal for this yet */
1027 RouteUI::toggle_denormal_protection ()
1029 if (denormal_menu_item) {
1033 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1035 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1036 _route->set_denormal_protection (x, this);
1042 RouteUI::denormal_protection_changed ()
1044 /* no signal for this yet */
1049 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1051 bool yn = _route->solo_safe ();
1053 if (check->get_active() != yn) {
1054 check->set_active (yn);
1058 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1060 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1062 bool yn = _route->get_mute_config(PRE_FADER);
1063 if (check->get_active() != yn) {
1064 check->set_active (yn);
1069 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1071 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1073 bool yn = _route->get_mute_config(POST_FADER);
1074 if (check->get_active() != yn) {
1075 check->set_active (yn);
1080 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1082 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1084 bool yn = _route->get_mute_config(CONTROL_OUTS);
1085 if (check->get_active() != yn) {
1086 check->set_active (yn);
1091 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1093 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1095 bool yn = _route->get_mute_config(MAIN_OUTS);
1096 if (check->get_active() != yn) {
1097 check->set_active (yn);
1102 RouteUI::disconnect_input ()
1104 _route->disconnect_inputs (this);
1108 RouteUI::disconnect_output ()
1110 _route->disconnect_outputs (this);
1114 RouteUI::is_track () const
1116 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1119 boost::shared_ptr<Track>
1120 RouteUI::track() const
1122 return boost::dynamic_pointer_cast<Track>(_route);
1126 RouteUI::is_audio_track () const
1128 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1131 boost::shared_ptr<AudioTrack>
1132 RouteUI::audio_track() const
1134 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1137 boost::shared_ptr<Diskstream>
1138 RouteUI::get_diskstream () const
1140 boost::shared_ptr<Track> t;
1142 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1143 return t->diskstream();
1145 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1150 RouteUI::name() const
1152 return _route->name();
1156 RouteUI::map_frozen ()
1158 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1160 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1163 switch (at->freeze_state()) {
1164 case AudioTrack::Frozen:
1165 rec_enable_button->set_sensitive (false);
1168 rec_enable_button->set_sensitive (true);