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->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
194 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
196 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
197 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (PublicEditor::instance(), &PublicEditor::update_rec_display)));
198 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
200 rec_enable_button->show();
201 rec_enable_button->set_controllable (t->rec_enable_control());
203 update_rec_display ();
206 mute_button->unset_flags (Gtk::CAN_FOCUS);
207 solo_button->unset_flags (Gtk::CAN_FOCUS);
211 if (_route->is_master()) {
212 solo_button->hide ();
217 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
219 /* map the current state */
228 RouteUI::mute_press(GdkEventButton* ev)
230 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
233 multiple_mute_change = false;
234 if (!ignore_toggle) {
236 if (Keyboard::is_context_menu_event (ev)) {
242 mute_menu->popup(0,ev->time);
246 if (Keyboard::is_button2_event (ev)) {
247 // Primary-button2 click is the midi binding click
248 // button2-click is "momentary"
250 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
251 wait_for_release = true;
257 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
259 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
261 /* Primary-Tertiary-click applies change to all routes */
263 _session.begin_reversible_command (_("mute change"));
264 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
265 _session.set_all_mute (!_route->muted());
267 _session.add_command(cmd);
268 _session.commit_reversible_command ();
269 multiple_mute_change = true;
271 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
273 /* Primary-button1 applies change to the mix group.
274 NOTE: Primary-button2 is MIDI learn.
277 if (ev->button == 1) {
278 set_route_group_mute (_route, !_route->muted());
283 /* plain click applies change to this route */
284 if (wait_for_release) {
285 _route->set_mute (!_route->muted(), this);
287 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
299 RouteUI::mute_release(GdkEventButton* ev)
301 if (!ignore_toggle) {
302 if (wait_for_release){
303 wait_for_release = false;
304 if (multiple_mute_change) {
305 multiple_mute_change = false;
307 // because the press was the last undoable thing we did
310 _route->set_mute (!_route->muted(), this);
318 RouteUI::solo_press(GdkEventButton* ev)
320 /* ignore double/triple clicks */
322 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
325 multiple_solo_change = false;
326 if (!ignore_toggle) {
328 if (Keyboard::is_context_menu_event (ev)) {
330 if (solo_menu == 0) {
334 solo_menu->popup (1, ev->time);
338 if (Keyboard::is_button2_event (ev)) {
340 // Primary-button2 click is the midi binding click
341 // button2-click is "momentary"
343 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
344 wait_for_release = true;
350 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
352 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
354 /* Primary-Tertiary-click applies change to all routes */
355 bool was_not_latched = false;
356 if (!Config->get_solo_latched ()) {
357 was_not_latched = true;
359 XXX it makes no sense to solo all tracks if we're
360 not in latched mode, but doing nothing feels like a bug,
363 Config->set_solo_latched (true);
365 _session.begin_reversible_command (_("solo change"));
366 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
367 _session.set_all_solo (!_route->soloed());
369 _session.add_command (cmd);
370 _session.commit_reversible_command ();
371 multiple_solo_change = true;
372 if (was_not_latched) {
373 Config->set_solo_latched (false);
376 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
378 // Primary-Secondary-click: exclusively solo this track, not a toggle */
380 _session.begin_reversible_command (_("solo change"));
381 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
382 _session.set_all_solo (false);
383 _route->set_solo (true, this);
385 _session.add_command(cmd);
386 _session.commit_reversible_command ();
388 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
390 // shift-click: set this route to solo safe
392 if (Profile->get_sae() && ev->button == 1) {
393 // button 1 and shift-click: disables solo_latched for this click
394 if (!Config->get_solo_latched ()) {
395 Config->set_solo_latched (true);
396 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
397 Config->set_solo_latched (false);
400 _route->set_solo_isolated (!_route->solo_isolated(), this);
401 wait_for_release = false;
404 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
406 /* Primary-button1: solo mix group.
407 NOTE: Primary-button2 is MIDI learn.
410 if (ev->button == 1) {
411 set_route_group_solo (_route, !_route->soloed());
416 /* click: solo this route */
417 if (wait_for_release) {
418 _route->set_solo (!_route->soloed(), this);
420 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
431 RouteUI::solo_release(GdkEventButton* ev)
433 if (!ignore_toggle) {
434 if (wait_for_release) {
435 wait_for_release = false;
436 if (multiple_solo_change) {
437 multiple_solo_change = false;
439 // because the press was the last undoable thing we did
442 // we don't use "undo the last op"
443 // here because its expensive for the GUI
444 _route->set_solo (!_route->soloed(), this);
453 RouteUI::rec_enable_press(GdkEventButton* ev)
455 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
459 if (!_session.engine().connected()) {
460 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
465 if (!ignore_toggle && is_track() && rec_enable_button) {
467 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
469 // do nothing on midi bind event
472 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
474 _session.begin_reversible_command (_("rec-enable change"));
475 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
477 if (rec_enable_button->get_active()) {
478 _session.record_disenable_all ();
480 _session.record_enable_all ();
481 check_rec_enable_sensitivity ();
485 _session.add_command(cmd);
486 _session.commit_reversible_command ();
488 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
490 /* Primary-button1 applies change to the mix group.
491 NOTE: Primary-button2 is MIDI learn.
494 set_route_group_rec_enable (_route, !_route->record_enabled());
497 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
498 check_rec_enable_sensitivity ();
506 RouteUI::rec_enable_release (GdkEventButton* ev)
512 RouteUI::build_sends_menu ()
514 using namespace Menu_Helpers;
516 sends_menu = new Menu;
517 sends_menu->set_name ("ArdourContextMenu");
518 MenuList& items = sends_menu->items();
520 items.push_back (MenuElem(_("Assign all tracks"), mem_fun (*this, &RouteUI::create_sends)));
521 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
522 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
523 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
528 RouteUI::create_sends ()
530 _session.globally_add_internal_sends (_route);
534 RouteUI::set_sends_gain_from_track ()
539 RouteUI::set_sends_gain_to_zero ()
544 RouteUI::set_sends_gain_to_unity ()
549 RouteUI::show_sends_press(GdkEventButton* ev)
551 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
555 if (!ignore_toggle && !is_track() && show_sends_button) {
557 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
559 // do nothing on midi bind event
562 } else if (Keyboard::is_context_menu_event (ev)) {
564 if (sends_menu == 0) {
568 sends_menu->popup (0, ev->time);
572 /* change button state */
574 show_sends_button->set_active (!show_sends_button->get_active());
578 if (show_sends_button->get_active()) {
579 /* show sends to this bus */
580 MixerStrip::SwitchIO (_route);
581 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
583 /* everybody back to normal */
584 send_blink_connection.disconnect ();
585 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
595 RouteUI::show_sends_release (GdkEventButton* ev)
601 RouteUI::send_blink (bool onoff)
603 if (!show_sends_button) {
608 show_sends_button->set_state (STATE_ACTIVE);
610 show_sends_button->set_state (STATE_NORMAL);
615 RouteUI::solo_changed(void* src)
618 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
622 RouteUI::update_solo_display ()
625 vector<Gdk::Color> fg_colors;
628 if (solo_button->get_active() != (x = _route->soloed())){
629 ignore_toggle = true;
630 solo_button->set_active(x);
631 ignore_toggle = false;
634 if (_route->solo_isolated()) {
635 solo_button->set_visual_state (2);
636 } else if (_route->soloed()) {
637 solo_button->set_visual_state (1);
639 solo_button->set_visual_state (0);
644 RouteUI::solo_changed_so_update_mute ()
646 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
650 RouteUI::mute_changed(void* src)
652 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
656 RouteUI::update_mute_display ()
658 bool model = _route->muted();
659 bool view = mute_button->get_active();
661 /* first make sure the button's "depressed" visual
666 ignore_toggle = true;
667 mute_button->set_active (model);
668 ignore_toggle = false;
671 /* now attend to visual state */
673 if (Config->get_show_solo_mutes()) {
674 if (_route->muted()) {
675 mute_button->set_visual_state (2);
676 } else if (!_route->soloed() && _session.soloing()) {
677 mute_button->set_visual_state (1);
679 mute_button->set_visual_state (0);
682 if (_route->muted()) {
683 mute_button->set_visual_state (2);
685 mute_button->set_visual_state (0);
692 RouteUI::route_rec_enable_changed ()
694 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
698 RouteUI::session_rec_enable_changed ()
700 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
704 RouteUI::update_rec_display ()
706 bool model = _route->record_enabled();
707 bool view = rec_enable_button->get_active();
709 /* first make sure the button's "depressed" visual
714 ignore_toggle = true;
715 rec_enable_button->set_active (model);
716 ignore_toggle = false;
722 /* now make sure its color state is correct */
726 switch (_session.record_status ()) {
727 case Session::Recording:
728 rec_enable_button->set_visual_state (1);
731 case Session::Disabled:
732 case Session::Enabled:
733 rec_enable_button->set_visual_state (2);
739 rec_enable_button->set_visual_state (0);
744 RouteUI::build_remote_control_menu ()
746 remote_control_menu = new Menu;
747 refresh_remote_control_menu ();
751 RouteUI::refresh_remote_control_menu ()
753 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
755 // only refresh the menu if it has been instantiated
757 if (remote_control_menu == 0) {
761 using namespace Menu_Helpers;
763 RadioMenuItem::Group rc_group;
764 CheckMenuItem* rc_active;
765 uint32_t limit = _session.ntracks() + _session.nbusses();
768 MenuList& rc_items = remote_control_menu->items();
771 /* note that this menu list starts at zero, not 1, because zero
772 is a valid, if useless, ID.
775 limit += 4; /* leave some breathing room */
777 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
778 if (_route->remote_control_id() == 0) {
779 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
780 rc_active->set_active ();
783 for (uint32_t i = 1; i < limit; ++i) {
784 snprintf (buf, sizeof (buf), "%u", i);
785 rc_items.push_back (RadioMenuElem (rc_group, buf));
786 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
787 if (_route->remote_control_id() == i) {
788 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
789 rc_active->set_active ();
791 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
796 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
798 /* this is called when the radio menu item is toggled, and so
799 is actually invoked twice per menu selection. we only
800 care about the invocation for the item that was being
804 if (item->get_active()) {
805 _route->set_remote_control_id (id);
810 RouteUI::build_solo_menu (void)
812 using namespace Menu_Helpers;
814 solo_menu = new Menu;
815 solo_menu->set_name ("ArdourContextMenu");
816 MenuList& items = solo_menu->items();
817 CheckMenuItem* check;
819 check = new CheckMenuItem(_("Solo Isolate"));
820 check->set_active (_route->solo_isolated());
821 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
822 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
823 items.push_back (CheckMenuElem(*check));
826 //items.push_back (SeparatorElem());
827 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
832 RouteUI::build_mute_menu(void)
834 using namespace Menu_Helpers;
836 mute_menu = new Menu;
837 mute_menu->set_name ("ArdourContextMenu");
840 MenuList& items = mute_menu->items();
841 CheckMenuItem* check;
843 check = new CheckMenuItem(_("Pre Fader"));
844 init_mute_menu(PRE_FADER, check);
845 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
846 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
847 items.push_back (CheckMenuElem(*check));
850 check = new CheckMenuItem(_("Post Fader"));
851 init_mute_menu(POST_FADER, check);
852 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
853 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
854 items.push_back (CheckMenuElem(*check));
857 check = new CheckMenuItem(_("Control Outs"));
858 init_mute_menu(CONTROL_OUTS, check);
859 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
860 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
861 items.push_back (CheckMenuElem(*check));
864 check = new CheckMenuItem(_("Main Outs"));
865 init_mute_menu(MAIN_OUTS, check);
866 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
867 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
868 items.push_back (CheckMenuElem(*check));
871 //items.push_back (SeparatorElem());
872 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
876 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
878 check->set_active (_route->mute_master()->muted_at (mp));
882 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
884 // _route->set_mute_config(type, check->get_active(), this);
888 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
890 _route->set_solo_isolated (check->get_active(), this);
894 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
896 RouteGroup* route_group;
898 if((route_group = route->route_group()) != 0){
899 _session.begin_reversible_command (_("mix group solo change"));
900 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
901 route_group->apply(&Route::set_solo, yn, this);
903 _session.add_command (cmd);
904 _session.commit_reversible_command ();
906 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
911 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
913 _session.begin_reversible_command (name);
914 XMLNode &before = _route->get_state();
915 bind(mem_fun(*_route, func), yn, arg)();
916 XMLNode &after = _route->get_state();
917 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
918 _session.commit_reversible_command ();
922 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
924 _session.begin_reversible_command (name);
925 XMLNode &before = track()->get_state();
926 bind (mem_fun (*track(), func), yn, arg)();
927 XMLNode &after = track()->get_state();
928 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
929 _session.commit_reversible_command ();
933 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
935 RouteGroup* route_group;
937 if((route_group = route->route_group()) != 0){
938 _session.begin_reversible_command (_("mix group mute change"));
939 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
940 route_group->apply(&Route::set_mute, yn, this);
942 _session.add_command(cmd);
943 _session.commit_reversible_command ();
945 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
950 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
952 RouteGroup* route_group;
954 if((route_group = route->route_group()) != 0){
955 _session.begin_reversible_command (_("mix group rec-enable change"));
956 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
957 route_group->apply (&Route::set_record_enable, yn, this);
959 _session.add_command(cmd);
960 _session.commit_reversible_command ();
962 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
968 RouteUI::choose_color()
973 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
983 RouteUI::set_color (const Gdk::Color & c)
990 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
991 xml_node->add_property ("color", buf);
993 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
998 RouteUI::ensure_xml_node ()
1000 if (xml_node == 0) {
1001 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1002 xml_node = new XMLNode ("GUI");
1003 _route->add_extra_xml (*xml_node);
1009 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1013 XMLNodeList kids = xml_node->children();
1014 XMLNodeConstIterator iter;
1016 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1018 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1019 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1020 XMLProperty* type = (*iter)->property("automation-id");
1021 if (type && type->value() == sym)
1026 // Didn't find it, make a new one
1027 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1028 child->add_property("automation-id", sym);
1029 xml_node->add_child_nocopy (*child);
1035 RouteUI::set_color_from_route ()
1039 RouteUI::ensure_xml_node ();
1041 if ((prop = xml_node->property ("color")) != 0) {
1043 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1045 _color.set_green(g);
1053 RouteUI::remove_this_route ()
1055 vector<string> choices;
1059 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());
1061 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1064 choices.push_back (_("No, do nothing."));
1065 choices.push_back (_("Yes, remove it."));
1067 Choice prompter (prompt, choices);
1069 if (prompter.run () == 1) {
1070 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1075 RouteUI::idle_remove_this_route (RouteUI *rui)
1077 rui->_session.remove_route (rui->_route);
1082 RouteUI::route_rename ()
1084 ArdourPrompter name_prompter (true);
1086 name_prompter.set_prompt (_("New Name: "));
1087 name_prompter.set_initial_text (_route->name());
1088 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1089 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1090 name_prompter.show_all ();
1092 switch (name_prompter.run ()) {
1094 case Gtk::RESPONSE_ACCEPT:
1095 name_prompter.get_result (result);
1096 if (result.length()) {
1097 _route->set_name (result);
1107 RouteUI::name_changed ()
1109 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1111 name_label.set_text (_route->name());
1115 RouteUI::toggle_route_active ()
1119 if (route_active_menu_item) {
1120 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1121 _route->set_active (!yn);
1127 RouteUI::route_active_changed ()
1129 if (route_active_menu_item) {
1130 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1135 RouteUI::toggle_polarity ()
1137 if (polarity_menu_item) {
1141 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1143 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1144 _route->set_phase_invert (x);
1146 name_label.set_text (X_("Ø ") + name_label.get_text());
1148 name_label.set_text (_route->name());
1155 RouteUI::polarity_changed ()
1157 if (_route->phase_invert()) {
1158 name_label.set_text (X_("Ø ") + name_label.get_text());
1160 name_label.set_text (_route->name());
1165 RouteUI::toggle_denormal_protection ()
1167 if (denormal_menu_item) {
1171 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1173 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1174 _route->set_denormal_protection (x);
1180 RouteUI::denormal_protection_changed ()
1182 if (denormal_menu_item) {
1183 denormal_menu_item->set_active (_route->denormal_protection());
1188 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1190 bool yn = _route->solo_isolated ();
1192 if (check->get_active() != yn) {
1193 check->set_active (yn);
1197 #ifdef FIX_THIS_FOR_3_0
1199 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1201 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1203 bool yn = _route->get_mute_config(PRE_FADER);
1204 if (check->get_active() != yn) {
1205 check->set_active (yn);
1210 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1212 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1214 bool yn = _route->get_mute_config(POST_FADER);
1215 if (check->get_active() != yn) {
1216 check->set_active (yn);
1221 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1223 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1225 bool yn = _route->get_mute_config(CONTROL_OUTS);
1226 if (check->get_active() != yn) {
1227 check->set_active (yn);
1232 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1234 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1236 bool yn = _route->get_mute_config(MAIN_OUTS);
1237 if (check->get_active() != yn) {
1238 check->set_active (yn);
1244 RouteUI::disconnect_input ()
1246 _route->input()->disconnect (this);
1250 RouteUI::disconnect_output ()
1252 _route->output()->disconnect (this);
1256 RouteUI::is_track () const
1258 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1261 boost::shared_ptr<Track>
1262 RouteUI::track() const
1264 return boost::dynamic_pointer_cast<Track>(_route);
1268 RouteUI::is_audio_track () const
1270 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1273 boost::shared_ptr<AudioTrack>
1274 RouteUI::audio_track() const
1276 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1280 RouteUI::is_midi_track () const
1282 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1285 boost::shared_ptr<MidiTrack>
1286 RouteUI::midi_track() const
1288 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1291 boost::shared_ptr<Diskstream>
1292 RouteUI::get_diskstream () const
1294 boost::shared_ptr<Track> t;
1296 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1297 return t->diskstream();
1299 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1304 RouteUI::name() const
1306 return _route->name();
1310 RouteUI::map_frozen ()
1312 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1314 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1317 switch (at->freeze_state()) {
1318 case AudioTrack::Frozen:
1319 rec_enable_button->set_sensitive (false);
1322 rec_enable_button->set_sensitive (true);
1329 RouteUI::adjust_latency ()
1331 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1335 RouteUI::save_as_template ()
1338 Glib::ustring safe_name;
1341 path = ARDOUR::user_route_template_directory ();
1343 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1344 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1348 Prompter p (true); // modal
1350 p.set_prompt (_("Template name:"));
1352 case RESPONSE_ACCEPT:
1359 p.get_result (name, true);
1361 safe_name = legalize_for_path (name);
1362 safe_name += template_suffix;
1366 _route->save_as_template (path.to_string(), name);
1370 RouteUI::check_rec_enable_sensitivity ()
1372 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1373 rec_enable_button->set_sensitive (false);
1375 rec_enable_button->set_sensitive (true);
1380 RouteUI::parameter_changed (string const & p)
1382 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1384 if (p == "disable-disarm-during-roll") {
1385 check_rec_enable_sensitivity ();
1386 } else if (p == "solo-model") {
1387 set_button_names ();