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"
39 #include "gui_thread.h"
40 #include "ardour_dialog.h"
41 #include "latency_gui.h"
42 #include "mixer_strip.h"
43 #include "automation_time_axis.h"
45 #include "ardour/route.h"
46 #include "ardour/session.h"
47 #include "ardour/audioengine.h"
48 #include "ardour/audio_track.h"
49 #include "ardour/audio_diskstream.h"
50 #include "ardour/midi_track.h"
51 #include "ardour/midi_diskstream.h"
52 #include "ardour/template_utils.h"
53 #include "ardour/filename_extensions.h"
54 #include "ardour/directory_names.h"
55 #include "ardour/profile.h"
60 using namespace Gtkmm2ext;
61 using namespace ARDOUR;
64 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
68 set_button_names (mute_name, solo_name, rec_name);
71 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
72 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
76 set_button_names (mute_name, solo_name, rec_name);
82 /* derived classes should emit GoingAway so that they receive the signal
83 when the object is still a legal derived instance.
88 delete remote_control_menu;
99 remote_control_menu = 0;
101 ignore_toggle = false;
102 wait_for_release = false;
103 route_active_menu_item = 0;
104 polarity_menu_item = 0;
105 denormal_menu_item = 0;
106 multiple_mute_change = false;
107 multiple_solo_change = false;
109 mute_button = manage (new BindableToggleButton (""));
110 mute_button->set_self_managed (true);
111 mute_button->set_name ("MuteButton");
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 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
118 solo_button->set_no_show_all (true);
120 rec_enable_button = manage (new BindableToggleButton (""));
121 rec_enable_button->set_name ("RecordEnableButton");
122 rec_enable_button->set_self_managed (true);
123 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
125 show_sends_button = manage (new BindableToggleButton (""));
126 show_sends_button->set_name ("SendAlert");
127 show_sends_button->set_self_managed (true);
128 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
130 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
131 _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
137 //Remove route connections associated with us.
138 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
142 connections.clear ();
151 /* do not delete the node - its owned by the route */
155 route_active_menu_item = 0;
156 polarity_menu_item = 0;
157 denormal_menu_item = 0;
161 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
169 RouteUI::set_route (boost::shared_ptr<Route> rp)
175 if (set_color_from_route()) {
176 set_color (unique_random_color());
179 /* no, there is no memory leak here. This object cleans itself (and other stuff)
180 up when the route is destroyed.
184 new PairedShiva<Route,RouteUI> (*_route, *this);
187 mute_button->set_controllable (_route->mute_control());
188 mute_button->set_label (m_name);
190 solo_button->set_controllable (_route->solo_control());
191 solo_button->set_label (s_name);
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->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
199 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
201 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
202 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
204 rec_enable_button->show();
205 rec_enable_button->set_controllable (t->rec_enable_control());
206 rec_enable_button->set_label (r_name);
208 update_rec_display ();
211 mute_button->unset_flags (Gtk::CAN_FOCUS);
212 solo_button->unset_flags (Gtk::CAN_FOCUS);
216 if (_route->is_master()) {
217 solo_button->hide ();
222 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
224 /* map the current state */
233 RouteUI::mute_press(GdkEventButton* ev)
235 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
238 multiple_mute_change = false;
239 if (!ignore_toggle) {
241 if (Keyboard::is_context_menu_event (ev)) {
247 mute_menu->popup(0,ev->time);
251 if (Keyboard::is_button2_event (ev)) {
252 // Primary-button2 click is the midi binding click
253 // button2-click is "momentary"
255 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
256 wait_for_release = true;
262 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
264 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
266 /* Primary-Tertiary-click applies change to all routes */
268 _session.begin_reversible_command (_("mute change"));
269 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
270 _session.set_all_mute (!_route->muted());
272 _session.add_command(cmd);
273 _session.commit_reversible_command ();
274 multiple_mute_change = true;
276 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
278 /* Primary-button1 applies change to the mix group.
279 NOTE: Primary-button2 is MIDI learn.
282 if (ev->button == 1) {
283 set_mix_group_mute (_route, !_route->muted());
288 /* plain click applies change to this route */
289 if (wait_for_release) {
290 _route->set_mute (!_route->muted(), this);
292 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
304 RouteUI::mute_release(GdkEventButton* ev)
306 if (!ignore_toggle) {
307 if (wait_for_release){
308 wait_for_release = false;
309 if (multiple_mute_change) {
310 multiple_mute_change = false;
312 // because the press was the last undoable thing we did
315 _route->set_mute (!_route->muted(), this);
323 RouteUI::solo_press(GdkEventButton* ev)
325 /* ignore double/triple clicks */
327 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
330 multiple_solo_change = false;
331 if (!ignore_toggle) {
333 if (Keyboard::is_context_menu_event (ev)) {
335 if (solo_menu == 0) {
339 solo_menu->popup (1, ev->time);
343 if (Keyboard::is_button2_event (ev)) {
345 // Primary-button2 click is the midi binding click
346 // button2-click is "momentary"
348 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
349 wait_for_release = true;
355 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
357 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
359 /* Primary-Tertiary-click applies change to all routes */
360 bool was_not_latched = false;
361 if (!Config->get_solo_latched ()) {
362 was_not_latched = true;
364 XXX it makes no sense to solo all tracks if we're
365 not in latched mode, but doing nothing feels like a bug,
368 Config->set_solo_latched (true);
370 _session.begin_reversible_command (_("solo change"));
371 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
372 _session.set_all_solo (!_route->soloed());
374 _session.add_command (cmd);
375 _session.commit_reversible_command ();
376 multiple_solo_change = true;
377 if (was_not_latched) {
378 Config->set_solo_latched (false);
381 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
383 // Primary-Secondary-click: exclusively solo this track, not a toggle */
385 _session.begin_reversible_command (_("solo change"));
386 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
387 _session.set_all_solo (false);
388 _route->set_solo (true, this);
390 _session.add_command(cmd);
391 _session.commit_reversible_command ();
393 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
395 // shift-click: set this route to solo safe
397 if (Profile->get_sae() && ev->button == 1) {
398 // button 1 and shift-click: disables solo_latched for this click
399 if (!Config->get_solo_latched ()) {
400 Config->set_solo_latched (true);
401 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
402 Config->set_solo_latched (false);
405 _route->set_solo_isolated (!_route->solo_isolated(), this);
406 wait_for_release = false;
409 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
411 /* Primary-button1: solo mix group.
412 NOTE: Primary-button2 is MIDI learn.
415 if (ev->button == 1) {
416 set_mix_group_solo (_route, !_route->soloed());
421 /* click: solo this route */
422 if (wait_for_release) {
423 _route->set_solo (!_route->soloed(), this);
425 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
436 RouteUI::solo_release(GdkEventButton* ev)
438 if (!ignore_toggle) {
439 if (wait_for_release) {
440 wait_for_release = false;
441 if (multiple_solo_change) {
442 multiple_solo_change = false;
444 // because the press was the last undoable thing we did
447 // we don't use "undo the last op"
448 // here because its expensive for the GUI
449 _route->set_solo (!_route->soloed(), this);
458 RouteUI::rec_enable_press(GdkEventButton* ev)
460 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
464 if (!_session.engine().connected()) {
465 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
470 if (!ignore_toggle && is_track() && rec_enable_button) {
472 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
474 // do nothing on midi bind event
477 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
479 _session.begin_reversible_command (_("rec-enable change"));
480 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
482 if (rec_enable_button->get_active()) {
483 _session.record_disenable_all ();
485 _session.record_enable_all ();
486 check_rec_enable_sensitivity ();
490 _session.add_command(cmd);
491 _session.commit_reversible_command ();
493 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
495 /* Primary-button1 applies change to the mix group.
496 NOTE: Primary-button2 is MIDI learn.
499 set_mix_group_rec_enable (_route, !_route->record_enabled());
503 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
504 check_rec_enable_sensitivity ();
512 RouteUI::rec_enable_release (GdkEventButton* ev)
518 RouteUI::build_sends_menu ()
520 using namespace Menu_Helpers;
522 sends_menu = new Menu;
523 sends_menu->set_name ("ArdourContextMenu");
524 MenuList& items = sends_menu->items();
526 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
527 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
528 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
532 RouteUI::set_sends_gain_from_track ()
537 RouteUI::set_sends_gain_to_zero ()
542 RouteUI::set_sends_gain_to_unity ()
547 RouteUI::show_sends_press(GdkEventButton* ev)
549 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
553 if (!ignore_toggle && !is_track() && show_sends_button) {
555 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
557 // do nothing on midi bind event
560 } else if (Keyboard::is_context_menu_event (ev)) {
562 if (sends_menu == 0) {
566 sends_menu->popup (0, ev->time);
570 /* change button state */
572 show_sends_button->set_active (!show_sends_button->get_active());
576 if (show_sends_button->get_active()) {
577 /* show sends to this bus */
578 MixerStrip::SwitchIO (_route);
579 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
581 /* everybody back to normal */
582 send_blink_connection.disconnect ();
583 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
593 RouteUI::show_sends_release (GdkEventButton* ev)
599 RouteUI::send_blink (bool onoff)
601 if (!show_sends_button) {
606 show_sends_button->set_state (STATE_ACTIVE);
608 show_sends_button->set_state (STATE_NORMAL);
613 RouteUI::solo_changed(void* src)
616 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
620 RouteUI::update_solo_display ()
623 vector<Gdk::Color> fg_colors;
626 if (solo_button->get_active() != (x = _route->soloed())){
627 ignore_toggle = true;
628 solo_button->set_active(x);
629 ignore_toggle = false;
632 if (_route->solo_isolated()) {
633 solo_button->set_visual_state (2);
634 } else if (_route->soloed()) {
635 solo_button->set_visual_state (1);
637 solo_button->set_visual_state (0);
642 RouteUI::solo_changed_so_update_mute ()
644 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
648 RouteUI::mute_changed(void* src)
650 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
654 RouteUI::update_mute_display ()
656 bool model = _route->muted();
657 bool view = mute_button->get_active();
659 /* first make sure the button's "depressed" visual
664 ignore_toggle = true;
665 mute_button->set_active (model);
666 ignore_toggle = false;
669 /* now attend to visual state */
671 if (Config->get_show_solo_mutes()) {
672 if (_route->muted()) {
673 mute_button->set_visual_state (2);
674 } else if (!_route->soloed() && _session.soloing()) {
675 mute_button->set_visual_state (1);
677 mute_button->set_visual_state (0);
680 if (_route->muted()) {
681 mute_button->set_visual_state (2);
683 mute_button->set_visual_state (0);
690 RouteUI::route_rec_enable_changed ()
692 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
696 RouteUI::session_rec_enable_changed ()
698 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
702 RouteUI::update_rec_display ()
704 bool model = _route->record_enabled();
705 bool view = rec_enable_button->get_active();
707 /* first make sure the button's "depressed" visual
712 ignore_toggle = true;
713 rec_enable_button->set_active (model);
714 ignore_toggle = false;
717 /* now make sure its color state is correct */
721 switch (_session.record_status ()) {
722 case Session::Recording:
723 rec_enable_button->set_visual_state (1);
726 case Session::Disabled:
727 case Session::Enabled:
728 rec_enable_button->set_visual_state (2);
734 rec_enable_button->set_visual_state (0);
739 RouteUI::build_remote_control_menu ()
741 remote_control_menu = new Menu;
742 refresh_remote_control_menu ();
746 RouteUI::refresh_remote_control_menu ()
748 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
750 // only refresh the menu if it has been instantiated
752 if (remote_control_menu == 0) {
756 using namespace Menu_Helpers;
758 RadioMenuItem::Group rc_group;
759 CheckMenuItem* rc_active;
760 uint32_t limit = _session.ntracks() + _session.nbusses();
763 MenuList& rc_items = remote_control_menu->items();
766 /* note that this menu list starts at zero, not 1, because zero
767 is a valid, if useless, ID.
770 limit += 4; /* leave some breathing room */
772 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
773 if (_route->remote_control_id() == 0) {
774 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
775 rc_active->set_active ();
778 for (uint32_t i = 1; i < limit; ++i) {
779 snprintf (buf, sizeof (buf), "%u", i);
780 rc_items.push_back (RadioMenuElem (rc_group, buf));
781 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
782 if (_route->remote_control_id() == i) {
783 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
784 rc_active->set_active ();
786 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
791 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
793 /* this is called when the radio menu item is toggled, and so
794 is actually invoked twice per menu selection. we only
795 care about the invocation for the item that was being
799 if (item->get_active()) {
800 _route->set_remote_control_id (id);
805 RouteUI::build_solo_menu (void)
807 using namespace Menu_Helpers;
809 solo_menu = new Menu;
810 solo_menu->set_name ("ArdourContextMenu");
811 MenuList& items = solo_menu->items();
812 CheckMenuItem* check;
814 check = new CheckMenuItem(_("Solo Isolate"));
815 check->set_active (_route->solo_isolated());
816 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
817 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
818 items.push_back (CheckMenuElem(*check));
821 //items.push_back (SeparatorElem());
822 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
827 RouteUI::build_mute_menu(void)
829 using namespace Menu_Helpers;
831 mute_menu = new Menu;
832 mute_menu->set_name ("ArdourContextMenu");
835 MenuList& items = mute_menu->items();
836 CheckMenuItem* check;
838 check = new CheckMenuItem(_("Pre Fader"));
839 init_mute_menu(PRE_FADER, check);
840 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
841 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
842 items.push_back (CheckMenuElem(*check));
845 check = new CheckMenuItem(_("Post Fader"));
846 init_mute_menu(POST_FADER, check);
847 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
848 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
849 items.push_back (CheckMenuElem(*check));
852 check = new CheckMenuItem(_("Control Outs"));
853 init_mute_menu(CONTROL_OUTS, check);
854 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
855 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
856 items.push_back (CheckMenuElem(*check));
859 check = new CheckMenuItem(_("Main Outs"));
860 init_mute_menu(MAIN_OUTS, check);
861 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
862 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
863 items.push_back (CheckMenuElem(*check));
866 //items.push_back (SeparatorElem());
867 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
871 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
873 check->set_active (_route->mute_master()->muted_at (mp));
877 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
879 // _route->set_mute_config(type, check->get_active(), this);
883 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
885 _route->set_solo_isolated (check->get_active(), this);
889 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
891 RouteGroup* mix_group;
893 if((mix_group = route->mix_group()) != 0){
894 _session.begin_reversible_command (_("mix group solo change"));
895 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
896 mix_group->apply(&Route::set_solo, yn, this);
898 _session.add_command (cmd);
899 _session.commit_reversible_command ();
901 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
906 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
908 _session.begin_reversible_command (name);
909 XMLNode &before = _route->get_state();
910 bind(mem_fun(*_route, func), yn, arg)();
911 XMLNode &after = _route->get_state();
912 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
913 _session.commit_reversible_command ();
917 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
919 _session.begin_reversible_command (name);
920 XMLNode &before = track()->get_state();
921 bind (mem_fun (*track(), func), yn, arg)();
922 XMLNode &after = track()->get_state();
923 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
924 _session.commit_reversible_command ();
928 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
930 RouteGroup* mix_group;
932 if((mix_group = route->mix_group()) != 0){
933 _session.begin_reversible_command (_("mix group mute change"));
934 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
935 mix_group->apply(&Route::set_mute, yn, this);
937 _session.add_command(cmd);
938 _session.commit_reversible_command ();
940 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
945 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
947 RouteGroup* mix_group;
949 if((mix_group = route->mix_group()) != 0){
950 _session.begin_reversible_command (_("mix group rec-enable change"));
951 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
952 mix_group->apply (&Route::set_record_enable, yn, this);
954 _session.add_command(cmd);
955 _session.commit_reversible_command ();
957 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
963 RouteUI::choose_color()
968 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
978 RouteUI::set_color (const Gdk::Color & c)
985 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
986 xml_node->add_property ("color", buf);
988 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
993 RouteUI::ensure_xml_node ()
996 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
997 xml_node = new XMLNode ("GUI");
998 _route->add_extra_xml (*xml_node);
1004 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1008 XMLNodeList kids = xml_node->children();
1009 XMLNodeConstIterator iter;
1011 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1013 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1014 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1015 XMLProperty* type = (*iter)->property("automation-id");
1016 if (type && type->value() == sym)
1021 // Didn't find it, make a new one
1022 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1023 child->add_property("automation-id", sym);
1024 xml_node->add_child_nocopy (*child);
1030 RouteUI::set_color_from_route ()
1034 RouteUI::ensure_xml_node ();
1036 if ((prop = xml_node->property ("color")) != 0) {
1038 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1040 _color.set_green(g);
1048 RouteUI::remove_this_route ()
1050 vector<string> choices;
1054 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());
1056 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1059 choices.push_back (_("No, do nothing."));
1060 choices.push_back (_("Yes, remove it."));
1062 Choice prompter (prompt, choices);
1064 if (prompter.run () == 1) {
1065 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1070 RouteUI::idle_remove_this_route (RouteUI *rui)
1072 rui->_session.remove_route (rui->_route);
1077 RouteUI::route_rename ()
1079 ArdourPrompter name_prompter (true);
1081 name_prompter.set_prompt (_("New Name: "));
1082 name_prompter.set_initial_text (_route->name());
1083 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1084 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1085 name_prompter.show_all ();
1087 switch (name_prompter.run ()) {
1089 case Gtk::RESPONSE_ACCEPT:
1090 name_prompter.get_result (result);
1091 if (result.length()) {
1092 _route->set_name (result);
1102 RouteUI::name_changed ()
1104 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1106 name_label.set_text (_route->name());
1110 RouteUI::toggle_route_active ()
1114 if (route_active_menu_item) {
1115 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1116 _route->set_active (!yn);
1122 RouteUI::route_active_changed ()
1124 if (route_active_menu_item) {
1125 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1130 RouteUI::toggle_polarity ()
1132 if (polarity_menu_item) {
1136 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1138 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1139 _route->set_phase_invert (x);
1141 name_label.set_text (X_("Ø ") + name_label.get_text());
1143 name_label.set_text (_route->name());
1150 RouteUI::polarity_changed ()
1152 if (_route->phase_invert()) {
1153 name_label.set_text (X_("Ø ") + name_label.get_text());
1155 name_label.set_text (_route->name());
1160 RouteUI::toggle_denormal_protection ()
1162 if (denormal_menu_item) {
1166 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1168 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1169 _route->set_denormal_protection (x);
1175 RouteUI::denormal_protection_changed ()
1177 if (denormal_menu_item) {
1178 denormal_menu_item->set_active (_route->denormal_protection());
1183 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1185 bool yn = _route->solo_isolated ();
1187 if (check->get_active() != yn) {
1188 check->set_active (yn);
1192 #ifdef FIX_THIS_FOR_3_0
1194 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1196 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1198 bool yn = _route->get_mute_config(PRE_FADER);
1199 if (check->get_active() != yn) {
1200 check->set_active (yn);
1205 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1207 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1209 bool yn = _route->get_mute_config(POST_FADER);
1210 if (check->get_active() != yn) {
1211 check->set_active (yn);
1216 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1218 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1220 bool yn = _route->get_mute_config(CONTROL_OUTS);
1221 if (check->get_active() != yn) {
1222 check->set_active (yn);
1227 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1229 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1231 bool yn = _route->get_mute_config(MAIN_OUTS);
1232 if (check->get_active() != yn) {
1233 check->set_active (yn);
1239 RouteUI::disconnect_input ()
1241 _route->input()->disconnect (this);
1245 RouteUI::disconnect_output ()
1247 _route->output()->disconnect (this);
1251 RouteUI::is_track () const
1253 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1256 boost::shared_ptr<Track>
1257 RouteUI::track() const
1259 return boost::dynamic_pointer_cast<Track>(_route);
1263 RouteUI::is_audio_track () const
1265 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1268 boost::shared_ptr<AudioTrack>
1269 RouteUI::audio_track() const
1271 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1275 RouteUI::is_midi_track () const
1277 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1280 boost::shared_ptr<MidiTrack>
1281 RouteUI::midi_track() const
1283 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1286 boost::shared_ptr<Diskstream>
1287 RouteUI::get_diskstream () const
1289 boost::shared_ptr<Track> t;
1291 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1292 return t->diskstream();
1294 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1299 RouteUI::name() const
1301 return _route->name();
1305 RouteUI::map_frozen ()
1307 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1309 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1312 switch (at->freeze_state()) {
1313 case AudioTrack::Frozen:
1314 rec_enable_button->set_sensitive (false);
1317 rec_enable_button->set_sensitive (true);
1324 RouteUI::adjust_latency ()
1326 LatencyDialog dialog (_route->name() + _("latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1330 RouteUI::save_as_template ()
1333 Glib::ustring safe_name;
1336 path = ARDOUR::user_route_template_directory ();
1338 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1339 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1343 Prompter p (true); // modal
1345 p.set_prompt (_("Template name:"));
1347 case RESPONSE_ACCEPT:
1354 p.get_result (name, true);
1356 safe_name = legalize_for_path (name);
1357 safe_name += template_suffix;
1361 _route->save_as_template (path.to_string(), name);
1365 RouteUI::check_rec_enable_sensitivity ()
1367 if (Config->get_disable_disarm_during_roll () == false) {
1371 if (_session.transport_rolling() && rec_enable_button->get_active()) {
1372 rec_enable_button->set_sensitive (false);
1374 rec_enable_button->set_sensitive (true);