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"
34 #include "ardour_ui.h"
40 #include "gui_thread.h"
41 #include "ardour_dialog.h"
42 #include "latency_gui.h"
43 #include "mixer_strip.h"
44 #include "automation_time_axis.h"
46 #include "ardour/route.h"
47 #include "ardour/session.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/audio_track.h"
50 #include "ardour/audio_diskstream.h"
51 #include "ardour/midi_track.h"
52 #include "ardour/midi_diskstream.h"
53 #include "ardour/template_utils.h"
54 #include "ardour/filename_extensions.h"
55 #include "ardour/directory_names.h"
56 #include "ardour/profile.h"
61 using namespace Gtkmm2ext;
62 using namespace ARDOUR;
65 RouteUI::RouteUI (ARDOUR::Session& sess)
71 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess)
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;
97 remote_control_menu = 0;
99 ignore_toggle = false;
100 wait_for_release = false;
101 route_active_menu_item = 0;
102 polarity_menu_item = 0;
103 denormal_menu_item = 0;
104 multiple_mute_change = false;
105 multiple_solo_change = false;
107 mute_button = manage (new BindableToggleButton ());
108 mute_button->set_self_managed (true);
109 mute_button->set_name ("MuteButton");
110 mute_button->add (mute_button_label);
111 mute_button_label.show ();
112 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
114 solo_button = manage (new BindableToggleButton ());
115 solo_button->set_self_managed (true);
116 solo_button->set_name ("SoloButton");
117 solo_button->add (solo_button_label);
118 solo_button_label.show ();
119 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
120 solo_button->set_no_show_all (true);
122 rec_enable_button = manage (new BindableToggleButton ());
123 rec_enable_button->set_name ("RecordEnableButton");
124 rec_enable_button->set_self_managed (true);
125 rec_enable_button->add (rec_enable_button_label);
126 rec_enable_button_label.show ();
127 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
129 show_sends_button = manage (new BindableToggleButton (""));
130 show_sends_button->set_name ("SendAlert");
131 show_sends_button->set_self_managed (true);
132 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
134 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
135 _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
137 Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
143 //Remove route connections associated with us.
144 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
148 connections.clear ();
157 /* do not delete the node - its owned by the route */
161 route_active_menu_item = 0;
162 polarity_menu_item = 0;
163 denormal_menu_item = 0;
167 RouteUI::set_route (boost::shared_ptr<Route> rp)
173 if (set_color_from_route()) {
174 set_color (unique_random_color());
177 /* no, there is no memory leak here. This object cleans itself (and other stuff)
178 up when the route is destroyed.
182 new PairedShiva<Route,RouteUI> (*_route, *this);
185 mute_button->set_controllable (_route->mute_control());
186 solo_button->set_controllable (_route->solo_control());
188 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
189 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
190 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
191 connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed)));
192 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
195 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
197 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
198 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (PublicEditor::instance(), &PublicEditor::update_rec_display)));
199 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
201 rec_enable_button->show();
202 rec_enable_button->set_controllable (t->rec_enable_control());
204 update_rec_display ();
207 mute_button->unset_flags (Gtk::CAN_FOCUS);
208 solo_button->unset_flags (Gtk::CAN_FOCUS);
212 if (_route->is_master()) {
213 solo_button->hide ();
218 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
220 /* map the current state */
229 RouteUI::mute_press(GdkEventButton* ev)
231 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
234 multiple_mute_change = false;
235 if (!ignore_toggle) {
237 if (Keyboard::is_context_menu_event (ev)) {
243 mute_menu->popup(0,ev->time);
247 if (Keyboard::is_button2_event (ev)) {
248 // Primary-button2 click is the midi binding click
249 // button2-click is "momentary"
251 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
252 wait_for_release = true;
258 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
260 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
262 /* Primary-Tertiary-click applies change to all routes */
264 _session.begin_reversible_command (_("mute change"));
265 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
266 _session.set_all_mute (!_route->muted());
268 _session.add_command(cmd);
269 _session.commit_reversible_command ();
270 multiple_mute_change = true;
272 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
274 /* Primary-button1 applies change to the mix group.
275 NOTE: Primary-button2 is MIDI learn.
278 if (ev->button == 1) {
279 set_route_group_mute (_route, !_route->muted());
284 /* plain click applies change to this route */
285 if (wait_for_release) {
286 _route->set_mute (!_route->muted(), this);
288 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
300 RouteUI::mute_release(GdkEventButton* ev)
302 if (!ignore_toggle) {
303 if (wait_for_release){
304 wait_for_release = false;
305 if (multiple_mute_change) {
306 multiple_mute_change = false;
308 // because the press was the last undoable thing we did
311 _route->set_mute (!_route->muted(), this);
319 RouteUI::solo_press(GdkEventButton* ev)
321 /* ignore double/triple clicks */
323 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
327 if (Config->get_solo_control_is_listen_control()) {
329 _route->set_listen (!_route->listening(), this);
333 multiple_solo_change = false;
334 if (!ignore_toggle) {
336 if (Keyboard::is_context_menu_event (ev)) {
338 if (solo_menu == 0) {
342 solo_menu->popup (1, ev->time);
346 if (Keyboard::is_button2_event (ev)) {
348 // Primary-button2 click is the midi binding click
349 // button2-click is "momentary"
351 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
352 wait_for_release = true;
358 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
360 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
362 /* Primary-Tertiary-click applies change to all routes */
363 bool was_not_latched = false;
364 if (!Config->get_solo_latched ()) {
365 was_not_latched = true;
367 XXX it makes no sense to solo all tracks if we're
368 not in latched mode, but doing nothing feels like a bug,
371 Config->set_solo_latched (true);
373 _session.begin_reversible_command (_("solo change"));
374 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
375 _session.set_all_solo (!_route->soloed());
377 _session.add_command (cmd);
378 _session.commit_reversible_command ();
379 multiple_solo_change = true;
380 if (was_not_latched) {
381 Config->set_solo_latched (false);
384 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
386 // Primary-Secondary-click: exclusively solo this track, not a toggle */
388 _session.begin_reversible_command (_("solo change"));
389 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
390 _session.set_all_solo (false);
391 _route->set_solo (true, this);
393 _session.add_command(cmd);
394 _session.commit_reversible_command ();
396 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
398 // shift-click: set this route to solo safe
400 if (Profile->get_sae() && ev->button == 1) {
401 // button 1 and shift-click: disables solo_latched for this click
402 if (!Config->get_solo_latched ()) {
403 Config->set_solo_latched (true);
404 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
405 Config->set_solo_latched (false);
408 _route->set_solo_isolated (!_route->solo_isolated(), this);
409 wait_for_release = false;
412 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
414 /* Primary-button1: solo mix group.
415 NOTE: Primary-button2 is MIDI learn.
418 if (ev->button == 1) {
419 set_route_group_solo (_route, !_route->soloed());
424 /* click: solo this route */
425 if (wait_for_release) {
426 _route->set_solo (!_route->soloed(), this);
428 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
440 RouteUI::solo_release(GdkEventButton* ev)
442 if (!ignore_toggle) {
443 if (wait_for_release) {
444 wait_for_release = false;
445 if (multiple_solo_change) {
446 multiple_solo_change = false;
448 // because the press was the last undoable thing we did
451 // we don't use "undo the last op"
452 // here because its expensive for the GUI
453 _route->set_solo (!_route->soloed(), this);
462 RouteUI::rec_enable_press(GdkEventButton* ev)
464 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
468 if (!_session.engine().connected()) {
469 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
474 if (!ignore_toggle && is_track() && rec_enable_button) {
476 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
478 // do nothing on midi bind event
481 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
483 _session.begin_reversible_command (_("rec-enable change"));
484 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
486 if (rec_enable_button->get_active()) {
487 _session.record_disenable_all ();
489 _session.record_enable_all ();
490 check_rec_enable_sensitivity ();
494 _session.add_command(cmd);
495 _session.commit_reversible_command ();
497 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
499 /* Primary-button1 applies change to the mix group.
500 NOTE: Primary-button2 is MIDI learn.
503 set_route_group_rec_enable (_route, !_route->record_enabled());
506 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
507 check_rec_enable_sensitivity ();
515 RouteUI::rec_enable_release (GdkEventButton* ev)
521 RouteUI::build_sends_menu ()
523 using namespace Menu_Helpers;
525 sends_menu = new Menu;
526 sends_menu->set_name ("ArdourContextMenu");
527 MenuList& items = sends_menu->items();
529 items.push_back (MenuElem(_("Assign all tracks"), mem_fun (*this, &RouteUI::create_sends)));
530 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
531 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
532 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
537 RouteUI::create_sends ()
539 _session.globally_add_internal_sends (_route);
543 RouteUI::set_sends_gain_from_track ()
548 RouteUI::set_sends_gain_to_zero ()
553 RouteUI::set_sends_gain_to_unity ()
558 RouteUI::show_sends_press(GdkEventButton* ev)
560 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
564 if (!ignore_toggle && !is_track() && show_sends_button) {
566 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
568 // do nothing on midi bind event
571 } else if (Keyboard::is_context_menu_event (ev)) {
573 if (sends_menu == 0) {
577 sends_menu->popup (0, ev->time);
581 /* change button state */
583 show_sends_button->set_active (!show_sends_button->get_active());
587 if (show_sends_button->get_active()) {
588 /* show sends to this bus */
589 MixerStrip::SwitchIO (_route);
590 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
592 /* everybody back to normal */
593 send_blink_connection.disconnect ();
594 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
604 RouteUI::show_sends_release (GdkEventButton* ev)
610 RouteUI::send_blink (bool onoff)
612 if (!show_sends_button) {
617 show_sends_button->set_state (STATE_ACTIVE);
619 show_sends_button->set_state (STATE_NORMAL);
624 RouteUI::solo_changed(void* src)
626 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
631 RouteUI::listen_changed(void* src)
633 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
637 RouteUI::update_solo_display ()
641 if (Config->get_solo_control_is_listen_control()) {
643 if (solo_button->get_active() != (x = _route->listening())) {
644 ignore_toggle = true;
645 solo_button->set_active(x);
646 ignore_toggle = false;
651 if (solo_button->get_active() != (x = _route->soloed())){
652 ignore_toggle = true;
653 solo_button->set_active(x);
654 ignore_toggle = false;
657 if (_route->solo_isolated()) {
658 solo_button->set_visual_state (2);
659 } else if (_route->soloed()) {
660 solo_button->set_visual_state (1);
662 solo_button->set_visual_state (0);
668 RouteUI::solo_changed_so_update_mute ()
670 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
674 RouteUI::mute_changed(void* src)
676 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
680 RouteUI::update_mute_display ()
682 bool model = _route->muted();
683 bool view = mute_button->get_active();
685 /* first make sure the button's "depressed" visual
690 ignore_toggle = true;
691 mute_button->set_active (model);
692 ignore_toggle = false;
695 /* now attend to visual state */
697 if (Config->get_show_solo_mutes()) {
698 if (_route->muted()) {
699 mute_button->set_visual_state (2);
700 } else if (!_route->soloed() && _session.soloing()) {
701 mute_button->set_visual_state (1);
703 mute_button->set_visual_state (0);
706 if (_route->muted()) {
707 mute_button->set_visual_state (2);
709 mute_button->set_visual_state (0);
716 RouteUI::route_rec_enable_changed ()
718 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
722 RouteUI::session_rec_enable_changed ()
724 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
728 RouteUI::update_rec_display ()
730 bool model = _route->record_enabled();
731 bool view = rec_enable_button->get_active();
733 /* first make sure the button's "depressed" visual
738 ignore_toggle = true;
739 rec_enable_button->set_active (model);
740 ignore_toggle = false;
746 /* now make sure its color state is correct */
750 switch (_session.record_status ()) {
751 case Session::Recording:
752 rec_enable_button->set_visual_state (1);
755 case Session::Disabled:
756 case Session::Enabled:
757 rec_enable_button->set_visual_state (2);
763 rec_enable_button->set_visual_state (0);
768 RouteUI::build_remote_control_menu ()
770 remote_control_menu = new Menu;
771 refresh_remote_control_menu ();
775 RouteUI::refresh_remote_control_menu ()
777 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
779 // only refresh the menu if it has been instantiated
781 if (remote_control_menu == 0) {
785 using namespace Menu_Helpers;
787 RadioMenuItem::Group rc_group;
788 CheckMenuItem* rc_active;
789 uint32_t limit = _session.ntracks() + _session.nbusses();
792 MenuList& rc_items = remote_control_menu->items();
795 /* note that this menu list starts at zero, not 1, because zero
796 is a valid, if useless, ID.
799 limit += 4; /* leave some breathing room */
801 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
802 if (_route->remote_control_id() == 0) {
803 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
804 rc_active->set_active ();
807 for (uint32_t i = 1; i < limit; ++i) {
808 snprintf (buf, sizeof (buf), "%u", i);
809 rc_items.push_back (RadioMenuElem (rc_group, buf));
810 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
811 if (_route->remote_control_id() == i) {
812 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
813 rc_active->set_active ();
815 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
820 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
822 /* this is called when the radio menu item is toggled, and so
823 is actually invoked twice per menu selection. we only
824 care about the invocation for the item that was being
828 if (item->get_active()) {
829 _route->set_remote_control_id (id);
834 RouteUI::build_solo_menu (void)
836 using namespace Menu_Helpers;
838 solo_menu = new Menu;
839 solo_menu->set_name ("ArdourContextMenu");
840 MenuList& items = solo_menu->items();
841 CheckMenuItem* check;
843 check = new CheckMenuItem(_("Solo Isolate"));
844 check->set_active (_route->solo_isolated());
845 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
846 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
847 items.push_back (CheckMenuElem(*check));
850 //items.push_back (SeparatorElem());
851 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
856 RouteUI::build_mute_menu(void)
858 using namespace Menu_Helpers;
860 mute_menu = new Menu;
861 mute_menu->set_name ("ArdourContextMenu");
864 MenuList& items = mute_menu->items();
865 CheckMenuItem* check;
867 check = new CheckMenuItem(_("Pre Fader"));
868 init_mute_menu(PRE_FADER, check);
869 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
870 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
871 items.push_back (CheckMenuElem(*check));
874 check = new CheckMenuItem(_("Post Fader"));
875 init_mute_menu(POST_FADER, check);
876 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
877 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
878 items.push_back (CheckMenuElem(*check));
881 check = new CheckMenuItem(_("Control Outs"));
882 init_mute_menu(CONTROL_OUTS, check);
883 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
884 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
885 items.push_back (CheckMenuElem(*check));
888 check = new CheckMenuItem(_("Main Outs"));
889 init_mute_menu(MAIN_OUTS, check);
890 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
891 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
892 items.push_back (CheckMenuElem(*check));
895 //items.push_back (SeparatorElem());
896 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
900 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
902 check->set_active (_route->mute_master()->muted_at (mp));
906 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
908 // _route->set_mute_config(type, check->get_active(), this);
912 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
914 _route->set_solo_isolated (check->get_active(), this);
918 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
920 RouteGroup* route_group;
922 if((route_group = route->route_group()) != 0){
923 _session.begin_reversible_command (_("mix group solo change"));
924 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
925 route_group->apply(&Route::set_solo, yn, this);
927 _session.add_command (cmd);
928 _session.commit_reversible_command ();
930 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
935 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
937 _session.begin_reversible_command (name);
938 XMLNode &before = _route->get_state();
939 bind(mem_fun(*_route, func), yn, arg)();
940 XMLNode &after = _route->get_state();
941 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
942 _session.commit_reversible_command ();
946 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
948 _session.begin_reversible_command (name);
949 XMLNode &before = track()->get_state();
950 bind (mem_fun (*track(), func), yn, arg)();
951 XMLNode &after = track()->get_state();
952 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
953 _session.commit_reversible_command ();
957 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
959 RouteGroup* route_group;
961 if((route_group = route->route_group()) != 0){
962 _session.begin_reversible_command (_("mix group mute change"));
963 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
964 route_group->apply(&Route::set_mute, yn, this);
966 _session.add_command(cmd);
967 _session.commit_reversible_command ();
969 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
974 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
976 RouteGroup* route_group;
978 if((route_group = route->route_group()) != 0){
979 _session.begin_reversible_command (_("mix group rec-enable change"));
980 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
981 route_group->apply (&Route::set_record_enable, yn, this);
983 _session.add_command(cmd);
984 _session.commit_reversible_command ();
986 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
992 RouteUI::choose_color()
997 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1007 RouteUI::set_color (const Gdk::Color & c)
1014 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1015 xml_node->add_property ("color", buf);
1017 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1022 RouteUI::ensure_xml_node ()
1024 if (xml_node == 0) {
1025 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1026 xml_node = new XMLNode ("GUI");
1027 _route->add_extra_xml (*xml_node);
1033 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1037 XMLNodeList kids = xml_node->children();
1038 XMLNodeConstIterator iter;
1040 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1042 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1043 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1044 XMLProperty* type = (*iter)->property("automation-id");
1045 if (type && type->value() == sym)
1050 // Didn't find it, make a new one
1051 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1052 child->add_property("automation-id", sym);
1053 xml_node->add_child_nocopy (*child);
1059 RouteUI::set_color_from_route ()
1063 RouteUI::ensure_xml_node ();
1065 if ((prop = xml_node->property ("color")) != 0) {
1067 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1069 _color.set_green(g);
1077 RouteUI::remove_this_route ()
1079 vector<string> choices;
1083 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());
1085 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1088 choices.push_back (_("No, do nothing."));
1089 choices.push_back (_("Yes, remove it."));
1091 Choice prompter (prompt, choices);
1093 if (prompter.run () == 1) {
1094 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1099 RouteUI::idle_remove_this_route (RouteUI *rui)
1101 rui->_session.remove_route (rui->_route);
1106 RouteUI::route_rename ()
1108 ArdourPrompter name_prompter (true);
1110 name_prompter.set_prompt (_("New Name: "));
1111 name_prompter.set_initial_text (_route->name());
1112 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1113 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1114 name_prompter.show_all ();
1116 switch (name_prompter.run ()) {
1118 case Gtk::RESPONSE_ACCEPT:
1119 name_prompter.get_result (result);
1120 if (result.length()) {
1121 _route->set_name (result);
1131 RouteUI::name_changed ()
1133 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1135 name_label.set_text (_route->name());
1139 RouteUI::toggle_route_active ()
1143 if (route_active_menu_item) {
1144 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1145 _route->set_active (!yn);
1151 RouteUI::route_active_changed ()
1153 if (route_active_menu_item) {
1154 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1159 RouteUI::toggle_polarity ()
1161 if (polarity_menu_item) {
1165 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1167 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1168 _route->set_phase_invert (x);
1170 name_label.set_text (X_("Ø ") + name_label.get_text());
1172 name_label.set_text (_route->name());
1179 RouteUI::polarity_changed ()
1181 if (_route->phase_invert()) {
1182 name_label.set_text (X_("Ø ") + name_label.get_text());
1184 name_label.set_text (_route->name());
1189 RouteUI::toggle_denormal_protection ()
1191 if (denormal_menu_item) {
1195 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1197 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1198 _route->set_denormal_protection (x);
1204 RouteUI::denormal_protection_changed ()
1206 if (denormal_menu_item) {
1207 denormal_menu_item->set_active (_route->denormal_protection());
1212 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1214 bool yn = _route->solo_isolated ();
1216 if (check->get_active() != yn) {
1217 check->set_active (yn);
1221 #ifdef FIX_THIS_FOR_3_0
1223 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1225 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1227 bool yn = _route->get_mute_config(PRE_FADER);
1228 if (check->get_active() != yn) {
1229 check->set_active (yn);
1234 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1236 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1238 bool yn = _route->get_mute_config(POST_FADER);
1239 if (check->get_active() != yn) {
1240 check->set_active (yn);
1245 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1247 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1249 bool yn = _route->get_mute_config(CONTROL_OUTS);
1250 if (check->get_active() != yn) {
1251 check->set_active (yn);
1256 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1258 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1260 bool yn = _route->get_mute_config(MAIN_OUTS);
1261 if (check->get_active() != yn) {
1262 check->set_active (yn);
1268 RouteUI::disconnect_input ()
1270 _route->input()->disconnect (this);
1274 RouteUI::disconnect_output ()
1276 _route->output()->disconnect (this);
1280 RouteUI::is_track () const
1282 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1285 boost::shared_ptr<Track>
1286 RouteUI::track() const
1288 return boost::dynamic_pointer_cast<Track>(_route);
1292 RouteUI::is_audio_track () const
1294 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1297 boost::shared_ptr<AudioTrack>
1298 RouteUI::audio_track() const
1300 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1304 RouteUI::is_midi_track () const
1306 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1309 boost::shared_ptr<MidiTrack>
1310 RouteUI::midi_track() const
1312 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1315 boost::shared_ptr<Diskstream>
1316 RouteUI::get_diskstream () const
1318 boost::shared_ptr<Track> t;
1320 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1321 return t->diskstream();
1323 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1328 RouteUI::name() const
1330 return _route->name();
1334 RouteUI::map_frozen ()
1336 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1338 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1341 switch (at->freeze_state()) {
1342 case AudioTrack::Frozen:
1343 rec_enable_button->set_sensitive (false);
1346 rec_enable_button->set_sensitive (true);
1353 RouteUI::adjust_latency ()
1355 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1359 RouteUI::save_as_template ()
1362 Glib::ustring safe_name;
1365 path = ARDOUR::user_route_template_directory ();
1367 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1368 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1372 Prompter p (true); // modal
1374 p.set_prompt (_("Template name:"));
1376 case RESPONSE_ACCEPT:
1383 p.get_result (name, true);
1385 safe_name = legalize_for_path (name);
1386 safe_name += template_suffix;
1390 _route->save_as_template (path.to_string(), name);
1394 RouteUI::check_rec_enable_sensitivity ()
1396 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1397 rec_enable_button->set_sensitive (false);
1399 rec_enable_button->set_sensitive (true);
1404 RouteUI::parameter_changed (string const & p)
1406 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1408 if (p == "disable-disarm-during-roll") {
1409 check_rec_enable_sensitivity ();
1410 } else if (p == "solo-control-is-listen-control") {
1411 set_button_names ();
1412 } else if (p == "listen-position") {
1413 set_button_names ();