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>
26 #include <gtkmm2ext/prompter.h>
28 #include <ardour/route_group.h>
29 #include <pbd/memento_command.h>
30 #include <pbd/stacktrace.h>
31 #include <pbd/shiva.h>
37 #include "gui_thread.h"
39 #include <ardour/route.h>
40 #include <ardour/session.h>
41 #include <ardour/audioengine.h>
42 #include <ardour/audio_track.h>
43 #include <ardour/audio_diskstream.h>
44 #include <ardour/profile.h>
45 #include <ardour/utils.h>
50 using namespace Gtkmm2ext;
51 using namespace ARDOUR;
54 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
58 set_button_names (mute_name, solo_name, rec_name);
61 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
62 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
66 set_button_names (mute_name, solo_name, rec_name);
77 remote_control_menu = 0;
78 ignore_toggle = false;
79 wait_for_release = false;
80 route_active_menu_item = 0;
81 was_solo_safe = false;
82 polarity_menu_item = 0;
83 denormal_menu_item = 0;
84 multiple_mute_change = false;
85 multiple_solo_change = false;
87 mute_button = manage (new BindableToggleButton (0, ""));
88 mute_button->set_self_managed (true);
89 mute_button->set_name ("MuteButton");
90 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
92 solo_button = manage (new BindableToggleButton (0, ""));
93 solo_button->set_self_managed (true);
94 solo_button->set_name ("SoloButton");
95 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
97 rec_enable_button = manage (new BindableToggleButton (0, ""));
98 rec_enable_button->set_name ("RecordEnableButton");
99 rec_enable_button->set_self_managed (true);
100 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
102 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
108 connections.clear ();
121 /* do not delete the node - its owned by the route */
125 route_active_menu_item = 0;
126 polarity_menu_item = 0;
127 denormal_menu_item = 0;
131 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
139 RouteUI::set_route (boost::shared_ptr<Route> rp)
145 if (set_color_from_route()) {
146 set_color (unique_random_color());
149 /* no, there is no memory leak here. This object cleans itself (and other stuff)
150 up when the route is destroyed.
154 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 /* derived classes should emit GoingAway so that they receive the signal
196 when the object is still a legal derived instance.
207 /* Note: the remote control menu is constructed
208 by derived classes (e.g. MixerStrip or RouteTimeAxis) and
209 is always attached to a context menu. It then becomes
210 owned by that menu, and will deleted along with it. We
211 do not need to take care of it here.
216 RouteUI::mute_press(GdkEventButton* ev)
218 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
221 multiple_mute_change = false;
222 if (!ignore_toggle) {
224 if (Keyboard::is_context_menu_event (ev)) {
230 mute_menu->popup(0,ev->time);
234 if (Keyboard::is_button2_event (ev)) {
235 // Primary-button2 click is the midi binding click
236 // button2-click is "momentary"
238 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
239 wait_for_release = true;
245 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
247 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
249 /* Primary-Tertiary-click applies change to all routes */
251 _session.begin_reversible_command (_("mute change"));
252 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
253 _session.set_all_mute (!_route->muted());
255 _session.add_command(cmd);
256 _session.commit_reversible_command ();
257 multiple_mute_change = true;
259 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
261 /* Primary-button1 applies change to the mix group.
262 NOTE: Primary-button2 is MIDI learn.
265 if (ev->button == 1) {
266 set_mix_group_mute (_route, !_route->muted());
271 /* plain click applies change to this route */
272 if (wait_for_release) {
273 _route->set_mute (!_route->muted(), this);
275 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
287 RouteUI::mute_release(GdkEventButton* ev)
289 if (!ignore_toggle) {
290 if (wait_for_release){
291 wait_for_release = false;
292 if (multiple_mute_change) {
293 multiple_mute_change = false;
295 // because the press was the last undoable thing we did
298 _route->set_mute (!_route->muted(), this);
306 RouteUI::solo_press(GdkEventButton* ev)
308 /* ignore double/triple clicks */
310 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
313 multiple_solo_change = false;
314 if (!ignore_toggle) {
316 if (Keyboard::is_context_menu_event (ev)) {
318 if (solo_menu == 0) {
322 solo_menu->popup (1, ev->time);
326 if (Keyboard::is_button2_event (ev)) {
328 // Primary-button2 click is the midi binding click
329 // button2-click is "momentary"
331 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
332 wait_for_release = true;
338 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
340 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
342 /* Primary-Tertiary-click applies change to all routes */
343 bool was_not_latched = false;
344 if (!Config->get_solo_latched ()) {
345 was_not_latched = true;
347 XXX it makes no sense to solo all tracks if we're
348 not in latched mode, but doing nothing feels like a bug,
351 Config->set_solo_latched (true);
353 _session.begin_reversible_command (_("solo change"));
354 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
355 _session.set_all_solo (!_route->soloed());
357 _session.add_command (cmd);
358 _session.commit_reversible_command ();
359 multiple_solo_change = true;
360 if (was_not_latched) {
361 Config->set_solo_latched (false);
364 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
366 // Primary-Secondary-click: exclusively solo this track, not a toggle */
368 _session.begin_reversible_command (_("solo change"));
369 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
370 _session.set_all_solo (false);
371 _route->set_solo (true, this);
373 _session.add_command(cmd);
374 _session.commit_reversible_command ();
376 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
378 // shift-click: set this route to solo safe
380 if (Profile->get_sae() && ev->button == 1) {
381 // button 1 and shift-click: disables solo_latched for this click
382 if (!Config->get_solo_latched ()) {
383 Config->set_solo_latched (true);
384 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
385 Config->set_solo_latched (false);
388 _route->set_solo_safe (!_route->solo_safe(), this);
389 wait_for_release = false;
392 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
394 /* Primary-button1: solo mix group.
395 NOTE: Primary-button2 is MIDI learn.
398 if (ev->button == 1) {
399 set_mix_group_solo (_route, !_route->soloed());
404 /* click: solo this route */
405 if (wait_for_release) {
406 _route->set_solo (!_route->soloed(), this);
408 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
419 RouteUI::solo_release(GdkEventButton* ev)
421 if (!ignore_toggle) {
422 if (wait_for_release) {
423 wait_for_release = false;
424 if (multiple_solo_change) {
425 multiple_solo_change = false;
427 // because the press was the last undoable thing we did
430 // we don't use "undo the last op"
431 // here because its expensive for the GUI
432 _route->set_solo (!_route->soloed(), this);
441 RouteUI::rec_enable_press(GdkEventButton* ev)
443 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
447 if (!_session.engine().connected()) {
448 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
453 if (!ignore_toggle && is_track() && rec_enable_button) {
455 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
457 // do nothing on midi bind event
460 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
462 _session.begin_reversible_command (_("rec-enable change"));
463 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
465 if (rec_enable_button->get_active()) {
466 _session.record_disenable_all ();
468 _session.record_enable_all ();
472 _session.add_command(cmd);
473 _session.commit_reversible_command ();
475 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
477 /* Primary-button1 applies change to the mix group.
478 NOTE: Primary-button2 is MIDI learn.
481 set_mix_group_rec_enable (_route, !_route->record_enabled());
485 reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
493 RouteUI::rec_enable_release (GdkEventButton* ev)
499 RouteUI::solo_changed(void* src)
502 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
506 RouteUI::update_solo_display ()
509 vector<Gdk::Color> fg_colors;
512 if (solo_button->get_active() != (x = _route->soloed())){
513 ignore_toggle = true;
514 solo_button->set_active(x);
515 ignore_toggle = false;
518 if (_route->solo_safe()) {
519 solo_button->set_visual_state (2);
520 } else if (_route->soloed()) {
521 solo_button->set_visual_state (1);
523 solo_button->set_visual_state (0);
528 RouteUI::solo_changed_so_update_mute ()
530 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
534 RouteUI::mute_changed(void* src)
536 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
540 RouteUI::update_mute_display ()
542 bool model = _route->muted();
543 bool view = mute_button->get_active();
545 /* first make sure the button's "depressed" visual
550 ignore_toggle = true;
551 mute_button->set_active (model);
552 ignore_toggle = false;
555 /* now attend to visual state */
557 if (Config->get_show_solo_mutes()) {
558 if (_route->muted()) {
559 mute_button->set_visual_state (2);
560 } else if (!_route->soloed() && _route->solo_muted()) {
562 mute_button->set_visual_state (1);
564 mute_button->set_visual_state (0);
567 if (_route->muted()) {
568 mute_button->set_visual_state (2);
570 mute_button->set_visual_state (0);
577 RouteUI::route_rec_enable_changed ()
579 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
583 RouteUI::session_rec_enable_changed ()
585 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
589 RouteUI::update_rec_display ()
591 bool model = _route->record_enabled();
592 bool view = rec_enable_button->get_active();
594 /* first make sure the button's "depressed" visual
599 ignore_toggle = true;
600 rec_enable_button->set_active (model);
601 ignore_toggle = false;
604 /* now make sure its color state is correct */
608 switch (_session.record_status ()) {
609 case Session::Recording:
610 rec_enable_button->set_visual_state (1);
613 case Session::Disabled:
614 case Session::Enabled:
615 rec_enable_button->set_visual_state (2);
621 rec_enable_button->set_visual_state (0);
626 RouteUI::build_remote_control_menu ()
628 remote_control_menu = new Menu;
629 refresh_remote_control_menu ();
633 RouteUI::refresh_remote_control_menu ()
635 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
637 // only refresh the menu if it has been instantiated
639 if (remote_control_menu == 0) {
643 using namespace Menu_Helpers;
645 RadioMenuItem::Group rc_group;
646 CheckMenuItem* rc_active;
647 uint32_t limit = _session.ntracks() + _session.nbusses();
650 MenuList& rc_items = remote_control_menu->items();
653 /* note that this menu list starts at zero, not 1, because zero
654 is a valid, if useless, ID.
657 limit += 4; /* leave some breathing room */
659 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
660 if (_route->remote_control_id() == 0) {
661 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
662 rc_active->set_active ();
665 for (uint32_t i = 1; i < limit; ++i) {
666 snprintf (buf, sizeof (buf), "%u", i);
667 rc_items.push_back (RadioMenuElem (rc_group, buf));
668 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
669 if (_route->remote_control_id() == i) {
670 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
671 rc_active->set_active ();
673 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
678 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
680 /* this is called when the radio menu item is toggled, and so
681 is actually invoked twice per menu selection. we only
682 care about the invocation for the item that was being
686 if (item->get_active()) {
687 _route->set_remote_control_id (id);
692 RouteUI::build_solo_menu (void)
694 using namespace Menu_Helpers;
696 solo_menu = new Menu;
697 solo_menu->set_name ("ArdourContextMenu");
698 MenuList& items = solo_menu->items();
699 CheckMenuItem* check;
701 check = new CheckMenuItem(_("Solo Locke "));
702 check->set_active (_route->solo_safe());
703 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
704 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
705 items.push_back (CheckMenuElem(*check));
708 //items.push_back (SeparatorElem());
709 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
714 RouteUI::build_mute_menu(void)
716 using namespace Menu_Helpers;
718 mute_menu = new Menu;
719 mute_menu->set_name ("ArdourContextMenu");
720 MenuList& items = mute_menu->items();
721 CheckMenuItem* check;
723 check = new CheckMenuItem(_("Pre Fader"));
724 init_mute_menu(PRE_FADER, check);
725 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
726 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
727 items.push_back (CheckMenuElem(*check));
730 check = new CheckMenuItem(_("Post Fader"));
731 init_mute_menu(POST_FADER, check);
732 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
733 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
734 items.push_back (CheckMenuElem(*check));
737 check = new CheckMenuItem(_("Control Outs"));
738 init_mute_menu(CONTROL_OUTS, check);
739 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
740 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
741 items.push_back (CheckMenuElem(*check));
744 check = new CheckMenuItem(_("Main Outs"));
745 init_mute_menu(MAIN_OUTS, check);
746 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
747 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
748 items.push_back (CheckMenuElem(*check));
751 //items.push_back (SeparatorElem());
752 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
756 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
758 if (_route->get_mute_config (type)) {
759 check->set_active (true);
764 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
766 _route->set_mute_config(type, check->get_active(), this);
770 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
772 _route->set_solo_safe (check->get_active(), this);
776 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
778 RouteGroup* mix_group;
780 if((mix_group = route->mix_group()) != 0){
781 _session.begin_reversible_command (_("mix group solo change"));
782 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
783 mix_group->apply(&Route::set_solo, yn, this);
785 _session.add_command (cmd);
786 _session.commit_reversible_command ();
788 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
793 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
795 _session.begin_reversible_command (name);
796 XMLNode &before = _route->get_state();
797 bind(mem_fun(*_route, func), yn, arg)();
798 XMLNode &after = _route->get_state();
799 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
800 _session.commit_reversible_command ();
804 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
806 _session.begin_reversible_command (name);
807 XMLNode &before = audio_track()->get_state();
808 bind (mem_fun (*audio_track(), func), yn, arg)();
809 XMLNode &after = audio_track()->get_state();
810 _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), &before, &after));
811 _session.commit_reversible_command ();
815 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
817 RouteGroup* mix_group;
819 if((mix_group = route->mix_group()) != 0){
820 _session.begin_reversible_command (_("mix group mute change"));
821 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
822 mix_group->apply(&Route::set_mute, yn, this);
824 _session.add_command(cmd);
825 _session.commit_reversible_command ();
827 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
832 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
834 RouteGroup* mix_group;
836 if((mix_group = route->mix_group()) != 0){
837 _session.begin_reversible_command (_("mix group rec-enable change"));
838 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
839 mix_group->apply (&Route::set_record_enable, yn, this);
841 _session.add_command(cmd);
842 _session.commit_reversible_command ();
844 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
850 RouteUI::choose_color()
855 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
865 RouteUI::set_color (const Gdk::Color & c)
872 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
873 xml_node->add_property ("color", buf);
875 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
880 RouteUI::ensure_xml_node ()
883 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
884 xml_node = new XMLNode ("GUI");
885 _route->add_extra_xml (*xml_node);
891 RouteUI::get_child_xml_node (const string & childname)
898 if ((child = find_named_node (*xml_node, childname)) == 0) {
899 child = new XMLNode (childname);
900 xml_node->add_child_nocopy (*child);
907 RouteUI::set_color_from_route ()
911 RouteUI::ensure_xml_node ();
913 if ((prop = xml_node->property ("color")) != 0) {
915 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
925 RouteUI::remove_this_route ()
927 vector<string> choices;
931 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());
933 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
936 choices.push_back (_("No, do nothing."));
937 choices.push_back (_("Yes, remove it."));
939 Choice prompter (prompt, choices);
941 if (prompter.run () == 1) {
942 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
947 RouteUI::idle_remove_this_route (RouteUI *rui)
949 rui->_session.remove_route (rui->_route);
954 RouteUI::route_rename ()
956 ArdourPrompter name_prompter (true);
958 name_prompter.set_prompt (_("New Name: "));
959 name_prompter.set_initial_text (_route->name());
960 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
961 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
962 name_prompter.show_all ();
964 switch (name_prompter.run ()) {
966 case Gtk::RESPONSE_ACCEPT:
967 name_prompter.get_result (result);
968 if (result.length()) {
969 _route->set_name (result, this);
979 RouteUI::name_changed (void *src)
981 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
983 name_label.set_text (_route->name());
987 RouteUI::toggle_route_active ()
991 if (route_active_menu_item) {
992 if (route_active_menu_item->get_active() != (yn = _route->active())) {
993 _route->set_active (!yn);
999 RouteUI::route_active_changed ()
1001 if (route_active_menu_item) {
1002 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1007 RouteUI::toggle_polarity ()
1009 if (polarity_menu_item) {
1013 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1015 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1016 _route->set_phase_invert (x, this);
1018 name_label.set_text (X_("Ø ") + name_label.get_text());
1020 name_label.set_text (_route->name());
1027 RouteUI::polarity_changed ()
1029 /* no signal for this yet */
1033 RouteUI::toggle_denormal_protection ()
1035 if (denormal_menu_item) {
1039 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1041 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1042 _route->set_denormal_protection (x, this);
1048 RouteUI::denormal_protection_changed ()
1050 /* no signal for this yet */
1055 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1057 bool yn = _route->solo_safe ();
1059 if (check->get_active() != yn) {
1060 check->set_active (yn);
1064 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1066 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1068 bool yn = _route->get_mute_config(PRE_FADER);
1069 if (check->get_active() != yn) {
1070 check->set_active (yn);
1075 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1077 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1079 bool yn = _route->get_mute_config(POST_FADER);
1080 if (check->get_active() != yn) {
1081 check->set_active (yn);
1086 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1088 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1090 bool yn = _route->get_mute_config(CONTROL_OUTS);
1091 if (check->get_active() != yn) {
1092 check->set_active (yn);
1097 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1099 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1101 bool yn = _route->get_mute_config(MAIN_OUTS);
1102 if (check->get_active() != yn) {
1103 check->set_active (yn);
1108 RouteUI::disconnect_input ()
1110 _route->disconnect_inputs (this);
1114 RouteUI::disconnect_output ()
1116 _route->disconnect_outputs (this);
1120 RouteUI::is_track () const
1122 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1125 boost::shared_ptr<Track>
1126 RouteUI::track() const
1128 return boost::dynamic_pointer_cast<Track>(_route);
1132 RouteUI::is_audio_track () const
1134 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1137 boost::shared_ptr<AudioTrack>
1138 RouteUI::audio_track() const
1140 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1143 boost::shared_ptr<Diskstream>
1144 RouteUI::get_diskstream () const
1146 boost::shared_ptr<Track> t;
1148 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1149 return t->diskstream();
1151 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1156 RouteUI::name() const
1158 return _route->name();
1162 RouteUI::map_frozen ()
1164 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1166 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1169 switch (at->freeze_state()) {
1170 case AudioTrack::Frozen:
1171 rec_enable_button->set_sensitive (false);
1174 rec_enable_button->set_sensitive (true);
1181 RouteUI::save_as_template ()
1184 Glib::ustring safe_name;
1187 path = Session::route_template_dir();
1189 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1190 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1194 Prompter p (true); // modal
1196 p.set_prompt (_("Template name:"));
1198 case RESPONSE_ACCEPT:
1205 p.get_result (name, true);
1207 safe_name = legalize_for_path (name);
1208 safe_name += Session::template_suffix ();
1210 path = Glib::build_filename (path, safe_name);
1212 _route->save_as_template (path, name);