2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/stop_signal.h>
22 #include <gtkmm2ext/choice.h>
23 #include <gtkmm2ext/doi.h>
24 #include <gtkmm2ext/bindable_button.h>
25 #include <gtkmm2ext/barcontroller.h>
26 #include <gtkmm2ext/gtk_ui.h>
28 #include "ardour/route_group.h"
29 #include "pbd/memento_command.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/shiva.h"
32 #include "pbd/controllable.h"
34 #include "ardour_ui.h"
40 #include "gui_thread.h"
41 #include "ardour_dialog.h"
42 #include "latency_gui.h"
43 #include "mixer_strip.h"
44 #include "automation_time_axis.h"
46 #include "ardour/route.h"
47 #include "ardour/session.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/audio_track.h"
50 #include "ardour/audio_diskstream.h"
51 #include "ardour/midi_track.h"
52 #include "ardour/midi_diskstream.h"
53 #include "ardour/template_utils.h"
54 #include "ardour/filename_extensions.h"
55 #include "ardour/directory_names.h"
56 #include "ardour/profile.h"
61 using namespace Gtkmm2ext;
62 using namespace ARDOUR;
65 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
69 set_button_names (mute_name, solo_name, rec_name);
72 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
73 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
77 set_button_names (mute_name, solo_name, rec_name);
83 /* derived classes should emit GoingAway so that they receive the signal
84 when the object is still a legal derived instance.
89 delete remote_control_menu;
100 remote_control_menu = 0;
102 ignore_toggle = false;
103 wait_for_release = false;
104 route_active_menu_item = 0;
105 polarity_menu_item = 0;
106 denormal_menu_item = 0;
107 multiple_mute_change = false;
108 multiple_solo_change = false;
110 mute_button = manage (new BindableToggleButton (""));
111 mute_button->set_self_managed (true);
112 mute_button->set_name ("MuteButton");
113 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
115 solo_button = manage (new BindableToggleButton (""));
116 solo_button->set_self_managed (true);
117 solo_button->set_name ("SoloButton");
118 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
119 solo_button->set_no_show_all (true);
121 rec_enable_button = manage (new BindableToggleButton (""));
122 rec_enable_button->set_name ("RecordEnableButton");
123 rec_enable_button->set_self_managed (true);
124 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
126 show_sends_button = manage (new BindableToggleButton (""));
127 show_sends_button->set_name ("SendAlert");
128 show_sends_button->set_self_managed (true);
129 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
131 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
132 _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
134 Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
140 //Remove route connections associated with us.
141 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
145 connections.clear ();
154 /* do not delete the node - its owned by the route */
158 route_active_menu_item = 0;
159 polarity_menu_item = 0;
160 denormal_menu_item = 0;
164 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
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 mute_button->set_label (m_name);
193 solo_button->set_controllable (_route->solo_control());
194 solo_button->set_label (s_name);
196 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
197 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
198 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
199 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
202 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
204 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
205 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (PublicEditor::instance(), &PublicEditor::update_rec_display)));
206 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
208 rec_enable_button->show();
209 rec_enable_button->set_controllable (t->rec_enable_control());
210 rec_enable_button->set_label (r_name);
212 update_rec_display ();
215 mute_button->unset_flags (Gtk::CAN_FOCUS);
216 solo_button->unset_flags (Gtk::CAN_FOCUS);
220 if (_route->is_master()) {
221 solo_button->hide ();
226 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
228 /* map the current state */
237 RouteUI::mute_press(GdkEventButton* ev)
239 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
242 multiple_mute_change = false;
243 if (!ignore_toggle) {
245 if (Keyboard::is_context_menu_event (ev)) {
251 mute_menu->popup(0,ev->time);
255 if (Keyboard::is_button2_event (ev)) {
256 // Primary-button2 click is the midi binding click
257 // button2-click is "momentary"
259 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
260 wait_for_release = true;
266 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
268 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
270 /* Primary-Tertiary-click applies change to all routes */
272 _session.begin_reversible_command (_("mute change"));
273 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
274 _session.set_all_mute (!_route->muted());
276 _session.add_command(cmd);
277 _session.commit_reversible_command ();
278 multiple_mute_change = true;
280 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
282 /* Primary-button1 applies change to the mix group.
283 NOTE: Primary-button2 is MIDI learn.
286 if (ev->button == 1) {
287 set_route_group_mute (_route, !_route->muted());
292 /* plain click applies change to this route */
293 if (wait_for_release) {
294 _route->set_mute (!_route->muted(), this);
296 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
308 RouteUI::mute_release(GdkEventButton* ev)
310 if (!ignore_toggle) {
311 if (wait_for_release){
312 wait_for_release = false;
313 if (multiple_mute_change) {
314 multiple_mute_change = false;
316 // because the press was the last undoable thing we did
319 _route->set_mute (!_route->muted(), this);
327 RouteUI::solo_press(GdkEventButton* ev)
329 /* ignore double/triple clicks */
331 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
334 multiple_solo_change = false;
335 if (!ignore_toggle) {
337 if (Keyboard::is_context_menu_event (ev)) {
339 if (solo_menu == 0) {
343 solo_menu->popup (1, ev->time);
347 if (Keyboard::is_button2_event (ev)) {
349 // Primary-button2 click is the midi binding click
350 // button2-click is "momentary"
352 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
353 wait_for_release = true;
359 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
361 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
363 /* Primary-Tertiary-click applies change to all routes */
364 bool was_not_latched = false;
365 if (!Config->get_solo_latched ()) {
366 was_not_latched = true;
368 XXX it makes no sense to solo all tracks if we're
369 not in latched mode, but doing nothing feels like a bug,
372 Config->set_solo_latched (true);
374 _session.begin_reversible_command (_("solo change"));
375 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
376 _session.set_all_solo (!_route->soloed());
378 _session.add_command (cmd);
379 _session.commit_reversible_command ();
380 multiple_solo_change = true;
381 if (was_not_latched) {
382 Config->set_solo_latched (false);
385 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
387 // Primary-Secondary-click: exclusively solo this track, not a toggle */
389 _session.begin_reversible_command (_("solo change"));
390 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
391 _session.set_all_solo (false);
392 _route->set_solo (true, this);
394 _session.add_command(cmd);
395 _session.commit_reversible_command ();
397 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
399 // shift-click: set this route to solo safe
401 if (Profile->get_sae() && ev->button == 1) {
402 // button 1 and shift-click: disables solo_latched for this click
403 if (!Config->get_solo_latched ()) {
404 Config->set_solo_latched (true);
405 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
406 Config->set_solo_latched (false);
409 _route->set_solo_isolated (!_route->solo_isolated(), this);
410 wait_for_release = false;
413 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
415 /* Primary-button1: solo mix group.
416 NOTE: Primary-button2 is MIDI learn.
419 if (ev->button == 1) {
420 set_route_group_solo (_route, !_route->soloed());
425 /* click: solo this route */
426 if (wait_for_release) {
427 _route->set_solo (!_route->soloed(), this);
429 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
440 RouteUI::solo_release(GdkEventButton* ev)
442 if (!ignore_toggle) {
443 if (wait_for_release) {
444 wait_for_release = false;
445 if (multiple_solo_change) {
446 multiple_solo_change = false;
448 // because the press was the last undoable thing we did
451 // we don't use "undo the last op"
452 // here because its expensive for the GUI
453 _route->set_solo (!_route->soloed(), this);
462 RouteUI::rec_enable_press(GdkEventButton* ev)
464 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
468 if (!_session.engine().connected()) {
469 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
474 if (!ignore_toggle && is_track() && rec_enable_button) {
476 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
478 // do nothing on midi bind event
481 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
483 _session.begin_reversible_command (_("rec-enable change"));
484 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
486 if (rec_enable_button->get_active()) {
487 _session.record_disenable_all ();
489 _session.record_enable_all ();
490 check_rec_enable_sensitivity ();
494 _session.add_command(cmd);
495 _session.commit_reversible_command ();
497 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
499 /* Primary-button1 applies change to the mix group.
500 NOTE: Primary-button2 is MIDI learn.
503 set_route_group_rec_enable (_route, !_route->record_enabled());
506 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
507 check_rec_enable_sensitivity ();
515 RouteUI::rec_enable_release (GdkEventButton* ev)
521 RouteUI::build_sends_menu ()
523 using namespace Menu_Helpers;
525 sends_menu = new Menu;
526 sends_menu->set_name ("ArdourContextMenu");
527 MenuList& items = sends_menu->items();
529 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
530 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
531 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
535 RouteUI::set_sends_gain_from_track ()
540 RouteUI::set_sends_gain_to_zero ()
545 RouteUI::set_sends_gain_to_unity ()
550 RouteUI::show_sends_press(GdkEventButton* ev)
552 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
556 if (!ignore_toggle && !is_track() && show_sends_button) {
558 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
560 // do nothing on midi bind event
563 } else if (Keyboard::is_context_menu_event (ev)) {
565 if (sends_menu == 0) {
569 sends_menu->popup (0, ev->time);
573 /* change button state */
575 show_sends_button->set_active (!show_sends_button->get_active());
579 if (show_sends_button->get_active()) {
580 /* show sends to this bus */
581 MixerStrip::SwitchIO (_route);
582 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
584 /* everybody back to normal */
585 send_blink_connection.disconnect ();
586 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
596 RouteUI::show_sends_release (GdkEventButton* ev)
602 RouteUI::send_blink (bool onoff)
604 if (!show_sends_button) {
609 show_sends_button->set_state (STATE_ACTIVE);
611 show_sends_button->set_state (STATE_NORMAL);
616 RouteUI::solo_changed(void* src)
619 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
623 RouteUI::update_solo_display ()
626 vector<Gdk::Color> fg_colors;
629 if (solo_button->get_active() != (x = _route->soloed())){
630 ignore_toggle = true;
631 solo_button->set_active(x);
632 ignore_toggle = false;
635 if (_route->solo_isolated()) {
636 solo_button->set_visual_state (2);
637 } else if (_route->soloed()) {
638 solo_button->set_visual_state (1);
640 solo_button->set_visual_state (0);
645 RouteUI::solo_changed_so_update_mute ()
647 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
651 RouteUI::mute_changed(void* src)
653 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
657 RouteUI::update_mute_display ()
659 bool model = _route->muted();
660 bool view = mute_button->get_active();
662 /* first make sure the button's "depressed" visual
667 ignore_toggle = true;
668 mute_button->set_active (model);
669 ignore_toggle = false;
672 /* now attend to visual state */
674 if (Config->get_show_solo_mutes()) {
675 if (_route->muted()) {
676 mute_button->set_visual_state (2);
677 } else if (!_route->soloed() && _session.soloing()) {
678 mute_button->set_visual_state (1);
680 mute_button->set_visual_state (0);
683 if (_route->muted()) {
684 mute_button->set_visual_state (2);
686 mute_button->set_visual_state (0);
693 RouteUI::route_rec_enable_changed ()
695 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
699 RouteUI::session_rec_enable_changed ()
701 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
705 RouteUI::update_rec_display ()
707 bool model = _route->record_enabled();
708 bool view = rec_enable_button->get_active();
710 /* first make sure the button's "depressed" visual
715 ignore_toggle = true;
716 rec_enable_button->set_active (model);
717 ignore_toggle = false;
723 /* now make sure its color state is correct */
727 switch (_session.record_status ()) {
728 case Session::Recording:
729 rec_enable_button->set_visual_state (1);
732 case Session::Disabled:
733 case Session::Enabled:
734 rec_enable_button->set_visual_state (2);
740 rec_enable_button->set_visual_state (0);
745 RouteUI::build_remote_control_menu ()
747 remote_control_menu = new Menu;
748 refresh_remote_control_menu ();
752 RouteUI::refresh_remote_control_menu ()
754 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
756 // only refresh the menu if it has been instantiated
758 if (remote_control_menu == 0) {
762 using namespace Menu_Helpers;
764 RadioMenuItem::Group rc_group;
765 CheckMenuItem* rc_active;
766 uint32_t limit = _session.ntracks() + _session.nbusses();
769 MenuList& rc_items = remote_control_menu->items();
772 /* note that this menu list starts at zero, not 1, because zero
773 is a valid, if useless, ID.
776 limit += 4; /* leave some breathing room */
778 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
779 if (_route->remote_control_id() == 0) {
780 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
781 rc_active->set_active ();
784 for (uint32_t i = 1; i < limit; ++i) {
785 snprintf (buf, sizeof (buf), "%u", i);
786 rc_items.push_back (RadioMenuElem (rc_group, buf));
787 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
788 if (_route->remote_control_id() == i) {
789 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
790 rc_active->set_active ();
792 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
797 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
799 /* this is called when the radio menu item is toggled, and so
800 is actually invoked twice per menu selection. we only
801 care about the invocation for the item that was being
805 if (item->get_active()) {
806 _route->set_remote_control_id (id);
811 RouteUI::build_solo_menu (void)
813 using namespace Menu_Helpers;
815 solo_menu = new Menu;
816 solo_menu->set_name ("ArdourContextMenu");
817 MenuList& items = solo_menu->items();
818 CheckMenuItem* check;
820 check = new CheckMenuItem(_("Solo Isolate"));
821 check->set_active (_route->solo_isolated());
822 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
823 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
824 items.push_back (CheckMenuElem(*check));
827 //items.push_back (SeparatorElem());
828 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
833 RouteUI::build_mute_menu(void)
835 using namespace Menu_Helpers;
837 mute_menu = new Menu;
838 mute_menu->set_name ("ArdourContextMenu");
841 MenuList& items = mute_menu->items();
842 CheckMenuItem* check;
844 check = new CheckMenuItem(_("Pre Fader"));
845 init_mute_menu(PRE_FADER, check);
846 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
847 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
848 items.push_back (CheckMenuElem(*check));
851 check = new CheckMenuItem(_("Post Fader"));
852 init_mute_menu(POST_FADER, check);
853 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
854 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
855 items.push_back (CheckMenuElem(*check));
858 check = new CheckMenuItem(_("Control Outs"));
859 init_mute_menu(CONTROL_OUTS, check);
860 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
861 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
862 items.push_back (CheckMenuElem(*check));
865 check = new CheckMenuItem(_("Main Outs"));
866 init_mute_menu(MAIN_OUTS, check);
867 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
868 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
869 items.push_back (CheckMenuElem(*check));
872 //items.push_back (SeparatorElem());
873 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
877 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
879 check->set_active (_route->mute_master()->muted_at (mp));
883 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
885 // _route->set_mute_config(type, check->get_active(), this);
889 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
891 _route->set_solo_isolated (check->get_active(), this);
895 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
897 RouteGroup* route_group;
899 if((route_group = route->route_group()) != 0){
900 _session.begin_reversible_command (_("mix group solo change"));
901 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
902 route_group->apply(&Route::set_solo, yn, this);
904 _session.add_command (cmd);
905 _session.commit_reversible_command ();
907 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
912 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
914 _session.begin_reversible_command (name);
915 XMLNode &before = _route->get_state();
916 bind(mem_fun(*_route, func), yn, arg)();
917 XMLNode &after = _route->get_state();
918 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
919 _session.commit_reversible_command ();
923 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
925 _session.begin_reversible_command (name);
926 XMLNode &before = track()->get_state();
927 bind (mem_fun (*track(), func), yn, arg)();
928 XMLNode &after = track()->get_state();
929 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
930 _session.commit_reversible_command ();
934 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
936 RouteGroup* route_group;
938 if((route_group = route->route_group()) != 0){
939 _session.begin_reversible_command (_("mix group mute change"));
940 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
941 route_group->apply(&Route::set_mute, yn, this);
943 _session.add_command(cmd);
944 _session.commit_reversible_command ();
946 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
951 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
953 RouteGroup* route_group;
955 if((route_group = route->route_group()) != 0){
956 _session.begin_reversible_command (_("mix group rec-enable change"));
957 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
958 route_group->apply (&Route::set_record_enable, yn, this);
960 _session.add_command(cmd);
961 _session.commit_reversible_command ();
963 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
969 RouteUI::choose_color()
974 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
984 RouteUI::set_color (const Gdk::Color & c)
991 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
992 xml_node->add_property ("color", buf);
994 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
999 RouteUI::ensure_xml_node ()
1001 if (xml_node == 0) {
1002 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1003 xml_node = new XMLNode ("GUI");
1004 _route->add_extra_xml (*xml_node);
1010 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1014 XMLNodeList kids = xml_node->children();
1015 XMLNodeConstIterator iter;
1017 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1019 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1020 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1021 XMLProperty* type = (*iter)->property("automation-id");
1022 if (type && type->value() == sym)
1027 // Didn't find it, make a new one
1028 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1029 child->add_property("automation-id", sym);
1030 xml_node->add_child_nocopy (*child);
1036 RouteUI::set_color_from_route ()
1040 RouteUI::ensure_xml_node ();
1042 if ((prop = xml_node->property ("color")) != 0) {
1044 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1046 _color.set_green(g);
1054 RouteUI::remove_this_route ()
1056 vector<string> choices;
1060 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());
1062 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1065 choices.push_back (_("No, do nothing."));
1066 choices.push_back (_("Yes, remove it."));
1068 Choice prompter (prompt, choices);
1070 if (prompter.run () == 1) {
1071 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1076 RouteUI::idle_remove_this_route (RouteUI *rui)
1078 rui->_session.remove_route (rui->_route);
1083 RouteUI::route_rename ()
1085 ArdourPrompter name_prompter (true);
1087 name_prompter.set_prompt (_("New Name: "));
1088 name_prompter.set_initial_text (_route->name());
1089 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1090 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1091 name_prompter.show_all ();
1093 switch (name_prompter.run ()) {
1095 case Gtk::RESPONSE_ACCEPT:
1096 name_prompter.get_result (result);
1097 if (result.length()) {
1098 _route->set_name (result);
1108 RouteUI::name_changed ()
1110 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1112 name_label.set_text (_route->name());
1116 RouteUI::toggle_route_active ()
1120 if (route_active_menu_item) {
1121 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1122 _route->set_active (!yn);
1128 RouteUI::route_active_changed ()
1130 if (route_active_menu_item) {
1131 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1136 RouteUI::toggle_polarity ()
1138 if (polarity_menu_item) {
1142 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1144 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1145 _route->set_phase_invert (x);
1147 name_label.set_text (X_("Ø ") + name_label.get_text());
1149 name_label.set_text (_route->name());
1156 RouteUI::polarity_changed ()
1158 if (_route->phase_invert()) {
1159 name_label.set_text (X_("Ø ") + name_label.get_text());
1161 name_label.set_text (_route->name());
1166 RouteUI::toggle_denormal_protection ()
1168 if (denormal_menu_item) {
1172 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1174 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1175 _route->set_denormal_protection (x);
1181 RouteUI::denormal_protection_changed ()
1183 if (denormal_menu_item) {
1184 denormal_menu_item->set_active (_route->denormal_protection());
1189 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1191 bool yn = _route->solo_isolated ();
1193 if (check->get_active() != yn) {
1194 check->set_active (yn);
1198 #ifdef FIX_THIS_FOR_3_0
1200 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1202 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1204 bool yn = _route->get_mute_config(PRE_FADER);
1205 if (check->get_active() != yn) {
1206 check->set_active (yn);
1211 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1213 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1215 bool yn = _route->get_mute_config(POST_FADER);
1216 if (check->get_active() != yn) {
1217 check->set_active (yn);
1222 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1224 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1226 bool yn = _route->get_mute_config(CONTROL_OUTS);
1227 if (check->get_active() != yn) {
1228 check->set_active (yn);
1233 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1235 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1237 bool yn = _route->get_mute_config(MAIN_OUTS);
1238 if (check->get_active() != yn) {
1239 check->set_active (yn);
1245 RouteUI::disconnect_input ()
1247 _route->input()->disconnect (this);
1251 RouteUI::disconnect_output ()
1253 _route->output()->disconnect (this);
1257 RouteUI::is_track () const
1259 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1262 boost::shared_ptr<Track>
1263 RouteUI::track() const
1265 return boost::dynamic_pointer_cast<Track>(_route);
1269 RouteUI::is_audio_track () const
1271 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1274 boost::shared_ptr<AudioTrack>
1275 RouteUI::audio_track() const
1277 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1281 RouteUI::is_midi_track () const
1283 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1286 boost::shared_ptr<MidiTrack>
1287 RouteUI::midi_track() const
1289 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1292 boost::shared_ptr<Diskstream>
1293 RouteUI::get_diskstream () const
1295 boost::shared_ptr<Track> t;
1297 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1298 return t->diskstream();
1300 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1305 RouteUI::name() const
1307 return _route->name();
1311 RouteUI::map_frozen ()
1313 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1315 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1318 switch (at->freeze_state()) {
1319 case AudioTrack::Frozen:
1320 rec_enable_button->set_sensitive (false);
1323 rec_enable_button->set_sensitive (true);
1330 RouteUI::adjust_latency ()
1332 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1336 RouteUI::save_as_template ()
1339 Glib::ustring safe_name;
1342 path = ARDOUR::user_route_template_directory ();
1344 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1345 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1349 Prompter p (true); // modal
1351 p.set_prompt (_("Template name:"));
1353 case RESPONSE_ACCEPT:
1360 p.get_result (name, true);
1362 safe_name = legalize_for_path (name);
1363 safe_name += template_suffix;
1367 _route->save_as_template (path.to_string(), name);
1371 RouteUI::check_rec_enable_sensitivity ()
1373 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1374 rec_enable_button->set_sensitive (false);
1376 rec_enable_button->set_sensitive (true);
1381 RouteUI::parameter_changed (string const & p)
1383 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1385 if (p == "disable-disarm-during-roll") {
1386 check_rec_enable_sensitivity ();