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/profile.h"
55 using namespace Gtkmm2ext;
56 using namespace ARDOUR;
59 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
63 set_button_names (mute_name, solo_name, rec_name);
66 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
67 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
71 set_button_names (mute_name, solo_name, rec_name);
77 GoingAway (); /* EMIT SIGNAL */
81 delete remote_control_menu;
90 remote_control_menu = 0;
91 ignore_toggle = false;
92 wait_for_release = false;
93 route_active_menu_item = 0;
94 was_solo_safe = false;
95 polarity_menu_item = 0;
96 denormal_menu_item = 0;
97 multiple_mute_change = false;
98 multiple_solo_change = false;
100 mute_button = manage (new BindableToggleButton (""));
101 mute_button->set_self_managed (true);
102 mute_button->set_name ("MuteButton");
103 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
105 solo_button = manage (new BindableToggleButton (""));
106 solo_button->set_self_managed (true);
107 solo_button->set_name ("SoloButton");
108 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
110 rec_enable_button = manage (new BindableToggleButton (""));
111 rec_enable_button->set_name ("RecordEnableButton");
112 rec_enable_button->set_self_managed (true);
113 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
115 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
121 connections.clear ();
130 /* do not delete the node - its owned by the route */
134 route_active_menu_item = 0;
135 polarity_menu_item = 0;
136 denormal_menu_item = 0;
140 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
148 RouteUI::set_route (boost::shared_ptr<Route> rp)
154 if (set_color_from_route()) {
155 set_color (unique_random_color());
158 /* no, there is no memory leak here. This object cleans itself (and other stuff)
159 up when the route is destroyed.
162 new PairedShiva<Route,RouteUI> (*_route, *this);
164 mute_button->set_controllable (_route->mute_control());
165 mute_button->set_label (m_name);
167 solo_button->set_controllable (_route->solo_control());
168 solo_button->set_label (s_name);
170 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
171 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
172 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
173 connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
175 /* when solo changes, update mute state too, in case the user wants us to display it */
177 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
180 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
182 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
183 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
185 rec_enable_button->show();
186 rec_enable_button->set_controllable (t->rec_enable_control());
187 rec_enable_button->set_label (r_name);
189 update_rec_display ();
192 mute_button->unset_flags (Gtk::CAN_FOCUS);
193 solo_button->unset_flags (Gtk::CAN_FOCUS);
198 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
200 /* map the current state */
206 RouteUI::mute_press(GdkEventButton* ev)
208 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
211 multiple_mute_change = false;
212 if (!ignore_toggle) {
214 if (Keyboard::is_context_menu_event (ev)) {
220 mute_menu->popup(0,ev->time);
224 if (Keyboard::is_button2_event (ev)) {
225 // Primary-button2 click is the midi binding click
226 // button2-click is "momentary"
228 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
229 wait_for_release = true;
235 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
237 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
239 /* Primary-Tertiary-click applies change to all routes */
241 _session.begin_reversible_command (_("mute change"));
242 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
243 _session.set_all_mute (!_route->muted());
245 _session.add_command(cmd);
246 _session.commit_reversible_command ();
247 multiple_mute_change = true;
249 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
251 /* Primary-button1 applies change to the mix group.
252 NOTE: Primary-button2 is MIDI learn.
255 if (ev->button == 1) {
256 set_mix_group_mute (_route, !_route->muted());
261 /* plain click applies change to this route */
262 if (wait_for_release) {
263 _route->set_mute (!_route->muted(), this);
265 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
277 RouteUI::mute_release(GdkEventButton* ev)
279 if (!ignore_toggle) {
280 if (wait_for_release){
281 wait_for_release = false;
282 if (multiple_mute_change) {
283 multiple_mute_change = false;
285 // because the press was the last undoable thing we did
288 _route->set_mute (!_route->muted(), this);
296 RouteUI::solo_press(GdkEventButton* ev)
298 /* ignore double/triple clicks */
300 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
303 multiple_solo_change = false;
304 if (!ignore_toggle) {
306 if (Keyboard::is_context_menu_event (ev)) {
308 if (solo_menu == 0) {
312 solo_menu->popup (1, ev->time);
316 if (Keyboard::is_button2_event (ev)) {
318 // Primary-button2 click is the midi binding click
319 // button2-click is "momentary"
321 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
322 wait_for_release = true;
328 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
330 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
332 /* Primary-Tertiary-click applies change to all routes */
333 bool was_not_latched = false;
334 if (!Config->get_solo_latched ()) {
335 was_not_latched = true;
337 XXX it makes no sense to solo all tracks if we're
338 not in latched mode, but doing nothing feels like a bug,
341 Config->set_solo_latched (true);
343 _session.begin_reversible_command (_("solo change"));
344 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
345 _session.set_all_solo (!_route->soloed());
347 _session.add_command (cmd);
348 _session.commit_reversible_command ();
349 multiple_solo_change = true;
350 if (was_not_latched) {
351 Config->set_solo_latched (false);
354 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
356 // Primary-Secondary-click: exclusively solo this track, not a toggle */
358 _session.begin_reversible_command (_("solo change"));
359 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
360 _session.set_all_solo (false);
361 _route->set_solo (true, this);
363 _session.add_command(cmd);
364 _session.commit_reversible_command ();
366 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
368 // shift-click: set this route to solo safe
370 if (Profile->get_sae() && ev->button == 1) {
371 // button 1 and shift-click: disables solo_latched for this click
372 if (!Config->get_solo_latched ()) {
373 Config->set_solo_latched (true);
374 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
375 Config->set_solo_latched (false);
378 _route->set_solo_safe (!_route->solo_safe(), this);
379 wait_for_release = false;
382 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
384 /* Primary-button1: solo mix group.
385 NOTE: Primary-button2 is MIDI learn.
388 if (ev->button == 1) {
389 set_mix_group_solo (_route, !_route->soloed());
394 /* click: solo this route */
395 if (wait_for_release) {
396 _route->set_solo (!_route->soloed(), this);
398 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
409 RouteUI::solo_release(GdkEventButton* ev)
411 if (!ignore_toggle) {
412 if (wait_for_release) {
413 wait_for_release = false;
414 if (multiple_solo_change) {
415 multiple_solo_change = false;
417 // because the press was the last undoable thing we did
420 // we don't use "undo the last op"
421 // here because its expensive for the GUI
422 _route->set_solo (!_route->soloed(), this);
431 RouteUI::rec_enable_press(GdkEventButton* ev)
433 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
437 if (!_session.engine().connected()) {
438 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
443 if (!ignore_toggle && is_track() && rec_enable_button) {
445 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
447 // do nothing on midi bind event
450 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
452 _session.begin_reversible_command (_("rec-enable change"));
453 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
455 if (rec_enable_button->get_active()) {
456 _session.record_disenable_all ();
458 _session.record_enable_all ();
462 _session.add_command(cmd);
463 _session.commit_reversible_command ();
465 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
467 /* Primary-button1 applies change to the mix group.
468 NOTE: Primary-button2 is MIDI learn.
471 set_mix_group_rec_enable (_route, !_route->record_enabled());
475 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
483 RouteUI::rec_enable_release (GdkEventButton* ev)
489 RouteUI::solo_changed(void* src)
492 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
496 RouteUI::update_solo_display ()
499 vector<Gdk::Color> fg_colors;
502 if (solo_button->get_active() != (x = _route->soloed())){
503 ignore_toggle = true;
504 solo_button->set_active(x);
505 ignore_toggle = false;
508 if (_route->solo_safe()) {
509 solo_button->set_visual_state (2);
510 } else if (_route->soloed()) {
511 solo_button->set_visual_state (1);
513 solo_button->set_visual_state (0);
518 RouteUI::solo_changed_so_update_mute ()
520 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
524 RouteUI::mute_changed(void* src)
526 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
530 RouteUI::update_mute_display ()
532 bool model = _route->muted();
533 bool view = mute_button->get_active();
535 /* first make sure the button's "depressed" visual
540 ignore_toggle = true;
541 mute_button->set_active (model);
542 ignore_toggle = false;
545 /* now attend to visual state */
547 if (Config->get_show_solo_mutes()) {
548 if (_route->muted()) {
549 mute_button->set_visual_state (2);
550 } else if (!_route->soloed() && _route->solo_muted()) {
552 mute_button->set_visual_state (1);
554 mute_button->set_visual_state (0);
557 if (_route->muted()) {
558 mute_button->set_visual_state (2);
560 mute_button->set_visual_state (0);
567 RouteUI::route_rec_enable_changed ()
569 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
573 RouteUI::session_rec_enable_changed ()
575 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
579 RouteUI::update_rec_display ()
581 bool model = _route->record_enabled();
582 bool view = rec_enable_button->get_active();
584 /* first make sure the button's "depressed" visual
589 ignore_toggle = true;
590 rec_enable_button->set_active (model);
591 ignore_toggle = false;
594 /* now make sure its color state is correct */
598 switch (_session.record_status ()) {
599 case Session::Recording:
600 rec_enable_button->set_visual_state (1);
603 case Session::Disabled:
604 case Session::Enabled:
605 rec_enable_button->set_visual_state (2);
611 rec_enable_button->set_visual_state (0);
616 RouteUI::build_remote_control_menu ()
618 remote_control_menu = new Menu;
619 refresh_remote_control_menu ();
623 RouteUI::refresh_remote_control_menu ()
625 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
627 // only refresh the menu if it has been instantiated
629 if (remote_control_menu == 0) {
633 using namespace Menu_Helpers;
635 RadioMenuItem::Group rc_group;
636 CheckMenuItem* rc_active;
637 uint32_t limit = _session.ntracks() + _session.nbusses();
640 MenuList& rc_items = remote_control_menu->items();
643 /* note that this menu list starts at zero, not 1, because zero
644 is a valid, if useless, ID.
647 limit += 4; /* leave some breathing room */
649 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
650 if (_route->remote_control_id() == 0) {
651 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
652 rc_active->set_active ();
655 for (uint32_t i = 1; i < limit; ++i) {
656 snprintf (buf, sizeof (buf), "%u", i);
657 rc_items.push_back (RadioMenuElem (rc_group, buf));
658 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
659 if (_route->remote_control_id() == i) {
660 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
661 rc_active->set_active ();
663 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
668 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
670 /* this is called when the radio menu item is toggled, and so
671 is actually invoked twice per menu selection. we only
672 care about the invocation for the item that was being
676 if (item->get_active()) {
677 _route->set_remote_control_id (id);
682 RouteUI::build_solo_menu (void)
684 using namespace Menu_Helpers;
686 solo_menu = new Menu;
687 solo_menu->set_name ("ArdourContextMenu");
688 MenuList& items = solo_menu->items();
689 CheckMenuItem* check;
691 check = new CheckMenuItem(_("Solo-safe"));
692 check->set_active (_route->solo_safe());
693 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
694 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
695 items.push_back (CheckMenuElem(*check));
698 //items.push_back (SeparatorElem());
699 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
704 RouteUI::build_mute_menu(void)
706 using namespace Menu_Helpers;
708 mute_menu = new Menu;
709 mute_menu->set_name ("ArdourContextMenu");
710 MenuList& items = mute_menu->items();
711 CheckMenuItem* check;
713 check = new CheckMenuItem(_("Pre Fader"));
714 init_mute_menu(PRE_FADER, check);
715 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
716 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
717 items.push_back (CheckMenuElem(*check));
720 check = new CheckMenuItem(_("Post Fader"));
721 init_mute_menu(POST_FADER, check);
722 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
723 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
724 items.push_back (CheckMenuElem(*check));
727 check = new CheckMenuItem(_("Control Outs"));
728 init_mute_menu(CONTROL_OUTS, check);
729 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
730 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
731 items.push_back (CheckMenuElem(*check));
734 check = new CheckMenuItem(_("Main Outs"));
735 init_mute_menu(MAIN_OUTS, check);
736 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
737 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
738 items.push_back (CheckMenuElem(*check));
741 //items.push_back (SeparatorElem());
742 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
746 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
748 if (_route->get_mute_config (type)) {
749 check->set_active (true);
754 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
756 _route->set_mute_config(type, check->get_active(), this);
760 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
762 _route->set_solo_safe (check->get_active(), this);
766 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
768 RouteGroup* mix_group;
770 if((mix_group = route->mix_group()) != 0){
771 _session.begin_reversible_command (_("mix group solo change"));
772 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
773 mix_group->apply(&Route::set_solo, yn, this);
775 _session.add_command (cmd);
776 _session.commit_reversible_command ();
778 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
783 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
785 _session.begin_reversible_command (name);
786 XMLNode &before = _route->get_state();
787 bind(mem_fun(*_route, func), yn, arg)();
788 XMLNode &after = _route->get_state();
789 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
790 _session.commit_reversible_command ();
794 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
796 _session.begin_reversible_command (name);
797 XMLNode &before = track()->get_state();
798 bind (mem_fun (*track(), func), yn, arg)();
799 XMLNode &after = track()->get_state();
800 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
801 _session.commit_reversible_command ();
805 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
807 RouteGroup* mix_group;
809 if((mix_group = route->mix_group()) != 0){
810 _session.begin_reversible_command (_("mix group mute change"));
811 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
812 mix_group->apply(&Route::set_mute, yn, this);
814 _session.add_command(cmd);
815 _session.commit_reversible_command ();
817 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
822 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
824 RouteGroup* mix_group;
826 if((mix_group = route->mix_group()) != 0){
827 _session.begin_reversible_command (_("mix group rec-enable change"));
828 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
829 mix_group->apply (&Route::set_record_enable, yn, this);
831 _session.add_command(cmd);
832 _session.commit_reversible_command ();
834 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
840 RouteUI::choose_color()
845 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
855 RouteUI::set_color (const Gdk::Color & c)
862 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
863 xml_node->add_property ("color", buf);
865 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
870 RouteUI::ensure_xml_node ()
873 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
874 xml_node = new XMLNode ("GUI");
875 _route->add_extra_xml (*xml_node);
881 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
885 XMLNodeList kids = xml_node->children();
886 XMLNodeConstIterator iter;
888 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
890 for (iter = kids.begin(); iter != kids.end(); ++iter) {
891 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
892 XMLProperty* type = (*iter)->property("automation-id");
893 if (type && type->value() == sym)
898 // Didn't find it, make a new one
899 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
900 child->add_property("automation-id", sym);
901 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);
979 RouteUI::name_changed ()
981 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
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);
1144 RouteUI::is_midi_track () const
1146 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1149 boost::shared_ptr<MidiTrack>
1150 RouteUI::midi_track() const
1152 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1155 boost::shared_ptr<Diskstream>
1156 RouteUI::get_diskstream () const
1158 boost::shared_ptr<Track> t;
1160 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1161 return t->diskstream();
1163 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1168 RouteUI::name() const
1170 return _route->name();
1174 RouteUI::map_frozen ()
1176 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1178 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1181 switch (at->freeze_state()) {
1182 case AudioTrack::Frozen:
1183 rec_enable_button->set_sensitive (false);
1186 rec_enable_button->set_sensitive (true);
1193 RouteUI::adjust_latency ()
1195 LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());