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 "ardour/dB.h"
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/shiva.h"
33 #include "pbd/controllable.h"
35 #include "ardour_ui.h"
41 #include "gui_thread.h"
42 #include "ardour_dialog.h"
43 #include "latency_gui.h"
44 #include "mixer_strip.h"
45 #include "automation_time_axis.h"
47 #include "ardour/route.h"
48 #include "ardour/session.h"
49 #include "ardour/audioengine.h"
50 #include "ardour/audio_track.h"
51 #include "ardour/audio_diskstream.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/midi_diskstream.h"
54 #include "ardour/template_utils.h"
55 #include "ardour/filename_extensions.h"
56 #include "ardour/directory_names.h"
57 #include "ardour/profile.h"
62 using namespace Gtkmm2ext;
63 using namespace ARDOUR;
66 RouteUI::RouteUI (ARDOUR::Session& sess)
72 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess)
81 /* derived classes should emit GoingAway so that they receive the signal
82 when the object is still a legal derived instance.
87 delete remote_control_menu;
98 remote_control_menu = 0;
100 ignore_toggle = false;
101 wait_for_release = false;
102 route_active_menu_item = 0;
103 polarity_menu_item = 0;
104 denormal_menu_item = 0;
105 multiple_mute_change = false;
106 multiple_solo_change = false;
108 mute_button = manage (new BindableToggleButton ());
109 mute_button->set_self_managed (true);
110 mute_button->set_name ("MuteButton");
111 mute_button->add (mute_button_label);
112 mute_button_label.show ();
113 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
115 solo_button = manage (new BindableToggleButton ());
116 solo_button->set_self_managed (true);
117 solo_button->set_name ("SoloButton");
118 solo_button->add (solo_button_label);
119 solo_button_label.show ();
120 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
121 solo_button->set_no_show_all (true);
123 rec_enable_button = manage (new BindableToggleButton ());
124 rec_enable_button->set_name ("RecordEnableButton");
125 rec_enable_button->set_self_managed (true);
126 rec_enable_button->add (rec_enable_button_label);
127 rec_enable_button_label.show ();
128 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
130 show_sends_button = manage (new BindableToggleButton (""));
131 show_sends_button->set_name ("SendAlert");
132 show_sends_button->set_self_managed (true);
133 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
135 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
136 _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
138 Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
144 //Remove route connections associated with us.
145 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
149 connections.clear ();
158 /* do not delete the node - its owned by the route */
162 route_active_menu_item = 0;
163 polarity_menu_item = 0;
164 denormal_menu_item = 0;
168 RouteUI::set_route (boost::shared_ptr<Route> rp)
174 if (set_color_from_route()) {
175 set_color (unique_random_color());
178 /* no, there is no memory leak here. This object cleans itself (and other stuff)
179 up when the route is destroyed.
183 new PairedShiva<Route,RouteUI> (*_route, *this);
186 mute_button->set_controllable (_route->mute_control());
187 solo_button->set_controllable (_route->solo_control());
189 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
190 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
191 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
192 connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed)));
193 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
196 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
198 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
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_control()) {
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 (prefader)"), bind (mem_fun (*this, &RouteUI::create_sends), PreFader)));
530 items.push_back (MenuElem(_("Assign all tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_sends), PostFader)));
531 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
532 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
533 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
538 RouteUI::create_sends (Placement p)
540 _session.globally_add_internal_sends (_route, p);
544 RouteUI::set_sends_gain_from_track ()
549 RouteUI::set_sends_gain_to_zero ()
554 RouteUI::set_sends_gain_to_unity ()
559 RouteUI::show_sends_press(GdkEventButton* ev)
561 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
565 if (!ignore_toggle && !is_track() && show_sends_button) {
567 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
569 // do nothing on midi bind event
572 } else if (Keyboard::is_context_menu_event (ev)) {
574 if (sends_menu == 0) {
578 sends_menu->popup (0, ev->time);
582 /* change button state */
584 show_sends_button->set_active (!show_sends_button->get_active());
588 if (show_sends_button->get_active()) {
589 /* show sends to this bus */
590 MixerStrip::SwitchIO (_route);
591 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
593 /* everybody back to normal */
594 send_blink_connection.disconnect ();
595 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
605 RouteUI::show_sends_release (GdkEventButton* ev)
611 RouteUI::send_blink (bool onoff)
613 if (!show_sends_button) {
618 show_sends_button->set_state (STATE_ACTIVE);
620 show_sends_button->set_state (STATE_NORMAL);
625 RouteUI::solo_changed(void* src)
627 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
632 RouteUI::listen_changed(void* src)
634 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
638 RouteUI::update_solo_display ()
642 if (Config->get_solo_control_is_listen_control()) {
644 if (solo_button->get_active() != (x = _route->listening())) {
645 ignore_toggle = true;
646 solo_button->set_active(x);
647 ignore_toggle = false;
651 solo_button->set_visual_state (1);
653 solo_button->set_visual_state (0);
659 if (solo_button->get_active() != (x = _route->soloed())){
660 ignore_toggle = true;
661 solo_button->set_active (x);
662 ignore_toggle = false;
665 if (_route->solo_isolated()) {
666 solo_button->set_visual_state (2);
668 solo_button->set_visual_state (1);
670 solo_button->set_visual_state (0);
676 RouteUI::solo_changed_so_update_mute ()
678 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
682 RouteUI::mute_changed(void* src)
684 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
688 RouteUI::update_mute_display ()
690 bool model = _route->muted();
691 bool view = mute_button->get_active();
693 /* first make sure the button's "depressed" visual
698 ignore_toggle = true;
699 mute_button->set_active (model);
700 ignore_toggle = false;
703 /* now attend to visual state */
705 if (Config->get_show_solo_mutes()) {
706 if (_route->muted()) {
707 mute_button->set_visual_state (2);
708 } else if (!_route->soloed() && _session.soloing()) {
709 mute_button->set_visual_state (1);
711 mute_button->set_visual_state (0);
714 if (_route->muted()) {
715 mute_button->set_visual_state (2);
717 mute_button->set_visual_state (0);
724 RouteUI::route_rec_enable_changed ()
726 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
730 RouteUI::session_rec_enable_changed ()
732 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
736 RouteUI::update_rec_display ()
738 bool model = _route->record_enabled();
739 bool view = rec_enable_button->get_active();
741 /* first make sure the button's "depressed" visual
746 ignore_toggle = true;
747 rec_enable_button->set_active (model);
748 ignore_toggle = false;
754 /* now make sure its color state is correct */
758 switch (_session.record_status ()) {
759 case Session::Recording:
760 rec_enable_button->set_visual_state (1);
763 case Session::Disabled:
764 case Session::Enabled:
765 rec_enable_button->set_visual_state (2);
771 rec_enable_button->set_visual_state (0);
776 RouteUI::build_remote_control_menu ()
778 remote_control_menu = new Menu;
779 refresh_remote_control_menu ();
783 RouteUI::refresh_remote_control_menu ()
785 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
787 // only refresh the menu if it has been instantiated
789 if (remote_control_menu == 0) {
793 using namespace Menu_Helpers;
795 RadioMenuItem::Group rc_group;
796 CheckMenuItem* rc_active;
797 uint32_t limit = _session.ntracks() + _session.nbusses();
800 MenuList& rc_items = remote_control_menu->items();
803 /* note that this menu list starts at zero, not 1, because zero
804 is a valid, if useless, ID.
807 limit += 4; /* leave some breathing room */
809 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
810 if (_route->remote_control_id() == 0) {
811 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
812 rc_active->set_active ();
815 for (uint32_t i = 1; i < limit; ++i) {
816 snprintf (buf, sizeof (buf), "%u", i);
817 rc_items.push_back (RadioMenuElem (rc_group, buf));
818 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
819 if (_route->remote_control_id() == i) {
820 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
821 rc_active->set_active ();
823 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
828 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
830 /* this is called when the radio menu item is toggled, and so
831 is actually invoked twice per menu selection. we only
832 care about the invocation for the item that was being
836 if (item->get_active()) {
837 _route->set_remote_control_id (id);
842 RouteUI::build_solo_menu (void)
844 using namespace Menu_Helpers;
846 solo_menu = new Menu;
847 solo_menu->set_name ("ArdourContextMenu");
848 MenuList& items = solo_menu->items();
849 CheckMenuItem* check;
851 check = new CheckMenuItem(_("Solo Isolate"));
852 check->set_active (_route->solo_isolated());
853 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
854 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
855 items.push_back (CheckMenuElem(*check));
858 //items.push_back (SeparatorElem());
859 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
864 RouteUI::build_mute_menu(void)
866 using namespace Menu_Helpers;
868 mute_menu = new Menu;
869 mute_menu->set_name ("ArdourContextMenu");
872 MenuList& items = mute_menu->items();
873 CheckMenuItem* check;
875 check = new CheckMenuItem(_("Pre Fader"));
876 init_mute_menu(PRE_FADER, check);
877 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
878 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
879 items.push_back (CheckMenuElem(*check));
882 check = new CheckMenuItem(_("Post Fader"));
883 init_mute_menu(POST_FADER, check);
884 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
885 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
886 items.push_back (CheckMenuElem(*check));
889 check = new CheckMenuItem(_("Control Outs"));
890 init_mute_menu(CONTROL_OUTS, check);
891 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
892 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
893 items.push_back (CheckMenuElem(*check));
896 check = new CheckMenuItem(_("Main Outs"));
897 init_mute_menu(MAIN_OUTS, check);
898 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
899 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
900 items.push_back (CheckMenuElem(*check));
903 //items.push_back (SeparatorElem());
904 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
908 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
910 check->set_active (_route->mute_master()->muted_at (mp));
914 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
916 // _route->set_mute_config(type, check->get_active(), this);
920 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
922 _route->set_solo_isolated (check->get_active(), this);
926 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
928 RouteGroup* route_group;
930 if((route_group = route->route_group()) != 0){
931 _session.begin_reversible_command (_("mix group solo change"));
932 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
933 route_group->apply(&Route::set_solo, yn, this);
935 _session.add_command (cmd);
936 _session.commit_reversible_command ();
938 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
943 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
945 _session.begin_reversible_command (name);
946 XMLNode &before = _route->get_state();
947 bind(mem_fun(*_route, func), yn, arg)();
948 XMLNode &after = _route->get_state();
949 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
950 _session.commit_reversible_command ();
954 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
956 _session.begin_reversible_command (name);
957 XMLNode &before = track()->get_state();
958 bind (mem_fun (*track(), func), yn, arg)();
959 XMLNode &after = track()->get_state();
960 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
961 _session.commit_reversible_command ();
965 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
967 RouteGroup* route_group;
969 if((route_group = route->route_group()) != 0){
970 _session.begin_reversible_command (_("mix group mute change"));
971 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
972 route_group->apply(&Route::set_mute, yn, this);
974 _session.add_command(cmd);
975 _session.commit_reversible_command ();
977 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
982 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
984 RouteGroup* route_group;
986 if((route_group = route->route_group()) != 0){
987 _session.begin_reversible_command (_("mix group rec-enable change"));
988 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
989 route_group->apply (&Route::set_record_enable, yn, this);
991 _session.add_command(cmd);
992 _session.commit_reversible_command ();
994 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
1000 RouteUI::choose_color()
1005 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1015 RouteUI::set_color (const Gdk::Color & c)
1022 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1023 xml_node->add_property ("color", buf);
1025 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1030 RouteUI::ensure_xml_node ()
1032 if (xml_node == 0) {
1033 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1034 xml_node = new XMLNode ("GUI");
1035 _route->add_extra_xml (*xml_node);
1041 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1045 XMLNodeList kids = xml_node->children();
1046 XMLNodeConstIterator iter;
1048 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1050 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1051 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1052 XMLProperty* type = (*iter)->property("automation-id");
1053 if (type && type->value() == sym)
1058 // Didn't find it, make a new one
1059 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1060 child->add_property("automation-id", sym);
1061 xml_node->add_child_nocopy (*child);
1067 RouteUI::set_color_from_route ()
1071 RouteUI::ensure_xml_node ();
1073 if ((prop = xml_node->property ("color")) != 0) {
1075 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1077 _color.set_green(g);
1085 RouteUI::remove_this_route ()
1087 vector<string> choices;
1091 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());
1093 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1096 choices.push_back (_("No, do nothing."));
1097 choices.push_back (_("Yes, remove it."));
1099 Choice prompter (prompt, choices);
1101 if (prompter.run () == 1) {
1102 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1107 RouteUI::idle_remove_this_route (RouteUI *rui)
1109 rui->_session.remove_route (rui->_route);
1114 RouteUI::route_rename ()
1116 ArdourPrompter name_prompter (true);
1118 name_prompter.set_prompt (_("New Name: "));
1119 name_prompter.set_initial_text (_route->name());
1120 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1121 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1122 name_prompter.show_all ();
1124 switch (name_prompter.run ()) {
1126 case Gtk::RESPONSE_ACCEPT:
1127 name_prompter.get_result (result);
1128 if (result.length()) {
1129 _route->set_name (result);
1139 RouteUI::name_changed ()
1141 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1143 name_label.set_text (_route->name());
1147 RouteUI::toggle_route_active ()
1151 if (route_active_menu_item) {
1152 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1153 _route->set_active (!yn);
1159 RouteUI::route_active_changed ()
1161 if (route_active_menu_item) {
1162 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1167 RouteUI::toggle_polarity ()
1169 if (polarity_menu_item) {
1173 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1175 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1176 _route->set_phase_invert (x);
1178 name_label.set_text (X_("Ø ") + name_label.get_text());
1180 name_label.set_text (_route->name());
1187 RouteUI::polarity_changed ()
1189 if (_route->phase_invert()) {
1190 name_label.set_text (X_("Ø ") + name_label.get_text());
1192 name_label.set_text (_route->name());
1197 RouteUI::toggle_denormal_protection ()
1199 if (denormal_menu_item) {
1203 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1205 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1206 _route->set_denormal_protection (x);
1212 RouteUI::denormal_protection_changed ()
1214 if (denormal_menu_item) {
1215 denormal_menu_item->set_active (_route->denormal_protection());
1220 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1222 bool yn = _route->solo_isolated ();
1224 if (check->get_active() != yn) {
1225 check->set_active (yn);
1229 #ifdef FIX_THIS_FOR_3_0
1231 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1233 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1235 bool yn = _route->get_mute_config(PRE_FADER);
1236 if (check->get_active() != yn) {
1237 check->set_active (yn);
1242 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1244 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1246 bool yn = _route->get_mute_config(POST_FADER);
1247 if (check->get_active() != yn) {
1248 check->set_active (yn);
1253 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1255 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1257 bool yn = _route->get_mute_config(CONTROL_OUTS);
1258 if (check->get_active() != yn) {
1259 check->set_active (yn);
1264 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1266 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1268 bool yn = _route->get_mute_config(MAIN_OUTS);
1269 if (check->get_active() != yn) {
1270 check->set_active (yn);
1276 RouteUI::disconnect_input ()
1278 _route->input()->disconnect (this);
1282 RouteUI::disconnect_output ()
1284 _route->output()->disconnect (this);
1288 RouteUI::is_track () const
1290 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1293 boost::shared_ptr<Track>
1294 RouteUI::track() const
1296 return boost::dynamic_pointer_cast<Track>(_route);
1300 RouteUI::is_audio_track () const
1302 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1305 boost::shared_ptr<AudioTrack>
1306 RouteUI::audio_track() const
1308 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1312 RouteUI::is_midi_track () const
1314 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1317 boost::shared_ptr<MidiTrack>
1318 RouteUI::midi_track() const
1320 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1323 boost::shared_ptr<Diskstream>
1324 RouteUI::get_diskstream () const
1326 boost::shared_ptr<Track> t;
1328 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1329 return t->diskstream();
1331 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1336 RouteUI::name() const
1338 return _route->name();
1342 RouteUI::map_frozen ()
1344 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1346 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1349 switch (at->freeze_state()) {
1350 case AudioTrack::Frozen:
1351 rec_enable_button->set_sensitive (false);
1354 rec_enable_button->set_sensitive (true);
1361 RouteUI::adjust_latency ()
1363 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1367 RouteUI::save_as_template ()
1370 Glib::ustring safe_name;
1373 path = ARDOUR::user_route_template_directory ();
1375 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1376 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1380 Prompter p (true); // modal
1382 p.set_prompt (_("Template name:"));
1384 case RESPONSE_ACCEPT:
1391 p.get_result (name, true);
1393 safe_name = legalize_for_path (name);
1394 safe_name += template_suffix;
1398 _route->save_as_template (path.to_string(), name);
1402 RouteUI::check_rec_enable_sensitivity ()
1404 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1405 rec_enable_button->set_sensitive (false);
1407 rec_enable_button->set_sensitive (true);
1412 RouteUI::parameter_changed (string const & p)
1414 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1416 if (p == "disable-disarm-during-roll") {
1417 check_rec_enable_sensitivity ();
1418 } else if (p == "solo-control-is-listen-control") {
1419 set_button_names ();
1420 } else if (p == "listen-position") {
1421 set_button_names ();
1426 RouteUI::step_gain_up ()
1428 _route->set_gain (dB_to_coefficient (coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1432 RouteUI::page_gain_up ()
1434 _route->set_gain (dB_to_coefficient (coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1438 RouteUI::step_gain_down ()
1440 _route->set_gain (dB_to_coefficient (coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1444 RouteUI::page_gain_down ()
1446 _route->set_gain (dB_to_coefficient (coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);