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"
34 #include "pbd/enumwriter.h"
36 #include "ardour_ui.h"
42 #include "gui_thread.h"
43 #include "ardour_dialog.h"
44 #include "latency_gui.h"
45 #include "mixer_strip.h"
46 #include "automation_time_axis.h"
48 #include "ardour/route.h"
49 #include "ardour/event_type_map.h"
50 #include "ardour/session.h"
51 #include "ardour/audioengine.h"
52 #include "ardour/audio_track.h"
53 #include "ardour/audio_diskstream.h"
54 #include "ardour/midi_track.h"
55 #include "ardour/midi_diskstream.h"
56 #include "ardour/template_utils.h"
57 #include "ardour/filename_extensions.h"
58 #include "ardour/directory_names.h"
59 #include "ardour/profile.h"
64 using namespace Gtkmm2ext;
65 using namespace ARDOUR;
68 RouteUI::RouteUI (ARDOUR::Session& sess)
74 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess)
83 /* derived classes should emit GoingAway so that they receive the signal
84 when the object is still a legal derived instance.
100 pre_fader_mute_check = 0;
101 post_fader_mute_check = 0;
102 listen_mute_check = 0;
104 ignore_toggle = false;
105 wait_for_release = false;
106 route_active_menu_item = 0;
107 polarity_menu_item = 0;
108 denormal_menu_item = 0;
109 multiple_mute_change = false;
110 multiple_solo_change = false;
112 mute_button = manage (new BindableToggleButton ());
113 mute_button->set_self_managed (true);
114 mute_button->set_name ("MuteButton");
115 mute_button->add (mute_button_label);
116 mute_button_label.show ();
117 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
119 solo_button = manage (new BindableToggleButton ());
120 solo_button->set_self_managed (true);
121 solo_button->set_name ("SoloButton");
122 solo_button->add (solo_button_label);
123 solo_button_label.show ();
124 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
125 solo_button->set_no_show_all (true);
127 rec_enable_button = manage (new BindableToggleButton ());
128 rec_enable_button->set_name ("RecordEnableButton");
129 rec_enable_button->set_self_managed (true);
130 rec_enable_button->add (rec_enable_button_label);
131 rec_enable_button_label.show ();
132 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
134 show_sends_button = manage (new BindableToggleButton (""));
135 show_sends_button->set_name ("SendAlert");
136 show_sends_button->set_self_managed (true);
137 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
139 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
140 _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
142 Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
148 //Remove route connections associated with us.
149 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
153 connections.clear ();
162 /* do not delete the node - its owned by the route */
166 route_active_menu_item = 0;
167 polarity_menu_item = 0;
168 denormal_menu_item = 0;
172 RouteUI::set_route (boost::shared_ptr<Route> rp)
178 if (set_color_from_route()) {
179 set_color (unique_random_color());
182 /* no, there is no memory leak here. This object cleans itself (and other stuff)
183 up when the route is destroyed.
187 new PairedShiva<Route,RouteUI> (*_route, *this);
190 mute_button->set_controllable (_route->mute_control());
191 solo_button->set_controllable (_route->solo_control());
193 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
194 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
195 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
196 connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed)));
197 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
199 if (_session.writable() && is_track()) {
200 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
202 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
203 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
205 rec_enable_button->show();
206 rec_enable_button->set_controllable (t->rec_enable_control());
208 update_rec_display ();
211 mute_button->unset_flags (Gtk::CAN_FOCUS);
212 solo_button->unset_flags (Gtk::CAN_FOCUS);
216 if (_route->is_control()) {
217 solo_button->hide ();
222 /* map the current state */
231 RouteUI::mute_press(GdkEventButton* ev)
233 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
236 multiple_mute_change = false;
237 if (!ignore_toggle) {
239 if (Keyboard::is_context_menu_event (ev)) {
245 mute_menu->popup(0,ev->time);
249 if (Keyboard::is_button2_event (ev)) {
250 // Primary-button2 click is the midi binding click
251 // button2-click is "momentary"
253 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
254 wait_for_release = true;
260 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
262 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
264 /* Primary-Tertiary-click applies change to all routes */
266 _session.begin_reversible_command (_("mute change"));
267 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
268 _session.set_all_mute (!_route->muted());
270 _session.add_command(cmd);
271 _session.commit_reversible_command ();
272 multiple_mute_change = true;
274 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
276 /* Primary-button1 applies change to the mix group.
277 NOTE: Primary-button2 is MIDI learn.
280 if (ev->button == 1) {
281 set_route_group_mute (_route, !_route->muted());
286 /* plain click applies change to this route */
287 if (wait_for_release) {
288 _route->set_mute (!_route->muted(), this);
290 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
302 RouteUI::mute_release(GdkEventButton*)
304 if (!ignore_toggle) {
305 if (wait_for_release){
306 wait_for_release = false;
307 if (multiple_mute_change) {
308 multiple_mute_change = false;
310 // because the press was the last undoable thing we did
313 _route->set_mute (!_route->muted(), this);
321 RouteUI::solo_press(GdkEventButton* ev)
323 /* ignore double/triple clicks */
325 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
329 if (Config->get_solo_control_is_listen_control()) {
331 _route->set_listen (!_route->listening(), this);
335 multiple_solo_change = false;
336 if (!ignore_toggle) {
338 if (Keyboard::is_context_menu_event (ev)) {
340 if (solo_menu == 0) {
344 solo_menu->popup (1, ev->time);
348 if (Keyboard::is_button2_event (ev)) {
350 // Primary-button2 click is the midi binding click
351 // button2-click is "momentary"
353 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
354 wait_for_release = true;
360 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
362 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
364 /* Primary-Tertiary-click applies change to all routes */
365 bool was_not_latched = false;
366 if (!Config->get_solo_latched ()) {
367 was_not_latched = true;
369 XXX it makes no sense to solo all tracks if we're
370 not in latched mode, but doing nothing feels like a bug,
373 Config->set_solo_latched (true);
375 _session.begin_reversible_command (_("solo change"));
376 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
377 _session.set_all_solo (!_route->soloed());
379 _session.add_command (cmd);
380 _session.commit_reversible_command ();
381 multiple_solo_change = true;
382 if (was_not_latched) {
383 Config->set_solo_latched (false);
386 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
388 // Primary-Secondary-click: exclusively solo this track, not a toggle */
390 _session.begin_reversible_command (_("solo change"));
391 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
392 _session.set_all_solo (false);
393 _route->set_solo (true, this);
395 _session.add_command(cmd);
396 _session.commit_reversible_command ();
398 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
400 // shift-click: set this route to solo safe
402 if (Profile->get_sae() && ev->button == 1) {
403 // button 1 and shift-click: disables solo_latched for this click
404 if (!Config->get_solo_latched ()) {
405 Config->set_solo_latched (true);
406 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
407 Config->set_solo_latched (false);
410 _route->set_solo_isolated (!_route->solo_isolated(), this);
411 wait_for_release = false;
414 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
416 /* Primary-button1: solo mix group.
417 NOTE: Primary-button2 is MIDI learn.
420 if (ev->button == 1) {
421 set_route_group_solo (_route, !_route->soloed());
426 /* click: solo this route */
427 if (wait_for_release) {
428 _route->set_solo (!_route->soloed(), this);
430 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
442 RouteUI::solo_release(GdkEventButton*)
444 if (!ignore_toggle) {
445 if (wait_for_release) {
446 wait_for_release = false;
447 if (multiple_solo_change) {
448 multiple_solo_change = false;
450 // because the press was the last undoable thing we did
453 // we don't use "undo the last op"
454 // here because its expensive for the GUI
455 _route->set_solo (!_route->soloed(), this);
464 RouteUI::rec_enable_press(GdkEventButton* ev)
466 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
470 if (!_session.engine().connected()) {
471 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
476 if (!ignore_toggle && is_track() && rec_enable_button) {
478 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
480 // do nothing on midi bind event
483 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
485 _session.begin_reversible_command (_("rec-enable change"));
486 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
488 if (rec_enable_button->get_active()) {
489 _session.record_disenable_all ();
491 _session.record_enable_all ();
492 check_rec_enable_sensitivity ();
496 _session.add_command(cmd);
497 _session.commit_reversible_command ();
499 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
501 /* Primary-button1 applies change to the mix group.
502 NOTE: Primary-button2 is MIDI learn.
505 set_route_group_rec_enable (_route, !_route->record_enabled());
507 } else if (Keyboard::is_context_menu_event (ev)) {
509 /* do this on release */
512 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
513 check_rec_enable_sensitivity ();
521 RouteUI::rec_enable_release (GdkEventButton*)
527 RouteUI::build_sends_menu ()
529 using namespace Menu_Helpers;
531 sends_menu = new Menu;
532 sends_menu->set_name ("ArdourContextMenu");
533 MenuList& items = sends_menu->items();
535 items.push_back (MenuElem(_("Assign all tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_sends), PreFader)));
536 items.push_back (MenuElem(_("Assign all tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_sends), PostFader)));
537 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
538 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
539 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
544 RouteUI::create_sends (Placement p)
546 _session.globally_add_internal_sends (_route, p);
550 RouteUI::set_sends_gain_from_track ()
552 _session.globally_set_send_gains_from_track (_route);
556 RouteUI::set_sends_gain_to_zero ()
558 _session.globally_set_send_gains_to_zero (_route);
562 RouteUI::set_sends_gain_to_unity ()
564 _session.globally_set_send_gains_to_unity (_route);
568 RouteUI::show_sends_press(GdkEventButton* ev)
570 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
574 if (!ignore_toggle && !is_track() && show_sends_button) {
576 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
578 // do nothing on midi bind event
581 } else if (Keyboard::is_context_menu_event (ev)) {
583 if (sends_menu == 0) {
587 sends_menu->popup (0, ev->time);
591 /* change button state */
593 show_sends_button->set_active (!show_sends_button->get_active());
597 if (show_sends_button->get_active()) {
598 /* show sends to this bus */
599 MixerStrip::SwitchIO (_route);
600 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
602 /* everybody back to normal */
603 send_blink_connection.disconnect ();
604 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
614 RouteUI::show_sends_release (GdkEventButton*)
620 RouteUI::send_blink (bool onoff)
622 if (!show_sends_button) {
627 show_sends_button->set_state (STATE_ACTIVE);
629 show_sends_button->set_state (STATE_NORMAL);
634 RouteUI::solo_changed(void* /*src*/)
636 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
641 RouteUI::listen_changed(void* /*src*/)
643 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
647 RouteUI::update_solo_display ()
651 if (Config->get_solo_control_is_listen_control()) {
653 if (solo_button->get_active() != (x = _route->listening())) {
654 ignore_toggle = true;
655 solo_button->set_active(x);
656 ignore_toggle = false;
660 solo_button->set_visual_state (1);
662 solo_button->set_visual_state (0);
668 if (solo_button->get_active() != (x = _route->soloed())){
669 ignore_toggle = true;
670 solo_button->set_active (x);
671 ignore_toggle = false;
674 if (_route->solo_isolated()) {
675 solo_button->set_visual_state (2);
677 solo_button->set_visual_state (1);
679 solo_button->set_visual_state (0);
685 RouteUI::solo_changed_so_update_mute ()
687 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
691 RouteUI::mute_changed(void* /*src*/)
693 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
697 RouteUI::update_mute_display ()
699 bool model = _route->muted();
700 bool view = mute_button->get_active();
702 /* first make sure the button's "depressed" visual
707 ignore_toggle = true;
708 mute_button->set_active (model);
709 ignore_toggle = false;
712 /* now attend to visual state */
714 if (Config->get_show_solo_mutes()) {
715 if (_route->muted()) {
716 mute_button->set_visual_state (2);
717 } else if (!_route->soloed() && _session.soloing()) {
718 mute_button->set_visual_state (1);
720 mute_button->set_visual_state (0);
723 if (_route->muted()) {
724 mute_button->set_visual_state (2);
726 mute_button->set_visual_state (0);
733 RouteUI::route_rec_enable_changed ()
735 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
739 RouteUI::session_rec_enable_changed ()
741 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
745 RouteUI::update_rec_display ()
747 bool model = _route->record_enabled();
748 bool view = rec_enable_button->get_active();
750 /* first make sure the button's "depressed" visual
755 ignore_toggle = true;
756 rec_enable_button->set_active (model);
757 ignore_toggle = false;
763 /* now make sure its color state is correct */
767 switch (_session.record_status ()) {
768 case Session::Recording:
769 rec_enable_button->set_visual_state (1);
772 case Session::Disabled:
773 case Session::Enabled:
774 rec_enable_button->set_visual_state (2);
780 rec_enable_button->set_visual_state (0);
785 RouteUI::build_solo_menu (void)
787 using namespace Menu_Helpers;
789 solo_menu = new Menu;
790 solo_menu->set_name ("ArdourContextMenu");
791 MenuList& items = solo_menu->items();
792 CheckMenuItem* check;
794 check = new CheckMenuItem(_("Solo Isolate"));
795 check->set_active (_route->solo_isolated());
796 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
797 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
798 items.push_back (CheckMenuElem(*check));
801 //items.push_back (SeparatorElem());
802 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
807 RouteUI::build_mute_menu(void)
809 using namespace Menu_Helpers;
811 mute_menu = new Menu;
812 mute_menu->set_name ("ArdourContextMenu");
814 MenuList& items = mute_menu->items();
816 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
817 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
818 pre_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
819 items.push_back (CheckMenuElem(*pre_fader_mute_check));
820 pre_fader_mute_check->show_all();
822 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
823 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
824 post_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
825 items.push_back (CheckMenuElem(*post_fader_mute_check));
826 post_fader_mute_check->show_all();
828 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
829 init_mute_menu(MuteMaster::Listen, listen_mute_check);
830 listen_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
831 items.push_back (CheckMenuElem(*listen_mute_check));
832 listen_mute_check->show_all();
834 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
835 init_mute_menu(MuteMaster::Main, main_mute_check);
836 main_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
837 items.push_back (CheckMenuElem(*main_mute_check));
838 main_mute_check->show_all();
840 //items.push_back (SeparatorElem());
841 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
843 _route->mute_points_changed.connect (mem_fun (*this, &RouteUI::muting_change));
847 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
849 check->set_active (_route->mute_points() & mp);
853 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
855 if (check->get_active()) {
856 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
858 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
863 RouteUI::muting_change ()
865 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::muting_change));
868 MuteMaster::MutePoint current = _route->mute_points ();
870 yn = (current & MuteMaster::PreFader);
872 if (pre_fader_mute_check->get_active() != yn) {
873 pre_fader_mute_check->set_active (yn);
876 yn = (current & MuteMaster::PostFader);
878 if (post_fader_mute_check->get_active() != yn) {
879 post_fader_mute_check->set_active (yn);
882 yn = (current & MuteMaster::Listen);
884 if (listen_mute_check->get_active() != yn) {
885 listen_mute_check->set_active (yn);
888 yn = (current & MuteMaster::Main);
890 if (main_mute_check->get_active() != yn) {
891 main_mute_check->set_active (yn);
896 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
898 _route->set_solo_isolated (check->get_active(), this);
902 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
904 RouteGroup* route_group;
906 if((route_group = route->route_group()) != 0){
907 _session.begin_reversible_command (_("mix group solo change"));
908 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
909 route_group->apply(&Route::set_solo, yn, this);
911 _session.add_command (cmd);
912 _session.commit_reversible_command ();
914 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
919 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
921 _session.begin_reversible_command (name);
922 XMLNode &before = _route->get_state();
923 bind(mem_fun(*_route, func), yn, arg)();
924 XMLNode &after = _route->get_state();
925 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
926 _session.commit_reversible_command ();
930 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
932 _session.begin_reversible_command (name);
933 XMLNode &before = track()->get_state();
934 bind (mem_fun (*track(), func), yn, arg)();
935 XMLNode &after = track()->get_state();
936 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
937 _session.commit_reversible_command ();
941 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
943 RouteGroup* route_group;
945 if((route_group = route->route_group()) != 0){
946 _session.begin_reversible_command (_("mix group mute change"));
947 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
948 route_group->apply(&Route::set_mute, yn, this);
950 _session.add_command(cmd);
951 _session.commit_reversible_command ();
953 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
958 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
960 RouteGroup* route_group;
962 if((route_group = route->route_group()) != 0){
963 _session.begin_reversible_command (_("mix group rec-enable change"));
964 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
965 route_group->apply (&Route::set_record_enable, yn, this);
967 _session.add_command(cmd);
968 _session.commit_reversible_command ();
970 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
976 RouteUI::choose_color()
981 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
991 RouteUI::set_color (const Gdk::Color & c)
998 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
999 xml_node->add_property ("color", buf);
1001 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1006 RouteUI::ensure_xml_node ()
1008 if (xml_node == 0) {
1009 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1010 xml_node = new XMLNode ("GUI");
1011 _route->add_extra_xml (*xml_node);
1017 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1021 XMLNodeList kids = xml_node->children();
1022 XMLNodeConstIterator iter;
1024 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1026 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1027 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1028 XMLProperty* type = (*iter)->property("automation-id");
1029 if (type && type->value() == sym)
1034 // Didn't find it, make a new one
1035 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1036 child->add_property("automation-id", sym);
1037 xml_node->add_child_nocopy (*child);
1043 RouteUI::set_color_from_route ()
1047 RouteUI::ensure_xml_node ();
1049 if ((prop = xml_node->property ("color")) != 0) {
1051 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1053 _color.set_green(g);
1061 RouteUI::remove_this_route ()
1063 vector<string> choices;
1067 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());
1069 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1072 choices.push_back (_("No, do nothing."));
1073 choices.push_back (_("Yes, remove it."));
1075 Choice prompter (prompt, choices);
1077 if (prompter.run () == 1) {
1078 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1083 RouteUI::idle_remove_this_route (RouteUI *rui)
1085 rui->_session.remove_route (rui->_route);
1090 RouteUI::route_rename ()
1092 ArdourPrompter name_prompter (true);
1094 name_prompter.set_prompt (_("New Name: "));
1095 name_prompter.set_initial_text (_route->name());
1096 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1097 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1098 name_prompter.show_all ();
1100 switch (name_prompter.run ()) {
1102 case Gtk::RESPONSE_ACCEPT:
1103 name_prompter.get_result (result);
1104 if (result.length()) {
1105 _route->set_name (result);
1115 RouteUI::name_changed ()
1117 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1119 name_label.set_text (_route->name());
1123 RouteUI::toggle_route_active ()
1127 if (route_active_menu_item) {
1128 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1129 _route->set_active (!yn);
1135 RouteUI::route_active_changed ()
1137 if (route_active_menu_item) {
1138 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1143 RouteUI::toggle_polarity ()
1145 if (polarity_menu_item) {
1149 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1151 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1152 _route->set_phase_invert (x);
1154 name_label.set_text (X_("Ø ") + name_label.get_text());
1156 name_label.set_text (_route->name());
1163 RouteUI::polarity_changed ()
1165 if (_route->phase_invert()) {
1166 name_label.set_text (X_("Ø ") + name_label.get_text());
1168 name_label.set_text (_route->name());
1173 RouteUI::toggle_denormal_protection ()
1175 if (denormal_menu_item) {
1179 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1181 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1182 _route->set_denormal_protection (x);
1188 RouteUI::denormal_protection_changed ()
1190 if (denormal_menu_item) {
1191 denormal_menu_item->set_active (_route->denormal_protection());
1196 RouteUI::solo_isolated_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1198 bool yn = _route->solo_isolated ();
1200 if (check->get_active() != yn) {
1201 check->set_active (yn);
1206 RouteUI::disconnect_input ()
1208 _route->input()->disconnect (this);
1212 RouteUI::disconnect_output ()
1214 _route->output()->disconnect (this);
1218 RouteUI::is_track () const
1220 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1223 boost::shared_ptr<Track>
1224 RouteUI::track() const
1226 return boost::dynamic_pointer_cast<Track>(_route);
1230 RouteUI::is_audio_track () const
1232 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1235 boost::shared_ptr<AudioTrack>
1236 RouteUI::audio_track() const
1238 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1242 RouteUI::is_midi_track () const
1244 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1247 boost::shared_ptr<MidiTrack>
1248 RouteUI::midi_track() const
1250 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1253 boost::shared_ptr<Diskstream>
1254 RouteUI::get_diskstream () const
1256 boost::shared_ptr<Track> t;
1258 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1259 return t->diskstream();
1261 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1266 RouteUI::name() const
1268 return _route->name();
1272 RouteUI::map_frozen ()
1274 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1276 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1279 switch (at->freeze_state()) {
1280 case AudioTrack::Frozen:
1281 rec_enable_button->set_sensitive (false);
1284 rec_enable_button->set_sensitive (true);
1291 RouteUI::adjust_latency ()
1293 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1297 RouteUI::save_as_template ()
1300 Glib::ustring safe_name;
1303 path = ARDOUR::user_route_template_directory ();
1305 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1306 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1310 Prompter p (true); // modal
1312 p.set_prompt (_("Template name:"));
1314 case RESPONSE_ACCEPT:
1321 p.get_result (name, true);
1323 safe_name = legalize_for_path (name);
1324 safe_name += template_suffix;
1328 _route->save_as_template (path.to_string(), name);
1332 RouteUI::check_rec_enable_sensitivity ()
1334 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1335 rec_enable_button->set_sensitive (false);
1337 rec_enable_button->set_sensitive (true);
1342 RouteUI::parameter_changed (string const & p)
1344 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1346 if (p == "disable-disarm-during-roll") {
1347 check_rec_enable_sensitivity ();
1348 } else if (p == "solo-control-is-listen-control") {
1349 set_button_names ();
1350 } else if (p == "listen-position") {
1351 set_button_names ();
1356 RouteUI::step_gain_up ()
1358 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1362 RouteUI::page_gain_up ()
1364 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1368 RouteUI::step_gain_down ()
1370 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1374 RouteUI::page_gain_down ()
1376 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1380 RouteUI::open_remote_control_id_dialog ()
1382 ArdourDialog dialog (_("Remote Control ID"));
1384 uint32_t const limit = _session.ntracks() + _session.nbusses () + 4;
1386 HBox* hbox = manage (new HBox);
1387 hbox->set_spacing (6);
1388 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1389 SpinButton* spin = manage (new SpinButton);
1390 spin->set_digits (0);
1391 spin->set_increments (1, 10);
1392 spin->set_range (0, limit);
1393 spin->set_value (_route->remote_control_id());
1394 hbox->pack_start (*spin);
1395 dialog.get_vbox()->pack_start (*hbox);
1397 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1398 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1401 int const r = dialog.run ();
1403 if (r == RESPONSE_ACCEPT) {
1404 _route->set_remote_control_id (spin->get_value_as_int ());