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);
76 remote_control_menu = 0;
77 ignore_toggle = false;
78 wait_for_release = false;
79 route_active_menu_item = 0;
80 was_solo_safe = false;
81 polarity_menu_item = 0;
82 denormal_menu_item = 0;
83 multiple_mute_change = false;
84 multiple_solo_change = false;
86 mute_button = manage (new BindableToggleButton (0, ""));
87 mute_button->set_self_managed (true);
88 mute_button->set_name ("MuteButton");
89 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
91 solo_button = manage (new BindableToggleButton (0, ""));
92 solo_button->set_self_managed (true);
93 solo_button->set_name ("SoloButton");
94 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
96 rec_enable_button = manage (new BindableToggleButton (0, ""));
97 rec_enable_button->set_name ("RecordEnableButton");
98 rec_enable_button->set_self_managed (true);
99 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
101 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
107 connections.clear ();
120 /* do not delete the node - its owned by the route */
124 route_active_menu_item = 0;
125 polarity_menu_item = 0;
126 denormal_menu_item = 0;
130 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
138 RouteUI::set_route (boost::shared_ptr<Route> rp)
144 if (set_color_from_route()) {
145 set_color (unique_random_color());
148 /* no, there is no memory leak here. This object cleans itself (and other stuff)
149 up when the route is destroyed.
152 new PairedShiva<Route,RouteUI> (*_route, *this);
154 mute_button->set_controllable (&_route->mute_control());
155 mute_button->set_label (m_name);
157 solo_button->set_controllable (&_route->solo_control());
158 solo_button->set_label (s_name);
160 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
161 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
162 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
163 connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
165 /* when solo changes, update mute state too, in case the user wants us to display it */
167 update_solo_display ();
168 update_mute_display ();
171 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
173 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
175 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
177 rec_enable_button->set_controllable (&t->rec_enable_control());
178 rec_enable_button->set_label (r_name);
180 update_rec_display ();
183 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
185 /* map the current state */
192 GoingAway (); /* EMIT SIGNAL */
202 /* Note: the remote control menu is constructed
203 by derived classes (e.g. MixerStrip or RouteTimeAxis) and
204 is always attached to a context menu. It then becomes
205 owned by that menu, and will deleted along with it. We
206 do not need to take care of it here.
211 RouteUI::mute_press(GdkEventButton* ev)
213 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
216 multiple_mute_change = false;
217 if (!ignore_toggle) {
219 if (Keyboard::is_context_menu_event (ev)) {
225 mute_menu->popup(0,ev->time);
229 if (Keyboard::is_button2_event (ev)) {
230 // Primary-button2 click is the midi binding click
231 // button2-click is "momentary"
233 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
234 wait_for_release = true;
240 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
242 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
244 /* Primary-Tertiary-click applies change to all routes */
246 _session.begin_reversible_command (_("mute change"));
247 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
248 _session.set_all_mute (!_route->muted());
250 _session.add_command(cmd);
251 _session.commit_reversible_command ();
252 multiple_mute_change = true;
254 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
256 /* Primary-button1 applies change to the mix group.
257 NOTE: Primary-button2 is MIDI learn.
260 if (ev->button == 1) {
261 set_mix_group_mute (_route, !_route->muted());
266 /* plain click applies change to this route */
267 if (wait_for_release) {
268 _route->set_mute (!_route->muted(), this);
270 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
282 RouteUI::mute_release(GdkEventButton* ev)
284 if (!ignore_toggle) {
285 if (wait_for_release){
286 wait_for_release = false;
287 if (multiple_mute_change) {
288 multiple_mute_change = false;
290 // because the press was the last undoable thing we did
293 _route->set_mute (!_route->muted(), this);
301 RouteUI::solo_press(GdkEventButton* ev)
303 /* ignore double/triple clicks */
305 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
308 multiple_solo_change = false;
309 if (!ignore_toggle) {
311 if (Keyboard::is_context_menu_event (ev)) {
313 if (solo_menu == 0) {
317 solo_menu->popup (1, ev->time);
321 if (Keyboard::is_button2_event (ev)) {
323 // Primary-button2 click is the midi binding click
324 // button2-click is "momentary"
326 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
327 wait_for_release = true;
333 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
335 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
337 /* Primary-Tertiary-click applies change to all routes */
338 bool was_not_latched = false;
339 if (!Config->get_solo_latched ()) {
340 was_not_latched = true;
342 XXX it makes no sense to solo all tracks if we're
343 not in latched mode, but doing nothing feels like a bug,
346 Config->set_solo_latched (true);
348 _session.begin_reversible_command (_("solo change"));
349 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
350 _session.set_all_solo (!_route->soloed());
352 _session.add_command (cmd);
353 _session.commit_reversible_command ();
354 multiple_solo_change = true;
355 if (was_not_latched) {
356 Config->set_solo_latched (false);
359 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
361 // Primary-Secondary-click: exclusively solo this track, not a toggle */
363 _session.begin_reversible_command (_("solo change"));
364 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
365 _session.set_all_solo (false);
366 _route->set_solo (true, this);
368 _session.add_command(cmd);
369 _session.commit_reversible_command ();
371 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
373 // shift-click: set this route to solo safe
375 if (Profile->get_sae() && ev->button == 1) {
376 // button 1 and shift-click: disables solo_latched for this click
377 if (!Config->get_solo_latched ()) {
378 Config->set_solo_latched (true);
379 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
380 Config->set_solo_latched (false);
383 _route->set_solo_safe (!_route->solo_safe(), this);
384 wait_for_release = false;
387 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
389 /* Primary-button1: solo mix group.
390 NOTE: Primary-button2 is MIDI learn.
393 if (ev->button == 1) {
394 set_mix_group_solo (_route, !_route->soloed());
399 /* click: solo this route */
400 if (wait_for_release) {
401 _route->set_solo (!_route->soloed(), this);
403 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
414 RouteUI::solo_release(GdkEventButton* ev)
416 if (!ignore_toggle) {
417 if (wait_for_release) {
418 wait_for_release = false;
419 if (multiple_solo_change) {
420 multiple_solo_change = false;
422 // because the press was the last undoable thing we did
425 // we don't use "undo the last op"
426 // here because its expensive for the GUI
427 _route->set_solo (!_route->soloed(), this);
436 RouteUI::rec_enable_press(GdkEventButton* ev)
438 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
442 if (!_session.engine().connected()) {
443 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
448 if (!ignore_toggle && is_track() && rec_enable_button) {
450 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
452 // do nothing on midi bind event
455 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
457 _session.begin_reversible_command (_("rec-enable change"));
458 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
460 if (rec_enable_button->get_active()) {
461 _session.record_disenable_all ();
463 _session.record_enable_all ();
467 _session.add_command(cmd);
468 _session.commit_reversible_command ();
470 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
472 /* Primary-button1 applies change to the mix group.
473 NOTE: Primary-button2 is MIDI learn.
476 set_mix_group_rec_enable (_route, !_route->record_enabled());
480 reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
488 RouteUI::rec_enable_release (GdkEventButton* ev)
494 RouteUI::solo_changed(void* src)
497 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
501 RouteUI::update_solo_display ()
504 vector<Gdk::Color> fg_colors;
507 if (solo_button->get_active() != (x = _route->soloed())){
508 ignore_toggle = true;
509 solo_button->set_active(x);
510 ignore_toggle = false;
513 if (_route->solo_safe()) {
514 solo_button->set_visual_state (2);
515 } else if (_route->soloed()) {
516 solo_button->set_visual_state (1);
518 solo_button->set_visual_state (0);
523 RouteUI::solo_changed_so_update_mute ()
525 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
529 RouteUI::mute_changed(void* src)
531 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
535 RouteUI::update_mute_display ()
537 bool model = _route->muted();
538 bool view = mute_button->get_active();
540 /* first make sure the button's "depressed" visual
545 ignore_toggle = true;
546 mute_button->set_active (model);
547 ignore_toggle = false;
550 /* now attend to visual state */
552 if (Config->get_show_solo_mutes()) {
553 if (_route->muted()) {
554 mute_button->set_visual_state (2);
555 } else if (!_route->soloed() && _route->solo_muted()) {
557 mute_button->set_visual_state (1);
559 mute_button->set_visual_state (0);
562 if (_route->muted()) {
563 mute_button->set_visual_state (2);
565 mute_button->set_visual_state (0);
572 RouteUI::route_rec_enable_changed ()
574 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
578 RouteUI::session_rec_enable_changed ()
580 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
584 RouteUI::update_rec_display ()
586 bool model = _route->record_enabled();
587 bool view = rec_enable_button->get_active();
589 /* first make sure the button's "depressed" visual
594 ignore_toggle = true;
595 rec_enable_button->set_active (model);
596 ignore_toggle = false;
599 /* now make sure its color state is correct */
603 switch (_session.record_status ()) {
604 case Session::Recording:
605 rec_enable_button->set_visual_state (1);
608 case Session::Disabled:
609 case Session::Enabled:
610 rec_enable_button->set_visual_state (2);
616 rec_enable_button->set_visual_state (0);
621 RouteUI::build_remote_control_menu ()
623 remote_control_menu = new Menu;
624 refresh_remote_control_menu ();
628 RouteUI::refresh_remote_control_menu ()
630 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
632 // only refresh the menu if it has been instantiated
634 if (remote_control_menu == 0) {
638 using namespace Menu_Helpers;
640 RadioMenuItem::Group rc_group;
641 CheckMenuItem* rc_active;
642 uint32_t limit = _session.ntracks() + _session.nbusses();
645 MenuList& rc_items = remote_control_menu->items();
648 /* note that this menu list starts at zero, not 1, because zero
649 is a valid, if useless, ID.
652 limit += 4; /* leave some breathing room */
654 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
655 if (_route->remote_control_id() == 0) {
656 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
657 rc_active->set_active ();
660 for (uint32_t i = 1; i < limit; ++i) {
661 snprintf (buf, sizeof (buf), "%u", i);
662 rc_items.push_back (RadioMenuElem (rc_group, buf));
663 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
664 if (_route->remote_control_id() == i) {
665 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
666 rc_active->set_active ();
668 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
673 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
675 /* this is called when the radio menu item is toggled, and so
676 is actually invoked twice per menu selection. we only
677 care about the invocation for the item that was being
681 if (item->get_active()) {
682 _route->set_remote_control_id (id);
687 RouteUI::build_solo_menu (void)
689 using namespace Menu_Helpers;
691 solo_menu = new Menu;
692 solo_menu->set_name ("ArdourContextMenu");
693 MenuList& items = solo_menu->items();
694 CheckMenuItem* check;
696 check = new CheckMenuItem(_("Solo-safe"));
697 check->set_active (_route->solo_safe());
698 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
699 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
700 items.push_back (CheckMenuElem(*check));
703 //items.push_back (SeparatorElem());
704 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
709 RouteUI::build_mute_menu(void)
711 using namespace Menu_Helpers;
713 mute_menu = new Menu;
714 mute_menu->set_name ("ArdourContextMenu");
715 MenuList& items = mute_menu->items();
716 CheckMenuItem* check;
718 check = new CheckMenuItem(_("Pre Fader"));
719 init_mute_menu(PRE_FADER, check);
720 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
721 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
722 items.push_back (CheckMenuElem(*check));
725 check = new CheckMenuItem(_("Post Fader"));
726 init_mute_menu(POST_FADER, check);
727 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
728 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
729 items.push_back (CheckMenuElem(*check));
732 check = new CheckMenuItem(_("Control Outs"));
733 init_mute_menu(CONTROL_OUTS, check);
734 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
735 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
736 items.push_back (CheckMenuElem(*check));
739 check = new CheckMenuItem(_("Main Outs"));
740 init_mute_menu(MAIN_OUTS, check);
741 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
742 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
743 items.push_back (CheckMenuElem(*check));
746 //items.push_back (SeparatorElem());
747 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
751 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
753 if (_route->get_mute_config (type)) {
754 check->set_active (true);
759 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
761 _route->set_mute_config(type, check->get_active(), this);
765 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
767 _route->set_solo_safe (check->get_active(), this);
771 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
773 RouteGroup* mix_group;
775 if((mix_group = route->mix_group()) != 0){
776 _session.begin_reversible_command (_("mix group solo change"));
777 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
778 mix_group->apply(&Route::set_solo, yn, this);
780 _session.add_command (cmd);
781 _session.commit_reversible_command ();
783 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
788 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
790 _session.begin_reversible_command (name);
791 XMLNode &before = _route->get_state();
792 bind(mem_fun(*_route, func), yn, arg)();
793 XMLNode &after = _route->get_state();
794 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
795 _session.commit_reversible_command ();
799 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
801 _session.begin_reversible_command (name);
802 XMLNode &before = audio_track()->get_state();
803 bind (mem_fun (*audio_track(), func), yn, arg)();
804 XMLNode &after = audio_track()->get_state();
805 _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), &before, &after));
806 _session.commit_reversible_command ();
810 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
812 RouteGroup* mix_group;
814 if((mix_group = route->mix_group()) != 0){
815 _session.begin_reversible_command (_("mix group mute change"));
816 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
817 mix_group->apply(&Route::set_mute, yn, this);
819 _session.add_command(cmd);
820 _session.commit_reversible_command ();
822 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
827 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
829 RouteGroup* mix_group;
831 if((mix_group = route->mix_group()) != 0){
832 _session.begin_reversible_command (_("mix group rec-enable change"));
833 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
834 mix_group->apply (&Route::set_record_enable, yn, this);
836 _session.add_command(cmd);
837 _session.commit_reversible_command ();
839 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
845 RouteUI::choose_color()
850 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
860 RouteUI::set_color (const Gdk::Color & c)
867 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
868 xml_node->add_property ("color", buf);
870 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
875 RouteUI::ensure_xml_node ()
878 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
879 xml_node = new XMLNode ("GUI");
880 _route->add_extra_xml (*xml_node);
886 RouteUI::get_child_xml_node (const string & childname)
893 if ((child = find_named_node (*xml_node, childname)) == 0) {
894 child = new XMLNode (childname);
895 xml_node->add_child_nocopy (*child);
902 RouteUI::set_color_from_route ()
906 RouteUI::ensure_xml_node ();
908 if ((prop = xml_node->property ("color")) != 0) {
910 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
920 RouteUI::remove_this_route ()
922 vector<string> choices;
926 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());
928 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
931 choices.push_back (_("No, do nothing."));
932 choices.push_back (_("Yes, remove it."));
934 Choice prompter (prompt, choices);
936 if (prompter.run () == 1) {
937 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
942 RouteUI::idle_remove_this_route (RouteUI *rui)
944 rui->_session.remove_route (rui->_route);
949 RouteUI::route_rename ()
951 ArdourPrompter name_prompter (true);
953 name_prompter.set_prompt (_("New Name: "));
954 name_prompter.set_initial_text (_route->name());
955 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
956 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
957 name_prompter.show_all ();
959 switch (name_prompter.run ()) {
961 case Gtk::RESPONSE_ACCEPT:
962 name_prompter.get_result (result);
963 if (result.length()) {
964 _route->set_name (result, this);
974 RouteUI::name_changed (void *src)
976 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
978 name_label.set_text (_route->name());
982 RouteUI::toggle_route_active ()
986 if (route_active_menu_item) {
987 if (route_active_menu_item->get_active() != (yn = _route->active())) {
988 _route->set_active (!yn);
994 RouteUI::route_active_changed ()
996 if (route_active_menu_item) {
997 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1002 RouteUI::toggle_polarity ()
1004 if (polarity_menu_item) {
1008 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1010 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1011 _route->set_phase_invert (x, this);
1013 name_label.set_text (X_("Ø ") + name_label.get_text());
1015 name_label.set_text (_route->name());
1022 RouteUI::polarity_changed ()
1024 /* no signal for this yet */
1028 RouteUI::toggle_denormal_protection ()
1030 if (denormal_menu_item) {
1034 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1036 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1037 _route->set_denormal_protection (x, this);
1043 RouteUI::denormal_protection_changed ()
1045 /* no signal for this yet */
1050 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1052 bool yn = _route->solo_safe ();
1054 if (check->get_active() != yn) {
1055 check->set_active (yn);
1059 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1061 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1063 bool yn = _route->get_mute_config(PRE_FADER);
1064 if (check->get_active() != yn) {
1065 check->set_active (yn);
1070 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1072 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1074 bool yn = _route->get_mute_config(POST_FADER);
1075 if (check->get_active() != yn) {
1076 check->set_active (yn);
1081 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1083 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1085 bool yn = _route->get_mute_config(CONTROL_OUTS);
1086 if (check->get_active() != yn) {
1087 check->set_active (yn);
1092 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1094 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1096 bool yn = _route->get_mute_config(MAIN_OUTS);
1097 if (check->get_active() != yn) {
1098 check->set_active (yn);
1103 RouteUI::disconnect_input ()
1105 _route->disconnect_inputs (this);
1109 RouteUI::disconnect_output ()
1111 _route->disconnect_outputs (this);
1115 RouteUI::is_track () const
1117 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1120 boost::shared_ptr<Track>
1121 RouteUI::track() const
1123 return boost::dynamic_pointer_cast<Track>(_route);
1127 RouteUI::is_audio_track () const
1129 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1132 boost::shared_ptr<AudioTrack>
1133 RouteUI::audio_track() const
1135 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1138 boost::shared_ptr<Diskstream>
1139 RouteUI::get_diskstream () const
1141 boost::shared_ptr<Track> t;
1143 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1144 return t->diskstream();
1146 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1151 RouteUI::name() const
1153 return _route->name();
1157 RouteUI::map_frozen ()
1159 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1161 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1164 switch (at->freeze_state()) {
1165 case AudioTrack::Frozen:
1166 rec_enable_button->set_sensitive (false);
1169 rec_enable_button->set_sensitive (true);
1176 RouteUI::save_as_template ()
1179 Glib::ustring safe_name;
1182 path = Session::route_template_dir();
1184 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1185 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1189 Prompter p (true); // modal
1191 p.set_prompt (_("Template name:"));
1193 case RESPONSE_ACCEPT:
1200 p.get_result (name, true);
1202 safe_name = legalize_for_path (name);
1203 safe_name += Session::template_suffix ();
1205 path = Glib::build_filename (path, safe_name);
1207 _route->save_as_template (path, name);