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 (_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_control()) {
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 ) {
326 if (Config->get_solo_control_is_listen_control()) {
328 _route->set_listen (!_route->listening(), this);
332 multiple_solo_change = false;
333 if (!ignore_toggle) {
335 if (Keyboard::is_context_menu_event (ev)) {
337 if (solo_menu == 0) {
341 solo_menu->popup (1, ev->time);
345 if (Keyboard::is_button2_event (ev)) {
347 // Primary-button2 click is the midi binding click
348 // button2-click is "momentary"
350 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
351 wait_for_release = true;
357 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
359 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
361 /* Primary-Tertiary-click applies change to all routes */
362 bool was_not_latched = false;
363 if (!Config->get_solo_latched ()) {
364 was_not_latched = true;
366 XXX it makes no sense to solo all tracks if we're
367 not in latched mode, but doing nothing feels like a bug,
370 Config->set_solo_latched (true);
372 _session.begin_reversible_command (_("solo change"));
373 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
374 _session.set_all_solo (!_route->soloed());
376 _session.add_command (cmd);
377 _session.commit_reversible_command ();
378 multiple_solo_change = true;
379 if (was_not_latched) {
380 Config->set_solo_latched (false);
383 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
385 // Primary-Secondary-click: exclusively solo this track, not a toggle */
387 _session.begin_reversible_command (_("solo change"));
388 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
389 _session.set_all_solo (false);
390 _route->set_solo (true, this);
392 _session.add_command(cmd);
393 _session.commit_reversible_command ();
395 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
397 // shift-click: set this route to solo safe
399 if (Profile->get_sae() && ev->button == 1) {
400 // button 1 and shift-click: disables solo_latched for this click
401 if (!Config->get_solo_latched ()) {
402 Config->set_solo_latched (true);
403 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
404 Config->set_solo_latched (false);
407 _route->set_solo_isolated (!_route->solo_isolated(), this);
408 wait_for_release = false;
411 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
413 /* Primary-button1: solo mix group.
414 NOTE: Primary-button2 is MIDI learn.
417 if (ev->button == 1) {
418 set_route_group_solo (_route, !_route->soloed());
423 /* click: solo this route */
424 if (wait_for_release) {
425 _route->set_solo (!_route->soloed(), this);
427 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
439 RouteUI::solo_release(GdkEventButton* ev)
441 if (!ignore_toggle) {
442 if (wait_for_release) {
443 wait_for_release = false;
444 if (multiple_solo_change) {
445 multiple_solo_change = false;
447 // because the press was the last undoable thing we did
450 // we don't use "undo the last op"
451 // here because its expensive for the GUI
452 _route->set_solo (!_route->soloed(), this);
461 RouteUI::rec_enable_press(GdkEventButton* ev)
463 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
467 if (!_session.engine().connected()) {
468 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
473 if (!ignore_toggle && is_track() && rec_enable_button) {
475 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
477 // do nothing on midi bind event
480 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
482 _session.begin_reversible_command (_("rec-enable change"));
483 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
485 if (rec_enable_button->get_active()) {
486 _session.record_disenable_all ();
488 _session.record_enable_all ();
489 check_rec_enable_sensitivity ();
493 _session.add_command(cmd);
494 _session.commit_reversible_command ();
496 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
498 /* Primary-button1 applies change to the mix group.
499 NOTE: Primary-button2 is MIDI learn.
502 set_route_group_rec_enable (_route, !_route->record_enabled());
505 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
506 check_rec_enable_sensitivity ();
514 RouteUI::rec_enable_release (GdkEventButton* ev)
520 RouteUI::build_sends_menu ()
522 using namespace Menu_Helpers;
524 sends_menu = new Menu;
525 sends_menu->set_name ("ArdourContextMenu");
526 MenuList& items = sends_menu->items();
528 items.push_back (MenuElem(_("Assign all tracks"), mem_fun (*this, &RouteUI::create_sends)));
529 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
530 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
531 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
536 RouteUI::create_sends ()
538 _session.globally_add_internal_sends (_route);
542 RouteUI::set_sends_gain_from_track ()
547 RouteUI::set_sends_gain_to_zero ()
552 RouteUI::set_sends_gain_to_unity ()
557 RouteUI::show_sends_press(GdkEventButton* ev)
559 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
563 if (!ignore_toggle && !is_track() && show_sends_button) {
565 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
567 // do nothing on midi bind event
570 } else if (Keyboard::is_context_menu_event (ev)) {
572 if (sends_menu == 0) {
576 sends_menu->popup (0, ev->time);
580 /* change button state */
582 show_sends_button->set_active (!show_sends_button->get_active());
586 if (show_sends_button->get_active()) {
587 /* show sends to this bus */
588 MixerStrip::SwitchIO (_route);
589 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
591 /* everybody back to normal */
592 send_blink_connection.disconnect ();
593 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
603 RouteUI::show_sends_release (GdkEventButton* ev)
609 RouteUI::send_blink (bool onoff)
611 if (!show_sends_button) {
616 show_sends_button->set_state (STATE_ACTIVE);
618 show_sends_button->set_state (STATE_NORMAL);
623 RouteUI::solo_changed(void* src)
625 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
630 RouteUI::listen_changed(void* src)
632 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
636 RouteUI::update_solo_display ()
640 if (Config->get_solo_control_is_listen_control()) {
642 if (solo_button->get_active() != (x = _route->listening())) {
643 ignore_toggle = true;
644 solo_button->set_active(x);
645 ignore_toggle = false;
649 solo_button->set_visual_state (1);
651 solo_button->set_visual_state (0);
657 if (solo_button->get_active() != (x = _route->soloed())){
658 ignore_toggle = true;
659 solo_button->set_active (x);
660 ignore_toggle = false;
663 if (_route->solo_isolated()) {
664 solo_button->set_visual_state (2);
666 solo_button->set_visual_state (1);
668 solo_button->set_visual_state (0);
674 RouteUI::solo_changed_so_update_mute ()
676 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
680 RouteUI::mute_changed(void* src)
682 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
686 RouteUI::update_mute_display ()
688 bool model = _route->muted();
689 bool view = mute_button->get_active();
691 /* first make sure the button's "depressed" visual
696 ignore_toggle = true;
697 mute_button->set_active (model);
698 ignore_toggle = false;
701 /* now attend to visual state */
703 if (Config->get_show_solo_mutes()) {
704 if (_route->muted()) {
705 mute_button->set_visual_state (2);
706 } else if (!_route->soloed() && _session.soloing()) {
707 mute_button->set_visual_state (1);
709 mute_button->set_visual_state (0);
712 if (_route->muted()) {
713 mute_button->set_visual_state (2);
715 mute_button->set_visual_state (0);
722 RouteUI::route_rec_enable_changed ()
724 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
728 RouteUI::session_rec_enable_changed ()
730 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
734 RouteUI::update_rec_display ()
736 bool model = _route->record_enabled();
737 bool view = rec_enable_button->get_active();
739 /* first make sure the button's "depressed" visual
744 ignore_toggle = true;
745 rec_enable_button->set_active (model);
746 ignore_toggle = false;
752 /* now make sure its color state is correct */
756 switch (_session.record_status ()) {
757 case Session::Recording:
758 rec_enable_button->set_visual_state (1);
761 case Session::Disabled:
762 case Session::Enabled:
763 rec_enable_button->set_visual_state (2);
769 rec_enable_button->set_visual_state (0);
774 RouteUI::build_remote_control_menu ()
776 remote_control_menu = new Menu;
777 refresh_remote_control_menu ();
781 RouteUI::refresh_remote_control_menu ()
783 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
785 // only refresh the menu if it has been instantiated
787 if (remote_control_menu == 0) {
791 using namespace Menu_Helpers;
793 RadioMenuItem::Group rc_group;
794 CheckMenuItem* rc_active;
795 uint32_t limit = _session.ntracks() + _session.nbusses();
798 MenuList& rc_items = remote_control_menu->items();
801 /* note that this menu list starts at zero, not 1, because zero
802 is a valid, if useless, ID.
805 limit += 4; /* leave some breathing room */
807 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
808 if (_route->remote_control_id() == 0) {
809 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
810 rc_active->set_active ();
813 for (uint32_t i = 1; i < limit; ++i) {
814 snprintf (buf, sizeof (buf), "%u", i);
815 rc_items.push_back (RadioMenuElem (rc_group, buf));
816 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
817 if (_route->remote_control_id() == i) {
818 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
819 rc_active->set_active ();
821 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
826 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
828 /* this is called when the radio menu item is toggled, and so
829 is actually invoked twice per menu selection. we only
830 care about the invocation for the item that was being
834 if (item->get_active()) {
835 _route->set_remote_control_id (id);
840 RouteUI::build_solo_menu (void)
842 using namespace Menu_Helpers;
844 solo_menu = new Menu;
845 solo_menu->set_name ("ArdourContextMenu");
846 MenuList& items = solo_menu->items();
847 CheckMenuItem* check;
849 check = new CheckMenuItem(_("Solo Isolate"));
850 check->set_active (_route->solo_isolated());
851 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
852 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
853 items.push_back (CheckMenuElem(*check));
856 //items.push_back (SeparatorElem());
857 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
862 RouteUI::build_mute_menu(void)
864 using namespace Menu_Helpers;
866 mute_menu = new Menu;
867 mute_menu->set_name ("ArdourContextMenu");
870 MenuList& items = mute_menu->items();
871 CheckMenuItem* check;
873 check = new CheckMenuItem(_("Pre Fader"));
874 init_mute_menu(PRE_FADER, check);
875 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
876 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
877 items.push_back (CheckMenuElem(*check));
880 check = new CheckMenuItem(_("Post Fader"));
881 init_mute_menu(POST_FADER, check);
882 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
883 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
884 items.push_back (CheckMenuElem(*check));
887 check = new CheckMenuItem(_("Control Outs"));
888 init_mute_menu(CONTROL_OUTS, check);
889 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
890 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
891 items.push_back (CheckMenuElem(*check));
894 check = new CheckMenuItem(_("Main Outs"));
895 init_mute_menu(MAIN_OUTS, check);
896 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
897 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
898 items.push_back (CheckMenuElem(*check));
901 //items.push_back (SeparatorElem());
902 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
906 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
908 check->set_active (_route->mute_master()->muted_at (mp));
912 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
914 // _route->set_mute_config(type, check->get_active(), this);
918 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
920 _route->set_solo_isolated (check->get_active(), this);
924 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
926 RouteGroup* route_group;
928 if((route_group = route->route_group()) != 0){
929 _session.begin_reversible_command (_("mix group solo change"));
930 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
931 route_group->apply(&Route::set_solo, yn, this);
933 _session.add_command (cmd);
934 _session.commit_reversible_command ();
936 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
941 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
943 _session.begin_reversible_command (name);
944 XMLNode &before = _route->get_state();
945 bind(mem_fun(*_route, func), yn, arg)();
946 XMLNode &after = _route->get_state();
947 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
948 _session.commit_reversible_command ();
952 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
954 _session.begin_reversible_command (name);
955 XMLNode &before = track()->get_state();
956 bind (mem_fun (*track(), func), yn, arg)();
957 XMLNode &after = track()->get_state();
958 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
959 _session.commit_reversible_command ();
963 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
965 RouteGroup* route_group;
967 if((route_group = route->route_group()) != 0){
968 _session.begin_reversible_command (_("mix group mute change"));
969 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
970 route_group->apply(&Route::set_mute, yn, this);
972 _session.add_command(cmd);
973 _session.commit_reversible_command ();
975 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
980 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
982 RouteGroup* route_group;
984 if((route_group = route->route_group()) != 0){
985 _session.begin_reversible_command (_("mix group rec-enable change"));
986 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
987 route_group->apply (&Route::set_record_enable, yn, this);
989 _session.add_command(cmd);
990 _session.commit_reversible_command ();
992 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
998 RouteUI::choose_color()
1003 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1013 RouteUI::set_color (const Gdk::Color & c)
1020 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1021 xml_node->add_property ("color", buf);
1023 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1028 RouteUI::ensure_xml_node ()
1030 if (xml_node == 0) {
1031 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1032 xml_node = new XMLNode ("GUI");
1033 _route->add_extra_xml (*xml_node);
1039 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1043 XMLNodeList kids = xml_node->children();
1044 XMLNodeConstIterator iter;
1046 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1048 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1049 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1050 XMLProperty* type = (*iter)->property("automation-id");
1051 if (type && type->value() == sym)
1056 // Didn't find it, make a new one
1057 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1058 child->add_property("automation-id", sym);
1059 xml_node->add_child_nocopy (*child);
1065 RouteUI::set_color_from_route ()
1069 RouteUI::ensure_xml_node ();
1071 if ((prop = xml_node->property ("color")) != 0) {
1073 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1075 _color.set_green(g);
1083 RouteUI::remove_this_route ()
1085 vector<string> choices;
1089 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());
1091 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1094 choices.push_back (_("No, do nothing."));
1095 choices.push_back (_("Yes, remove it."));
1097 Choice prompter (prompt, choices);
1099 if (prompter.run () == 1) {
1100 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1105 RouteUI::idle_remove_this_route (RouteUI *rui)
1107 rui->_session.remove_route (rui->_route);
1112 RouteUI::route_rename ()
1114 ArdourPrompter name_prompter (true);
1116 name_prompter.set_prompt (_("New Name: "));
1117 name_prompter.set_initial_text (_route->name());
1118 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1119 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1120 name_prompter.show_all ();
1122 switch (name_prompter.run ()) {
1124 case Gtk::RESPONSE_ACCEPT:
1125 name_prompter.get_result (result);
1126 if (result.length()) {
1127 _route->set_name (result);
1137 RouteUI::name_changed ()
1139 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1141 name_label.set_text (_route->name());
1145 RouteUI::toggle_route_active ()
1149 if (route_active_menu_item) {
1150 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1151 _route->set_active (!yn);
1157 RouteUI::route_active_changed ()
1159 if (route_active_menu_item) {
1160 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1165 RouteUI::toggle_polarity ()
1167 if (polarity_menu_item) {
1171 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1173 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1174 _route->set_phase_invert (x);
1176 name_label.set_text (X_("Ø ") + name_label.get_text());
1178 name_label.set_text (_route->name());
1185 RouteUI::polarity_changed ()
1187 if (_route->phase_invert()) {
1188 name_label.set_text (X_("Ø ") + name_label.get_text());
1190 name_label.set_text (_route->name());
1195 RouteUI::toggle_denormal_protection ()
1197 if (denormal_menu_item) {
1201 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1203 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1204 _route->set_denormal_protection (x);
1210 RouteUI::denormal_protection_changed ()
1212 if (denormal_menu_item) {
1213 denormal_menu_item->set_active (_route->denormal_protection());
1218 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1220 bool yn = _route->solo_isolated ();
1222 if (check->get_active() != yn) {
1223 check->set_active (yn);
1227 #ifdef FIX_THIS_FOR_3_0
1229 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1231 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1233 bool yn = _route->get_mute_config(PRE_FADER);
1234 if (check->get_active() != yn) {
1235 check->set_active (yn);
1240 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1242 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1244 bool yn = _route->get_mute_config(POST_FADER);
1245 if (check->get_active() != yn) {
1246 check->set_active (yn);
1251 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1253 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1255 bool yn = _route->get_mute_config(CONTROL_OUTS);
1256 if (check->get_active() != yn) {
1257 check->set_active (yn);
1262 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1264 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1266 bool yn = _route->get_mute_config(MAIN_OUTS);
1267 if (check->get_active() != yn) {
1268 check->set_active (yn);
1274 RouteUI::disconnect_input ()
1276 _route->input()->disconnect (this);
1280 RouteUI::disconnect_output ()
1282 _route->output()->disconnect (this);
1286 RouteUI::is_track () const
1288 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1291 boost::shared_ptr<Track>
1292 RouteUI::track() const
1294 return boost::dynamic_pointer_cast<Track>(_route);
1298 RouteUI::is_audio_track () const
1300 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1303 boost::shared_ptr<AudioTrack>
1304 RouteUI::audio_track() const
1306 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1310 RouteUI::is_midi_track () const
1312 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1315 boost::shared_ptr<MidiTrack>
1316 RouteUI::midi_track() const
1318 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1321 boost::shared_ptr<Diskstream>
1322 RouteUI::get_diskstream () const
1324 boost::shared_ptr<Track> t;
1326 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1327 return t->diskstream();
1329 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1334 RouteUI::name() const
1336 return _route->name();
1340 RouteUI::map_frozen ()
1342 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1344 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1347 switch (at->freeze_state()) {
1348 case AudioTrack::Frozen:
1349 rec_enable_button->set_sensitive (false);
1352 rec_enable_button->set_sensitive (true);
1359 RouteUI::adjust_latency ()
1361 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1365 RouteUI::save_as_template ()
1368 Glib::ustring safe_name;
1371 path = ARDOUR::user_route_template_directory ();
1373 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1374 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1378 Prompter p (true); // modal
1380 p.set_prompt (_("Template name:"));
1382 case RESPONSE_ACCEPT:
1389 p.get_result (name, true);
1391 safe_name = legalize_for_path (name);
1392 safe_name += template_suffix;
1396 _route->save_as_template (path.to_string(), name);
1400 RouteUI::check_rec_enable_sensitivity ()
1402 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1403 rec_enable_button->set_sensitive (false);
1405 rec_enable_button->set_sensitive (true);
1410 RouteUI::parameter_changed (string const & p)
1412 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1414 if (p == "disable-disarm-during-roll") {
1415 check_rec_enable_sensitivity ();
1416 } else if (p == "solo-control-is-listen-control") {
1417 set_button_names ();
1418 } else if (p == "listen-position") {
1419 set_button_names ();