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 ();
118 /* do not delete the node - its owned by the route */
122 route_active_menu_item = 0;
123 polarity_menu_item = 0;
124 denormal_menu_item = 0;
128 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
136 RouteUI::set_route (boost::shared_ptr<Route> rp)
142 if (set_color_from_route()) {
143 set_color (unique_random_color());
146 /* no, there is no memory leak here. This object cleans itself (and other stuff)
147 up when the route is destroyed.
150 new PairedShiva<Route,RouteUI> (*_route, *this);
152 mute_button->set_controllable (&_route->mute_control());
153 mute_button->set_label (m_name);
155 solo_button->set_controllable (&_route->solo_control());
156 solo_button->set_label (s_name);
158 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
159 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
160 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
161 connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
163 /* when solo changes, update mute state too, in case the user wants us to display it */
165 update_solo_display ();
166 update_mute_display ();
169 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
171 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
173 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
175 rec_enable_button->set_controllable (&t->rec_enable_control());
176 rec_enable_button->set_label (r_name);
178 update_rec_display ();
181 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
183 /* map the current state */
190 GoingAway (); /* EMIT SIGNAL */
200 /* Note: the remote control menu is constructed
201 by derived classes (e.g. MixerStrip or RouteTimeAxis) and
202 is always attached to a context menu. It then becomes
203 owned by that menu, and will deleted along with it. We
204 do not need to take care of it here.
209 RouteUI::mute_press(GdkEventButton* ev)
211 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
214 multiple_mute_change = false;
215 if (!ignore_toggle) {
217 if (Keyboard::is_context_menu_event (ev)) {
223 mute_menu->popup(0,ev->time);
227 if (Keyboard::is_button2_event (ev)) {
228 // Primary-button2 click is the midi binding click
229 // button2-click is "momentary"
231 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
232 wait_for_release = true;
238 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
240 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
242 /* Primary-Tertiary-click applies change to all routes */
244 _session.begin_reversible_command (_("mute change"));
245 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
246 _session.set_all_mute (!_route->muted());
248 _session.add_command(cmd);
249 _session.commit_reversible_command ();
250 multiple_mute_change = true;
252 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
254 /* Primary-button1 applies change to the mix group.
255 NOTE: Primary-button2 is MIDI learn.
258 if (ev->button == 1) {
259 set_mix_group_mute (_route, !_route->muted());
264 /* plain click applies change to this route */
265 if (wait_for_release) {
266 _route->set_mute (!_route->muted(), this);
268 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
280 RouteUI::mute_release(GdkEventButton* ev)
282 if (!ignore_toggle) {
283 if (wait_for_release){
284 wait_for_release = false;
285 if (multiple_mute_change) {
286 multiple_mute_change = false;
288 // because the press was the last undoable thing we did
291 _route->set_mute (!_route->muted(), this);
299 RouteUI::solo_press(GdkEventButton* ev)
301 /* ignore double/triple clicks */
303 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
306 multiple_solo_change = false;
307 if (!ignore_toggle) {
309 if (Keyboard::is_context_menu_event (ev)) {
311 if (solo_menu == 0) {
315 solo_menu->popup (1, ev->time);
319 if (Keyboard::is_button2_event (ev)) {
321 // Primary-button2 click is the midi binding click
322 // button2-click is "momentary"
324 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
325 wait_for_release = true;
331 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
333 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
335 /* Primary-Tertiary-click applies change to all routes */
336 bool was_not_latched = false;
337 if (!Config->get_solo_latched ()) {
338 was_not_latched = true;
340 XXX it makes no sense to solo all tracks if we're
341 not in latched mode, but doing nothing feels like a bug,
344 Config->set_solo_latched (true);
346 _session.begin_reversible_command (_("solo change"));
347 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
348 _session.set_all_solo (!_route->soloed());
350 _session.add_command (cmd);
351 _session.commit_reversible_command ();
352 multiple_solo_change = true;
353 if (was_not_latched) {
354 Config->set_solo_latched (false);
357 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
359 // Primary-Secondary-click: exclusively solo this track, not a toggle */
361 _session.begin_reversible_command (_("solo change"));
362 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
363 _session.set_all_solo (false);
364 _route->set_solo (true, this);
366 _session.add_command(cmd);
367 _session.commit_reversible_command ();
369 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
371 // shift-click: set this route to solo safe
373 if (Profile->get_sae() && ev->button == 1) {
374 // button 1 and shift-click: disables solo_latched for this click
375 if (!Config->get_solo_latched ()) {
376 Config->set_solo_latched (true);
377 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
378 Config->set_solo_latched (false);
381 _route->set_solo_safe (!_route->solo_safe(), this);
382 wait_for_release = false;
385 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
387 /* Primary-button1: solo mix group.
388 NOTE: Primary-button2 is MIDI learn.
391 if (ev->button == 1) {
392 set_mix_group_solo (_route, !_route->soloed());
397 /* click: solo this route */
398 if (wait_for_release) {
399 _route->set_solo (!_route->soloed(), this);
401 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
412 RouteUI::solo_release(GdkEventButton* ev)
414 if (!ignore_toggle) {
415 if (wait_for_release) {
416 wait_for_release = false;
417 if (multiple_solo_change) {
418 multiple_solo_change = false;
420 // because the press was the last undoable thing we did
423 // we don't use "undo the last op"
424 // here because its expensive for the GUI
425 _route->set_solo (!_route->soloed(), this);
434 RouteUI::rec_enable_press(GdkEventButton* ev)
436 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
440 if (!_session.engine().connected()) {
441 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
446 if (!ignore_toggle && is_track() && rec_enable_button) {
448 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
450 // do nothing on midi bind event
453 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
455 _session.begin_reversible_command (_("rec-enable change"));
456 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
458 if (rec_enable_button->get_active()) {
459 _session.record_disenable_all ();
461 _session.record_enable_all ();
465 _session.add_command(cmd);
466 _session.commit_reversible_command ();
468 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
470 /* Primary-button1 applies change to the mix group.
471 NOTE: Primary-button2 is MIDI learn.
474 set_mix_group_rec_enable (_route, !_route->record_enabled());
478 reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
486 RouteUI::rec_enable_release (GdkEventButton* ev)
492 RouteUI::solo_changed(void* src)
495 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
499 RouteUI::update_solo_display ()
502 vector<Gdk::Color> fg_colors;
505 if (solo_button->get_active() != (x = _route->soloed())){
506 ignore_toggle = true;
507 solo_button->set_active(x);
508 ignore_toggle = false;
511 if (_route->solo_safe()) {
512 solo_button->set_visual_state (2);
513 } else if (_route->soloed()) {
514 solo_button->set_visual_state (1);
516 solo_button->set_visual_state (0);
521 RouteUI::solo_changed_so_update_mute ()
523 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
527 RouteUI::mute_changed(void* src)
529 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
533 RouteUI::update_mute_display ()
535 bool model = _route->muted();
536 bool view = mute_button->get_active();
538 /* first make sure the button's "depressed" visual
543 ignore_toggle = true;
544 mute_button->set_active (model);
545 ignore_toggle = false;
548 /* now attend to visual state */
550 if (Config->get_show_solo_mutes()) {
551 if (_route->muted()) {
552 mute_button->set_visual_state (2);
553 } else if (!_route->soloed() && _route->solo_muted()) {
555 mute_button->set_visual_state (1);
557 mute_button->set_visual_state (0);
560 if (_route->muted()) {
561 mute_button->set_visual_state (2);
563 mute_button->set_visual_state (0);
570 RouteUI::route_rec_enable_changed ()
572 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
576 RouteUI::session_rec_enable_changed ()
578 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
582 RouteUI::update_rec_display ()
584 bool model = _route->record_enabled();
585 bool view = rec_enable_button->get_active();
587 /* first make sure the button's "depressed" visual
592 ignore_toggle = true;
593 rec_enable_button->set_active (model);
594 ignore_toggle = false;
597 /* now make sure its color state is correct */
601 switch (_session.record_status ()) {
602 case Session::Recording:
603 rec_enable_button->set_visual_state (1);
606 case Session::Disabled:
607 case Session::Enabled:
608 rec_enable_button->set_visual_state (2);
614 rec_enable_button->set_visual_state (0);
619 RouteUI::build_remote_control_menu ()
621 remote_control_menu = new Menu;
622 refresh_remote_control_menu ();
626 RouteUI::refresh_remote_control_menu ()
628 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
630 // only refresh the menu if it has been instantiated
632 if (remote_control_menu == 0) {
636 using namespace Menu_Helpers;
638 RadioMenuItem::Group rc_group;
639 CheckMenuItem* rc_active;
640 uint32_t limit = _session.ntracks() + _session.nbusses();
643 MenuList& rc_items = remote_control_menu->items();
646 /* note that this menu list starts at zero, not 1, because zero
647 is a valid, if useless, ID.
650 limit += 4; /* leave some breathing room */
652 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
653 if (_route->remote_control_id() == 0) {
654 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
655 rc_active->set_active ();
658 for (uint32_t i = 1; i < limit; ++i) {
659 snprintf (buf, sizeof (buf), "%u", i);
660 rc_items.push_back (RadioMenuElem (rc_group, buf));
661 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
662 if (_route->remote_control_id() == i) {
663 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
664 rc_active->set_active ();
666 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
671 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
673 /* this is called when the radio menu item is toggled, and so
674 is actually invoked twice per menu selection. we only
675 care about the invocation for the item that was being
679 if (item->get_active()) {
680 _route->set_remote_control_id (id);
685 RouteUI::build_solo_menu (void)
687 using namespace Menu_Helpers;
689 solo_menu = new Menu;
690 solo_menu->set_name ("ArdourContextMenu");
691 MenuList& items = solo_menu->items();
692 CheckMenuItem* check;
694 check = new CheckMenuItem(_("Solo-safe"));
695 check->set_active (_route->solo_safe());
696 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
697 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
698 items.push_back (CheckMenuElem(*check));
701 //items.push_back (SeparatorElem());
702 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
707 RouteUI::build_mute_menu(void)
709 using namespace Menu_Helpers;
711 mute_menu = new Menu;
712 mute_menu->set_name ("ArdourContextMenu");
713 MenuList& items = mute_menu->items();
714 CheckMenuItem* check;
716 check = new CheckMenuItem(_("Pre Fader"));
717 init_mute_menu(PRE_FADER, check);
718 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
719 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
720 items.push_back (CheckMenuElem(*check));
723 check = new CheckMenuItem(_("Post Fader"));
724 init_mute_menu(POST_FADER, check);
725 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
726 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
727 items.push_back (CheckMenuElem(*check));
730 check = new CheckMenuItem(_("Control Outs"));
731 init_mute_menu(CONTROL_OUTS, check);
732 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
733 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
734 items.push_back (CheckMenuElem(*check));
737 check = new CheckMenuItem(_("Main Outs"));
738 init_mute_menu(MAIN_OUTS, check);
739 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
740 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
741 items.push_back (CheckMenuElem(*check));
744 //items.push_back (SeparatorElem());
745 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
749 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
751 if (_route->get_mute_config (type)) {
752 check->set_active (true);
757 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
759 _route->set_mute_config(type, check->get_active(), this);
763 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
765 _route->set_solo_safe (check->get_active(), this);
769 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
771 RouteGroup* mix_group;
773 if((mix_group = route->mix_group()) != 0){
774 _session.begin_reversible_command (_("mix group solo change"));
775 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
776 mix_group->apply(&Route::set_solo, yn, this);
778 _session.add_command (cmd);
779 _session.commit_reversible_command ();
781 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
786 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
788 _session.begin_reversible_command (name);
789 XMLNode &before = _route->get_state();
790 bind(mem_fun(*_route, func), yn, arg)();
791 XMLNode &after = _route->get_state();
792 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
793 _session.commit_reversible_command ();
797 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
799 _session.begin_reversible_command (name);
800 XMLNode &before = audio_track()->get_state();
801 bind (mem_fun (*audio_track(), func), yn, arg)();
802 XMLNode &after = audio_track()->get_state();
803 _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), &before, &after));
804 _session.commit_reversible_command ();
808 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
810 RouteGroup* mix_group;
812 if((mix_group = route->mix_group()) != 0){
813 _session.begin_reversible_command (_("mix group mute change"));
814 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
815 mix_group->apply(&Route::set_mute, yn, this);
817 _session.add_command(cmd);
818 _session.commit_reversible_command ();
820 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
825 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
827 RouteGroup* mix_group;
829 if((mix_group = route->mix_group()) != 0){
830 _session.begin_reversible_command (_("mix group rec-enable change"));
831 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
832 mix_group->apply (&Route::set_record_enable, yn, this);
834 _session.add_command(cmd);
835 _session.commit_reversible_command ();
837 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
843 RouteUI::choose_color()
848 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
858 RouteUI::set_color (const Gdk::Color & c)
865 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
866 xml_node->add_property ("color", buf);
868 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
873 RouteUI::ensure_xml_node ()
876 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
877 xml_node = new XMLNode ("GUI");
878 _route->add_extra_xml (*xml_node);
884 RouteUI::get_child_xml_node (const string & childname)
891 if ((child = find_named_node (*xml_node, childname)) == 0) {
892 child = new XMLNode (childname);
893 xml_node->add_child_nocopy (*child);
900 RouteUI::set_color_from_route ()
904 RouteUI::ensure_xml_node ();
906 if ((prop = xml_node->property ("color")) != 0) {
908 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
918 RouteUI::remove_this_route ()
920 vector<string> choices;
924 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());
926 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
929 choices.push_back (_("No, do nothing."));
930 choices.push_back (_("Yes, remove it."));
932 Choice prompter (prompt, choices);
934 if (prompter.run () == 1) {
935 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
940 RouteUI::idle_remove_this_route (RouteUI *rui)
942 rui->_session.remove_route (rui->_route);
947 RouteUI::route_rename ()
949 ArdourPrompter name_prompter (true);
951 name_prompter.set_prompt (_("New Name: "));
952 name_prompter.set_initial_text (_route->name());
953 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
954 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
955 name_prompter.show_all ();
957 switch (name_prompter.run ()) {
959 case Gtk::RESPONSE_ACCEPT:
960 name_prompter.get_result (result);
961 if (result.length()) {
962 _route->set_name (result, this);
972 RouteUI::name_changed (void *src)
974 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
976 name_label.set_text (_route->name());
980 RouteUI::toggle_route_active ()
984 if (route_active_menu_item) {
985 if (route_active_menu_item->get_active() != (yn = _route->active())) {
986 _route->set_active (!yn);
992 RouteUI::route_active_changed ()
994 if (route_active_menu_item) {
995 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1000 RouteUI::toggle_polarity ()
1002 if (polarity_menu_item) {
1006 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1008 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1009 _route->set_phase_invert (x, this);
1011 name_label.set_text (X_("Ø ") + name_label.get_text());
1013 name_label.set_text (_route->name());
1020 RouteUI::polarity_changed ()
1022 /* no signal for this yet */
1026 RouteUI::toggle_denormal_protection ()
1028 if (denormal_menu_item) {
1032 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1034 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1035 _route->set_denormal_protection (x, this);
1041 RouteUI::denormal_protection_changed ()
1043 /* no signal for this yet */
1048 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1050 bool yn = _route->solo_safe ();
1052 if (check->get_active() != yn) {
1053 check->set_active (yn);
1057 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1059 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1061 bool yn = _route->get_mute_config(PRE_FADER);
1062 if (check->get_active() != yn) {
1063 check->set_active (yn);
1068 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1070 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1072 bool yn = _route->get_mute_config(POST_FADER);
1073 if (check->get_active() != yn) {
1074 check->set_active (yn);
1079 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1081 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1083 bool yn = _route->get_mute_config(CONTROL_OUTS);
1084 if (check->get_active() != yn) {
1085 check->set_active (yn);
1090 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1092 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1094 bool yn = _route->get_mute_config(MAIN_OUTS);
1095 if (check->get_active() != yn) {
1096 check->set_active (yn);
1101 RouteUI::disconnect_input ()
1103 _route->disconnect_inputs (this);
1107 RouteUI::disconnect_output ()
1109 _route->disconnect_outputs (this);
1113 RouteUI::is_track () const
1115 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1118 boost::shared_ptr<Track>
1119 RouteUI::track() const
1121 return boost::dynamic_pointer_cast<Track>(_route);
1125 RouteUI::is_audio_track () const
1127 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1130 boost::shared_ptr<AudioTrack>
1131 RouteUI::audio_track() const
1133 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1136 boost::shared_ptr<Diskstream>
1137 RouteUI::get_diskstream () const
1139 boost::shared_ptr<Track> t;
1141 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1142 return t->diskstream();
1144 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1149 RouteUI::name() const
1151 return _route->name();
1155 RouteUI::map_frozen ()
1157 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1159 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1162 switch (at->freeze_state()) {
1163 case AudioTrack::Frozen:
1164 rec_enable_button->set_sensitive (false);
1167 rec_enable_button->set_sensitive (true);