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));
133 Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
139 //Remove route connections associated with us.
140 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
144 connections.clear ();
153 /* do not delete the node - its owned by the route */
157 route_active_menu_item = 0;
158 polarity_menu_item = 0;
159 denormal_menu_item = 0;
163 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
171 RouteUI::set_route (boost::shared_ptr<Route> rp)
177 if (set_color_from_route()) {
178 set_color (unique_random_color());
181 /* no, there is no memory leak here. This object cleans itself (and other stuff)
182 up when the route is destroyed.
186 new PairedShiva<Route,RouteUI> (*_route, *this);
189 mute_button->set_controllable (_route->mute_control());
190 mute_button->set_label (m_name);
192 solo_button->set_controllable (_route->solo_control());
193 solo_button->set_label (s_name);
195 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
196 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
197 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
198 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
201 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
203 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
204 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
206 rec_enable_button->show();
207 rec_enable_button->set_controllable (t->rec_enable_control());
208 rec_enable_button->set_label (r_name);
210 update_rec_display ();
213 mute_button->unset_flags (Gtk::CAN_FOCUS);
214 solo_button->unset_flags (Gtk::CAN_FOCUS);
218 if (_route->is_master()) {
219 solo_button->hide ();
224 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
226 /* map the current state */
235 RouteUI::mute_press(GdkEventButton* ev)
237 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
240 multiple_mute_change = false;
241 if (!ignore_toggle) {
243 if (Keyboard::is_context_menu_event (ev)) {
249 mute_menu->popup(0,ev->time);
253 if (Keyboard::is_button2_event (ev)) {
254 // Primary-button2 click is the midi binding click
255 // button2-click is "momentary"
257 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
258 wait_for_release = true;
264 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
266 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
268 /* Primary-Tertiary-click applies change to all routes */
270 _session.begin_reversible_command (_("mute change"));
271 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
272 _session.set_all_mute (!_route->muted());
274 _session.add_command(cmd);
275 _session.commit_reversible_command ();
276 multiple_mute_change = true;
278 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
280 /* Primary-button1 applies change to the mix group.
281 NOTE: Primary-button2 is MIDI learn.
284 if (ev->button == 1) {
285 set_mix_group_mute (_route, !_route->muted());
290 /* plain click applies change to this route */
291 if (wait_for_release) {
292 _route->set_mute (!_route->muted(), this);
294 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
306 RouteUI::mute_release(GdkEventButton* ev)
308 if (!ignore_toggle) {
309 if (wait_for_release){
310 wait_for_release = false;
311 if (multiple_mute_change) {
312 multiple_mute_change = false;
314 // because the press was the last undoable thing we did
317 _route->set_mute (!_route->muted(), this);
325 RouteUI::solo_press(GdkEventButton* ev)
327 /* ignore double/triple clicks */
329 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
332 multiple_solo_change = false;
333 if (!ignore_toggle) {
335 if (Keyboard::is_context_menu_event (ev)) {
337 if (solo_menu == 0) {
341 solo_menu->popup (1, ev->time);
345 if (Keyboard::is_button2_event (ev)) {
347 // Primary-button2 click is the midi binding click
348 // button2-click is "momentary"
350 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
351 wait_for_release = true;
357 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
359 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
361 /* Primary-Tertiary-click applies change to all routes */
362 bool was_not_latched = false;
363 if (!Config->get_solo_latched ()) {
364 was_not_latched = true;
366 XXX it makes no sense to solo all tracks if we're
367 not in latched mode, but doing nothing feels like a bug,
370 Config->set_solo_latched (true);
372 _session.begin_reversible_command (_("solo change"));
373 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
374 _session.set_all_solo (!_route->soloed());
376 _session.add_command (cmd);
377 _session.commit_reversible_command ();
378 multiple_solo_change = true;
379 if (was_not_latched) {
380 Config->set_solo_latched (false);
383 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
385 // Primary-Secondary-click: exclusively solo this track, not a toggle */
387 _session.begin_reversible_command (_("solo change"));
388 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
389 _session.set_all_solo (false);
390 _route->set_solo (true, this);
392 _session.add_command(cmd);
393 _session.commit_reversible_command ();
395 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
397 // shift-click: set this route to solo safe
399 if (Profile->get_sae() && ev->button == 1) {
400 // button 1 and shift-click: disables solo_latched for this click
401 if (!Config->get_solo_latched ()) {
402 Config->set_solo_latched (true);
403 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
404 Config->set_solo_latched (false);
407 _route->set_solo_isolated (!_route->solo_isolated(), this);
408 wait_for_release = false;
411 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
413 /* Primary-button1: solo mix group.
414 NOTE: Primary-button2 is MIDI learn.
417 if (ev->button == 1) {
418 set_mix_group_solo (_route, !_route->soloed());
423 /* click: solo this route */
424 if (wait_for_release) {
425 _route->set_solo (!_route->soloed(), this);
427 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
438 RouteUI::solo_release(GdkEventButton* ev)
440 if (!ignore_toggle) {
441 if (wait_for_release) {
442 wait_for_release = false;
443 if (multiple_solo_change) {
444 multiple_solo_change = false;
446 // because the press was the last undoable thing we did
449 // we don't use "undo the last op"
450 // here because its expensive for the GUI
451 _route->set_solo (!_route->soloed(), this);
460 RouteUI::rec_enable_press(GdkEventButton* ev)
462 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
466 if (!_session.engine().connected()) {
467 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
472 if (!ignore_toggle && is_track() && rec_enable_button) {
474 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
476 // do nothing on midi bind event
479 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
481 _session.begin_reversible_command (_("rec-enable change"));
482 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
484 if (rec_enable_button->get_active()) {
485 _session.record_disenable_all ();
487 _session.record_enable_all ();
488 check_rec_enable_sensitivity ();
492 _session.add_command(cmd);
493 _session.commit_reversible_command ();
495 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
497 /* Primary-button1 applies change to the mix group.
498 NOTE: Primary-button2 is MIDI learn.
501 set_mix_group_rec_enable (_route, !_route->record_enabled());
505 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
506 check_rec_enable_sensitivity ();
514 RouteUI::rec_enable_release (GdkEventButton* ev)
520 RouteUI::build_sends_menu ()
522 using namespace Menu_Helpers;
524 sends_menu = new Menu;
525 sends_menu->set_name ("ArdourContextMenu");
526 MenuList& items = sends_menu->items();
528 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
529 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
530 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
534 RouteUI::set_sends_gain_from_track ()
539 RouteUI::set_sends_gain_to_zero ()
544 RouteUI::set_sends_gain_to_unity ()
549 RouteUI::show_sends_press(GdkEventButton* ev)
551 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
555 if (!ignore_toggle && !is_track() && show_sends_button) {
557 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
559 // do nothing on midi bind event
562 } else if (Keyboard::is_context_menu_event (ev)) {
564 if (sends_menu == 0) {
568 sends_menu->popup (0, ev->time);
572 /* change button state */
574 show_sends_button->set_active (!show_sends_button->get_active());
578 if (show_sends_button->get_active()) {
579 /* show sends to this bus */
580 MixerStrip::SwitchIO (_route);
581 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
583 /* everybody back to normal */
584 send_blink_connection.disconnect ();
585 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
595 RouteUI::show_sends_release (GdkEventButton* ev)
601 RouteUI::send_blink (bool onoff)
603 if (!show_sends_button) {
608 show_sends_button->set_state (STATE_ACTIVE);
610 show_sends_button->set_state (STATE_NORMAL);
615 RouteUI::solo_changed(void* src)
618 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
622 RouteUI::update_solo_display ()
625 vector<Gdk::Color> fg_colors;
628 if (solo_button->get_active() != (x = _route->soloed())){
629 ignore_toggle = true;
630 solo_button->set_active(x);
631 ignore_toggle = false;
634 if (_route->solo_isolated()) {
635 solo_button->set_visual_state (2);
636 } else if (_route->soloed()) {
637 solo_button->set_visual_state (1);
639 solo_button->set_visual_state (0);
644 RouteUI::solo_changed_so_update_mute ()
646 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
650 RouteUI::mute_changed(void* src)
652 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
656 RouteUI::update_mute_display ()
658 bool model = _route->muted();
659 bool view = mute_button->get_active();
661 /* first make sure the button's "depressed" visual
666 ignore_toggle = true;
667 mute_button->set_active (model);
668 ignore_toggle = false;
671 /* now attend to visual state */
673 if (Config->get_show_solo_mutes()) {
674 if (_route->muted()) {
675 mute_button->set_visual_state (2);
676 } else if (!_route->soloed() && _session.soloing()) {
677 mute_button->set_visual_state (1);
679 mute_button->set_visual_state (0);
682 if (_route->muted()) {
683 mute_button->set_visual_state (2);
685 mute_button->set_visual_state (0);
692 RouteUI::route_rec_enable_changed ()
694 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
698 RouteUI::session_rec_enable_changed ()
700 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
704 RouteUI::update_rec_display ()
706 bool model = _route->record_enabled();
707 bool view = rec_enable_button->get_active();
709 /* first make sure the button's "depressed" visual
714 ignore_toggle = true;
715 rec_enable_button->set_active (model);
716 ignore_toggle = false;
719 /* now make sure its color state is correct */
723 switch (_session.record_status ()) {
724 case Session::Recording:
725 rec_enable_button->set_visual_state (1);
728 case Session::Disabled:
729 case Session::Enabled:
730 rec_enable_button->set_visual_state (2);
736 rec_enable_button->set_visual_state (0);
741 RouteUI::build_remote_control_menu ()
743 remote_control_menu = new Menu;
744 refresh_remote_control_menu ();
748 RouteUI::refresh_remote_control_menu ()
750 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
752 // only refresh the menu if it has been instantiated
754 if (remote_control_menu == 0) {
758 using namespace Menu_Helpers;
760 RadioMenuItem::Group rc_group;
761 CheckMenuItem* rc_active;
762 uint32_t limit = _session.ntracks() + _session.nbusses();
765 MenuList& rc_items = remote_control_menu->items();
768 /* note that this menu list starts at zero, not 1, because zero
769 is a valid, if useless, ID.
772 limit += 4; /* leave some breathing room */
774 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
775 if (_route->remote_control_id() == 0) {
776 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
777 rc_active->set_active ();
780 for (uint32_t i = 1; i < limit; ++i) {
781 snprintf (buf, sizeof (buf), "%u", i);
782 rc_items.push_back (RadioMenuElem (rc_group, buf));
783 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
784 if (_route->remote_control_id() == i) {
785 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
786 rc_active->set_active ();
788 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
793 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
795 /* this is called when the radio menu item is toggled, and so
796 is actually invoked twice per menu selection. we only
797 care about the invocation for the item that was being
801 if (item->get_active()) {
802 _route->set_remote_control_id (id);
807 RouteUI::build_solo_menu (void)
809 using namespace Menu_Helpers;
811 solo_menu = new Menu;
812 solo_menu->set_name ("ArdourContextMenu");
813 MenuList& items = solo_menu->items();
814 CheckMenuItem* check;
816 check = new CheckMenuItem(_("Solo Isolate"));
817 check->set_active (_route->solo_isolated());
818 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
819 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
820 items.push_back (CheckMenuElem(*check));
823 //items.push_back (SeparatorElem());
824 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
829 RouteUI::build_mute_menu(void)
831 using namespace Menu_Helpers;
833 mute_menu = new Menu;
834 mute_menu->set_name ("ArdourContextMenu");
837 MenuList& items = mute_menu->items();
838 CheckMenuItem* check;
840 check = new CheckMenuItem(_("Pre Fader"));
841 init_mute_menu(PRE_FADER, check);
842 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
843 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
844 items.push_back (CheckMenuElem(*check));
847 check = new CheckMenuItem(_("Post Fader"));
848 init_mute_menu(POST_FADER, check);
849 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
850 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
851 items.push_back (CheckMenuElem(*check));
854 check = new CheckMenuItem(_("Control Outs"));
855 init_mute_menu(CONTROL_OUTS, check);
856 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
857 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
858 items.push_back (CheckMenuElem(*check));
861 check = new CheckMenuItem(_("Main Outs"));
862 init_mute_menu(MAIN_OUTS, check);
863 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
864 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
865 items.push_back (CheckMenuElem(*check));
868 //items.push_back (SeparatorElem());
869 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
873 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
875 check->set_active (_route->mute_master()->muted_at (mp));
879 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
881 // _route->set_mute_config(type, check->get_active(), this);
885 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
887 _route->set_solo_isolated (check->get_active(), this);
891 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
893 RouteGroup* mix_group;
895 if((mix_group = route->mix_group()) != 0){
896 _session.begin_reversible_command (_("mix group solo change"));
897 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
898 mix_group->apply(&Route::set_solo, yn, this);
900 _session.add_command (cmd);
901 _session.commit_reversible_command ();
903 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
908 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
910 _session.begin_reversible_command (name);
911 XMLNode &before = _route->get_state();
912 bind(mem_fun(*_route, func), yn, arg)();
913 XMLNode &after = _route->get_state();
914 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
915 _session.commit_reversible_command ();
919 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
921 _session.begin_reversible_command (name);
922 XMLNode &before = track()->get_state();
923 bind (mem_fun (*track(), func), yn, arg)();
924 XMLNode &after = track()->get_state();
925 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
926 _session.commit_reversible_command ();
930 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
932 RouteGroup* mix_group;
934 if((mix_group = route->mix_group()) != 0){
935 _session.begin_reversible_command (_("mix group mute change"));
936 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
937 mix_group->apply(&Route::set_mute, yn, this);
939 _session.add_command(cmd);
940 _session.commit_reversible_command ();
942 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
947 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
949 RouteGroup* mix_group;
951 if((mix_group = route->mix_group()) != 0){
952 _session.begin_reversible_command (_("mix group rec-enable change"));
953 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
954 mix_group->apply (&Route::set_record_enable, yn, this);
956 _session.add_command(cmd);
957 _session.commit_reversible_command ();
959 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
965 RouteUI::choose_color()
970 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
980 RouteUI::set_color (const Gdk::Color & c)
987 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
988 xml_node->add_property ("color", buf);
990 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
995 RouteUI::ensure_xml_node ()
998 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
999 xml_node = new XMLNode ("GUI");
1000 _route->add_extra_xml (*xml_node);
1006 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1010 XMLNodeList kids = xml_node->children();
1011 XMLNodeConstIterator iter;
1013 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1015 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1016 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1017 XMLProperty* type = (*iter)->property("automation-id");
1018 if (type && type->value() == sym)
1023 // Didn't find it, make a new one
1024 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1025 child->add_property("automation-id", sym);
1026 xml_node->add_child_nocopy (*child);
1032 RouteUI::set_color_from_route ()
1036 RouteUI::ensure_xml_node ();
1038 if ((prop = xml_node->property ("color")) != 0) {
1040 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1042 _color.set_green(g);
1050 RouteUI::remove_this_route ()
1052 vector<string> choices;
1056 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());
1058 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1061 choices.push_back (_("No, do nothing."));
1062 choices.push_back (_("Yes, remove it."));
1064 Choice prompter (prompt, choices);
1066 if (prompter.run () == 1) {
1067 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1072 RouteUI::idle_remove_this_route (RouteUI *rui)
1074 rui->_session.remove_route (rui->_route);
1079 RouteUI::route_rename ()
1081 ArdourPrompter name_prompter (true);
1083 name_prompter.set_prompt (_("New Name: "));
1084 name_prompter.set_initial_text (_route->name());
1085 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1086 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1087 name_prompter.show_all ();
1089 switch (name_prompter.run ()) {
1091 case Gtk::RESPONSE_ACCEPT:
1092 name_prompter.get_result (result);
1093 if (result.length()) {
1094 _route->set_name (result);
1104 RouteUI::name_changed ()
1106 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1108 name_label.set_text (_route->name());
1112 RouteUI::toggle_route_active ()
1116 if (route_active_menu_item) {
1117 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1118 _route->set_active (!yn);
1124 RouteUI::route_active_changed ()
1126 if (route_active_menu_item) {
1127 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1132 RouteUI::toggle_polarity ()
1134 if (polarity_menu_item) {
1138 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1140 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1141 _route->set_phase_invert (x);
1143 name_label.set_text (X_("Ø ") + name_label.get_text());
1145 name_label.set_text (_route->name());
1152 RouteUI::polarity_changed ()
1154 if (_route->phase_invert()) {
1155 name_label.set_text (X_("Ø ") + name_label.get_text());
1157 name_label.set_text (_route->name());
1162 RouteUI::toggle_denormal_protection ()
1164 if (denormal_menu_item) {
1168 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1170 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1171 _route->set_denormal_protection (x);
1177 RouteUI::denormal_protection_changed ()
1179 if (denormal_menu_item) {
1180 denormal_menu_item->set_active (_route->denormal_protection());
1185 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1187 bool yn = _route->solo_isolated ();
1189 if (check->get_active() != yn) {
1190 check->set_active (yn);
1194 #ifdef FIX_THIS_FOR_3_0
1196 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1198 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1200 bool yn = _route->get_mute_config(PRE_FADER);
1201 if (check->get_active() != yn) {
1202 check->set_active (yn);
1207 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1209 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1211 bool yn = _route->get_mute_config(POST_FADER);
1212 if (check->get_active() != yn) {
1213 check->set_active (yn);
1218 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1220 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1222 bool yn = _route->get_mute_config(CONTROL_OUTS);
1223 if (check->get_active() != yn) {
1224 check->set_active (yn);
1229 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1231 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1233 bool yn = _route->get_mute_config(MAIN_OUTS);
1234 if (check->get_active() != yn) {
1235 check->set_active (yn);
1241 RouteUI::disconnect_input ()
1243 _route->input()->disconnect (this);
1247 RouteUI::disconnect_output ()
1249 _route->output()->disconnect (this);
1253 RouteUI::is_track () const
1255 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1258 boost::shared_ptr<Track>
1259 RouteUI::track() const
1261 return boost::dynamic_pointer_cast<Track>(_route);
1265 RouteUI::is_audio_track () const
1267 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1270 boost::shared_ptr<AudioTrack>
1271 RouteUI::audio_track() const
1273 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1277 RouteUI::is_midi_track () const
1279 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1282 boost::shared_ptr<MidiTrack>
1283 RouteUI::midi_track() const
1285 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1288 boost::shared_ptr<Diskstream>
1289 RouteUI::get_diskstream () const
1291 boost::shared_ptr<Track> t;
1293 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1294 return t->diskstream();
1296 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1301 RouteUI::name() const
1303 return _route->name();
1307 RouteUI::map_frozen ()
1309 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1311 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1314 switch (at->freeze_state()) {
1315 case AudioTrack::Frozen:
1316 rec_enable_button->set_sensitive (false);
1319 rec_enable_button->set_sensitive (true);
1326 RouteUI::adjust_latency ()
1328 LatencyDialog dialog (_route->name() + _("latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1332 RouteUI::save_as_template ()
1335 Glib::ustring safe_name;
1338 path = ARDOUR::user_route_template_directory ();
1340 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1341 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1345 Prompter p (true); // modal
1347 p.set_prompt (_("Template name:"));
1349 case RESPONSE_ACCEPT:
1356 p.get_result (name, true);
1358 safe_name = legalize_for_path (name);
1359 safe_name += template_suffix;
1363 _route->save_as_template (path.to_string(), name);
1367 RouteUI::check_rec_enable_sensitivity ()
1369 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1370 rec_enable_button->set_sensitive (false);
1372 rec_enable_button->set_sensitive (true);
1377 RouteUI::parameter_changed (string const & p)
1379 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1381 if (p == "disable-disarm-during-roll") {
1382 check_rec_enable_sensitivity ();