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/barcontroller.h>
26 #include <gtkmm2ext/gtk_ui.h>
28 #include "ardour/route_group.h"
29 #include "pbd/memento_command.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/shiva.h"
32 #include "pbd/controllable.h"
38 #include "gui_thread.h"
39 #include "ardour_dialog.h"
40 #include "latency_gui.h"
41 #include "automation_time_axis.h"
43 #include "ardour/route.h"
44 #include "ardour/session.h"
45 #include "ardour/audioengine.h"
46 #include "ardour/audio_track.h"
47 #include "ardour/audio_diskstream.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/midi_diskstream.h"
50 #include "ardour/template_utils.h"
51 #include "ardour/filename_extensions.h"
52 #include "ardour/directory_names.h"
53 #include "ardour/profile.h"
58 using namespace Gtkmm2ext;
59 using namespace ARDOUR;
62 RouteUI::RouteUI (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);
69 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
70 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
74 set_button_names (mute_name, solo_name, rec_name);
80 /* derived classes should emit GoingAway so that they receive the signal
81 when the object is still a legal derived instance.
86 delete remote_control_menu;
96 remote_control_menu = 0;
97 ignore_toggle = false;
98 wait_for_release = false;
99 route_active_menu_item = 0;
100 was_solo_safe = false;
101 polarity_menu_item = 0;
102 denormal_menu_item = 0;
103 multiple_mute_change = false;
104 multiple_solo_change = false;
106 mute_button = manage (new BindableToggleButton (""));
107 mute_button->set_self_managed (true);
108 mute_button->set_name ("MuteButton");
109 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
111 solo_button = manage (new BindableToggleButton (""));
112 solo_button->set_self_managed (true);
113 solo_button->set_name ("SoloButton");
114 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
116 rec_enable_button = manage (new BindableToggleButton (""));
117 rec_enable_button->set_name ("RecordEnableButton");
118 rec_enable_button->set_self_managed (true);
119 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
121 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
127 connections.clear ();
136 /* do not delete the node - its owned by the route */
140 route_active_menu_item = 0;
141 polarity_menu_item = 0;
142 denormal_menu_item = 0;
146 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
154 RouteUI::set_route (boost::shared_ptr<Route> rp)
160 if (set_color_from_route()) {
161 set_color (unique_random_color());
164 /* no, there is no memory leak here. This object cleans itself (and other stuff)
165 up when the route is destroyed.
169 new PairedShiva<Route,RouteUI> (*_route, *this);
172 mute_button->set_controllable (_route->mute_control());
173 mute_button->set_label (m_name);
175 solo_button->set_controllable (_route->solo_control());
176 solo_button->set_label (s_name);
178 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
179 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
180 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
181 connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
183 /* when solo changes, update mute state too, in case the user wants us to display it */
185 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
188 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
190 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
191 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
193 rec_enable_button->show();
194 rec_enable_button->set_controllable (t->rec_enable_control());
195 rec_enable_button->set_label (r_name);
197 update_rec_display ();
200 mute_button->unset_flags (Gtk::CAN_FOCUS);
201 solo_button->unset_flags (Gtk::CAN_FOCUS);
206 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
208 /* map the current state */
214 RouteUI::mute_press(GdkEventButton* ev)
216 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
219 multiple_mute_change = false;
220 if (!ignore_toggle) {
222 if (Keyboard::is_context_menu_event (ev)) {
228 mute_menu->popup(0,ev->time);
232 if (Keyboard::is_button2_event (ev)) {
233 // Primary-button2 click is the midi binding click
234 // button2-click is "momentary"
236 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
237 wait_for_release = true;
243 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
245 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
247 /* Primary-Tertiary-click applies change to all routes */
249 _session.begin_reversible_command (_("mute change"));
250 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
251 _session.set_all_mute (!_route->muted());
253 _session.add_command(cmd);
254 _session.commit_reversible_command ();
255 multiple_mute_change = true;
257 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
259 /* Primary-button1 applies change to the mix group.
260 NOTE: Primary-button2 is MIDI learn.
263 if (ev->button == 1) {
264 set_mix_group_mute (_route, !_route->muted());
269 /* plain click applies change to this route */
270 if (wait_for_release) {
271 _route->set_mute (!_route->muted(), this);
273 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
285 RouteUI::mute_release(GdkEventButton* ev)
287 if (!ignore_toggle) {
288 if (wait_for_release){
289 wait_for_release = false;
290 if (multiple_mute_change) {
291 multiple_mute_change = false;
293 // because the press was the last undoable thing we did
296 _route->set_mute (!_route->muted(), this);
304 RouteUI::solo_press(GdkEventButton* ev)
306 /* ignore double/triple clicks */
308 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
311 multiple_solo_change = false;
312 if (!ignore_toggle) {
314 if (Keyboard::is_context_menu_event (ev)) {
316 if (solo_menu == 0) {
320 solo_menu->popup (1, ev->time);
324 if (Keyboard::is_button2_event (ev)) {
326 // Primary-button2 click is the midi binding click
327 // button2-click is "momentary"
329 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
330 wait_for_release = true;
336 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
338 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
340 /* Primary-Tertiary-click applies change to all routes */
341 bool was_not_latched = false;
342 if (!Config->get_solo_latched ()) {
343 was_not_latched = true;
345 XXX it makes no sense to solo all tracks if we're
346 not in latched mode, but doing nothing feels like a bug,
349 Config->set_solo_latched (true);
351 _session.begin_reversible_command (_("solo change"));
352 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
353 _session.set_all_solo (!_route->soloed());
355 _session.add_command (cmd);
356 _session.commit_reversible_command ();
357 multiple_solo_change = true;
358 if (was_not_latched) {
359 Config->set_solo_latched (false);
362 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
364 // Primary-Secondary-click: exclusively solo this track, not a toggle */
366 _session.begin_reversible_command (_("solo change"));
367 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
368 _session.set_all_solo (false);
369 _route->set_solo (true, this);
371 _session.add_command(cmd);
372 _session.commit_reversible_command ();
374 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
376 // shift-click: set this route to solo safe
378 if (Profile->get_sae() && ev->button == 1) {
379 // button 1 and shift-click: disables solo_latched for this click
380 if (!Config->get_solo_latched ()) {
381 Config->set_solo_latched (true);
382 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
383 Config->set_solo_latched (false);
386 _route->set_solo_safe (!_route->solo_safe(), this);
387 wait_for_release = false;
390 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
392 /* Primary-button1: solo mix group.
393 NOTE: Primary-button2 is MIDI learn.
396 if (ev->button == 1) {
397 set_mix_group_solo (_route, !_route->soloed());
402 /* click: solo this route */
403 if (wait_for_release) {
404 _route->set_solo (!_route->soloed(), this);
406 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
417 RouteUI::solo_release(GdkEventButton* ev)
419 if (!ignore_toggle) {
420 if (wait_for_release) {
421 wait_for_release = false;
422 if (multiple_solo_change) {
423 multiple_solo_change = false;
425 // because the press was the last undoable thing we did
428 // we don't use "undo the last op"
429 // here because its expensive for the GUI
430 _route->set_solo (!_route->soloed(), this);
439 RouteUI::rec_enable_press(GdkEventButton* ev)
441 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
445 if (!_session.engine().connected()) {
446 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
451 if (!ignore_toggle && is_track() && rec_enable_button) {
453 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
455 // do nothing on midi bind event
458 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
460 _session.begin_reversible_command (_("rec-enable change"));
461 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
463 if (rec_enable_button->get_active()) {
464 _session.record_disenable_all ();
466 _session.record_enable_all ();
470 _session.add_command(cmd);
471 _session.commit_reversible_command ();
473 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
475 /* Primary-button1 applies change to the mix group.
476 NOTE: Primary-button2 is MIDI learn.
479 set_mix_group_rec_enable (_route, !_route->record_enabled());
483 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
491 RouteUI::rec_enable_release (GdkEventButton* ev)
497 RouteUI::solo_changed(void* src)
500 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
504 RouteUI::update_solo_display ()
507 vector<Gdk::Color> fg_colors;
510 if (solo_button->get_active() != (x = _route->soloed())){
511 ignore_toggle = true;
512 solo_button->set_active(x);
513 ignore_toggle = false;
516 if (_route->solo_safe()) {
517 solo_button->set_visual_state (2);
518 } else if (_route->soloed()) {
519 solo_button->set_visual_state (1);
521 solo_button->set_visual_state (0);
526 RouteUI::solo_changed_so_update_mute ()
528 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
532 RouteUI::mute_changed(void* src)
534 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
538 RouteUI::update_mute_display ()
540 bool model = _route->muted();
541 bool view = mute_button->get_active();
543 /* first make sure the button's "depressed" visual
548 ignore_toggle = true;
549 mute_button->set_active (model);
550 ignore_toggle = false;
553 /* now attend to visual state */
555 if (Config->get_show_solo_mutes()) {
556 if (_route->muted()) {
557 mute_button->set_visual_state (2);
558 } else if (!_route->soloed() && _route->solo_muted()) {
560 mute_button->set_visual_state (1);
562 mute_button->set_visual_state (0);
565 if (_route->muted()) {
566 mute_button->set_visual_state (2);
568 mute_button->set_visual_state (0);
575 RouteUI::route_rec_enable_changed ()
577 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
581 RouteUI::session_rec_enable_changed ()
583 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
587 RouteUI::update_rec_display ()
589 bool model = _route->record_enabled();
590 bool view = rec_enable_button->get_active();
592 /* first make sure the button's "depressed" visual
597 ignore_toggle = true;
598 rec_enable_button->set_active (model);
599 ignore_toggle = false;
602 /* now make sure its color state is correct */
606 switch (_session.record_status ()) {
607 case Session::Recording:
608 rec_enable_button->set_visual_state (1);
611 case Session::Disabled:
612 case Session::Enabled:
613 rec_enable_button->set_visual_state (2);
619 rec_enable_button->set_visual_state (0);
624 RouteUI::build_remote_control_menu ()
626 remote_control_menu = new Menu;
627 refresh_remote_control_menu ();
631 RouteUI::refresh_remote_control_menu ()
633 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
635 // only refresh the menu if it has been instantiated
637 if (remote_control_menu == 0) {
641 using namespace Menu_Helpers;
643 RadioMenuItem::Group rc_group;
644 CheckMenuItem* rc_active;
645 uint32_t limit = _session.ntracks() + _session.nbusses();
648 MenuList& rc_items = remote_control_menu->items();
651 /* note that this menu list starts at zero, not 1, because zero
652 is a valid, if useless, ID.
655 limit += 4; /* leave some breathing room */
657 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
658 if (_route->remote_control_id() == 0) {
659 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
660 rc_active->set_active ();
663 for (uint32_t i = 1; i < limit; ++i) {
664 snprintf (buf, sizeof (buf), "%u", i);
665 rc_items.push_back (RadioMenuElem (rc_group, buf));
666 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
667 if (_route->remote_control_id() == i) {
668 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
669 rc_active->set_active ();
671 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
676 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
678 /* this is called when the radio menu item is toggled, and so
679 is actually invoked twice per menu selection. we only
680 care about the invocation for the item that was being
684 if (item->get_active()) {
685 _route->set_remote_control_id (id);
690 RouteUI::build_solo_menu (void)
692 using namespace Menu_Helpers;
694 solo_menu = new Menu;
695 solo_menu->set_name ("ArdourContextMenu");
696 MenuList& items = solo_menu->items();
697 CheckMenuItem* check;
699 check = new CheckMenuItem(_("Solo-safe"));
700 check->set_active (_route->solo_safe());
701 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
702 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
703 items.push_back (CheckMenuElem(*check));
706 //items.push_back (SeparatorElem());
707 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
712 RouteUI::build_mute_menu(void)
714 using namespace Menu_Helpers;
716 mute_menu = new Menu;
717 mute_menu->set_name ("ArdourContextMenu");
718 MenuList& items = mute_menu->items();
719 CheckMenuItem* check;
721 check = new CheckMenuItem(_("Pre Fader"));
722 init_mute_menu(PRE_FADER, check);
723 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
724 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
725 items.push_back (CheckMenuElem(*check));
728 check = new CheckMenuItem(_("Post Fader"));
729 init_mute_menu(POST_FADER, check);
730 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
731 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
732 items.push_back (CheckMenuElem(*check));
735 check = new CheckMenuItem(_("Control Outs"));
736 init_mute_menu(CONTROL_OUTS, check);
737 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
738 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
739 items.push_back (CheckMenuElem(*check));
742 check = new CheckMenuItem(_("Main Outs"));
743 init_mute_menu(MAIN_OUTS, check);
744 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
745 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
746 items.push_back (CheckMenuElem(*check));
749 //items.push_back (SeparatorElem());
750 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
754 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
756 if (_route->get_mute_config (type)) {
757 check->set_active (true);
762 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
764 _route->set_mute_config(type, check->get_active(), this);
768 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
770 _route->set_solo_safe (check->get_active(), this);
774 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
776 RouteGroup* mix_group;
778 if((mix_group = route->mix_group()) != 0){
779 _session.begin_reversible_command (_("mix group solo change"));
780 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
781 mix_group->apply(&Route::set_solo, yn, this);
783 _session.add_command (cmd);
784 _session.commit_reversible_command ();
786 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
791 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
793 _session.begin_reversible_command (name);
794 XMLNode &before = _route->get_state();
795 bind(mem_fun(*_route, func), yn, arg)();
796 XMLNode &after = _route->get_state();
797 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
798 _session.commit_reversible_command ();
802 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
804 _session.begin_reversible_command (name);
805 XMLNode &before = track()->get_state();
806 bind (mem_fun (*track(), func), yn, arg)();
807 XMLNode &after = track()->get_state();
808 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
809 _session.commit_reversible_command ();
813 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
815 RouteGroup* mix_group;
817 if((mix_group = route->mix_group()) != 0){
818 _session.begin_reversible_command (_("mix group mute change"));
819 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
820 mix_group->apply(&Route::set_mute, yn, this);
822 _session.add_command(cmd);
823 _session.commit_reversible_command ();
825 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
830 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
832 RouteGroup* mix_group;
834 if((mix_group = route->mix_group()) != 0){
835 _session.begin_reversible_command (_("mix group rec-enable change"));
836 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
837 mix_group->apply (&Route::set_record_enable, yn, this);
839 _session.add_command(cmd);
840 _session.commit_reversible_command ();
842 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
848 RouteUI::choose_color()
853 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
863 RouteUI::set_color (const Gdk::Color & c)
870 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
871 xml_node->add_property ("color", buf);
873 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
878 RouteUI::ensure_xml_node ()
881 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
882 xml_node = new XMLNode ("GUI");
883 _route->add_extra_xml (*xml_node);
889 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
893 XMLNodeList kids = xml_node->children();
894 XMLNodeConstIterator iter;
896 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
898 for (iter = kids.begin(); iter != kids.end(); ++iter) {
899 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
900 XMLProperty* type = (*iter)->property("automation-id");
901 if (type && type->value() == sym)
906 // Didn't find it, make a new one
907 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
908 child->add_property("automation-id", sym);
909 xml_node->add_child_nocopy (*child);
915 RouteUI::set_color_from_route ()
919 RouteUI::ensure_xml_node ();
921 if ((prop = xml_node->property ("color")) != 0) {
923 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
933 RouteUI::remove_this_route ()
935 vector<string> choices;
939 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());
941 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
944 choices.push_back (_("No, do nothing."));
945 choices.push_back (_("Yes, remove it."));
947 Choice prompter (prompt, choices);
949 if (prompter.run () == 1) {
950 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
955 RouteUI::idle_remove_this_route (RouteUI *rui)
957 rui->_session.remove_route (rui->_route);
962 RouteUI::route_rename ()
964 ArdourPrompter name_prompter (true);
966 name_prompter.set_prompt (_("New Name: "));
967 name_prompter.set_initial_text (_route->name());
968 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
969 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
970 name_prompter.show_all ();
972 switch (name_prompter.run ()) {
974 case Gtk::RESPONSE_ACCEPT:
975 name_prompter.get_result (result);
976 if (result.length()) {
977 _route->set_name (result);
987 RouteUI::name_changed ()
989 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
991 name_label.set_text (_route->name());
995 RouteUI::toggle_route_active ()
999 if (route_active_menu_item) {
1000 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1001 _route->set_active (!yn);
1007 RouteUI::route_active_changed ()
1009 if (route_active_menu_item) {
1010 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1015 RouteUI::toggle_polarity ()
1017 if (polarity_menu_item) {
1021 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1023 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1024 _route->set_phase_invert (x, this);
1026 name_label.set_text (X_("Ø ") + name_label.get_text());
1028 name_label.set_text (_route->name());
1035 RouteUI::polarity_changed ()
1037 /* no signal for this yet */
1041 RouteUI::toggle_denormal_protection ()
1043 if (denormal_menu_item) {
1047 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1049 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1050 _route->set_denormal_protection (x, this);
1056 RouteUI::denormal_protection_changed ()
1058 /* no signal for this yet */
1063 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1065 bool yn = _route->solo_safe ();
1067 if (check->get_active() != yn) {
1068 check->set_active (yn);
1072 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1074 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1076 bool yn = _route->get_mute_config(PRE_FADER);
1077 if (check->get_active() != yn) {
1078 check->set_active (yn);
1083 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1085 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1087 bool yn = _route->get_mute_config(POST_FADER);
1088 if (check->get_active() != yn) {
1089 check->set_active (yn);
1094 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1096 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1098 bool yn = _route->get_mute_config(CONTROL_OUTS);
1099 if (check->get_active() != yn) {
1100 check->set_active (yn);
1105 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1107 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1109 bool yn = _route->get_mute_config(MAIN_OUTS);
1110 if (check->get_active() != yn) {
1111 check->set_active (yn);
1116 RouteUI::disconnect_input ()
1118 _route->disconnect_inputs (this);
1122 RouteUI::disconnect_output ()
1124 _route->disconnect_outputs (this);
1128 RouteUI::is_track () const
1130 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1133 boost::shared_ptr<Track>
1134 RouteUI::track() const
1136 return boost::dynamic_pointer_cast<Track>(_route);
1140 RouteUI::is_audio_track () const
1142 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1145 boost::shared_ptr<AudioTrack>
1146 RouteUI::audio_track() const
1148 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1152 RouteUI::is_midi_track () const
1154 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1157 boost::shared_ptr<MidiTrack>
1158 RouteUI::midi_track() const
1160 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1163 boost::shared_ptr<Diskstream>
1164 RouteUI::get_diskstream () const
1166 boost::shared_ptr<Track> t;
1168 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1169 return t->diskstream();
1171 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1176 RouteUI::name() const
1178 return _route->name();
1182 RouteUI::map_frozen ()
1184 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1186 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1189 switch (at->freeze_state()) {
1190 case AudioTrack::Frozen:
1191 rec_enable_button->set_sensitive (false);
1194 rec_enable_button->set_sensitive (true);
1201 RouteUI::adjust_latency ()
1203 LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());
1207 RouteUI::save_as_template ()
1210 Glib::ustring safe_name;
1213 path = ARDOUR::user_route_template_directory ();
1215 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1216 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1220 Prompter p (true); // modal
1222 p.set_prompt (_("Template name:"));
1224 case RESPONSE_ACCEPT:
1231 p.get_result (name, true);
1233 safe_name = legalize_for_path (name);
1234 safe_name += template_suffix;
1238 _route->save_as_template (path.to_string(), name);