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"), "");
119 rec_enable_button = manage (new BindableToggleButton (""));
120 rec_enable_button->set_name ("RecordEnableButton");
121 rec_enable_button->set_self_managed (true);
122 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
124 show_sends_button = manage (new BindableToggleButton (""));
125 show_sends_button->set_name ("SendAlert");
126 show_sends_button->set_self_managed (true);
127 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
129 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
135 //Remove route connections associated with us.
136 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
140 connections.clear ();
149 /* do not delete the node - its owned by the route */
153 route_active_menu_item = 0;
154 polarity_menu_item = 0;
155 denormal_menu_item = 0;
159 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
167 RouteUI::set_route (boost::shared_ptr<Route> rp)
173 if (set_color_from_route()) {
174 set_color (unique_random_color());
177 /* no, there is no memory leak here. This object cleans itself (and other stuff)
178 up when the route is destroyed.
182 new PairedShiva<Route,RouteUI> (*_route, *this);
185 mute_button->set_controllable (_route->mute_control());
186 mute_button->set_label (m_name);
188 solo_button->set_controllable (_route->solo_control());
189 solo_button->set_label (s_name);
191 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
192 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
193 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
194 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
197 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
199 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
200 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
202 rec_enable_button->show();
203 rec_enable_button->set_controllable (t->rec_enable_control());
204 rec_enable_button->set_label (r_name);
206 update_rec_display ();
209 mute_button->unset_flags (Gtk::CAN_FOCUS);
210 solo_button->unset_flags (Gtk::CAN_FOCUS);
215 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
217 /* map the current state */
226 RouteUI::mute_press(GdkEventButton* ev)
228 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
231 multiple_mute_change = false;
232 if (!ignore_toggle) {
234 if (Keyboard::is_context_menu_event (ev)) {
240 mute_menu->popup(0,ev->time);
244 if (Keyboard::is_button2_event (ev)) {
245 // Primary-button2 click is the midi binding click
246 // button2-click is "momentary"
248 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
249 wait_for_release = true;
255 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
257 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
259 /* Primary-Tertiary-click applies change to all routes */
261 _session.begin_reversible_command (_("mute change"));
262 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
263 _session.set_all_mute (!_route->muted());
265 _session.add_command(cmd);
266 _session.commit_reversible_command ();
267 multiple_mute_change = true;
269 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
271 /* Primary-button1 applies change to the mix group.
272 NOTE: Primary-button2 is MIDI learn.
275 if (ev->button == 1) {
276 set_mix_group_mute (_route, !_route->muted());
281 /* plain click applies change to this route */
282 if (wait_for_release) {
283 _route->set_mute (!_route->muted(), this);
285 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
297 RouteUI::mute_release(GdkEventButton* ev)
299 if (!ignore_toggle) {
300 if (wait_for_release){
301 wait_for_release = false;
302 if (multiple_mute_change) {
303 multiple_mute_change = false;
305 // because the press was the last undoable thing we did
308 _route->set_mute (!_route->muted(), this);
316 RouteUI::solo_press(GdkEventButton* ev)
318 /* ignore double/triple clicks */
320 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
323 multiple_solo_change = false;
324 if (!ignore_toggle) {
326 if (Keyboard::is_context_menu_event (ev)) {
328 if (solo_menu == 0) {
332 solo_menu->popup (1, ev->time);
336 if (Keyboard::is_button2_event (ev)) {
338 // Primary-button2 click is the midi binding click
339 // button2-click is "momentary"
341 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
342 wait_for_release = true;
348 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
350 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
352 /* Primary-Tertiary-click applies change to all routes */
353 bool was_not_latched = false;
354 if (!Config->get_solo_latched ()) {
355 was_not_latched = true;
357 XXX it makes no sense to solo all tracks if we're
358 not in latched mode, but doing nothing feels like a bug,
361 Config->set_solo_latched (true);
363 _session.begin_reversible_command (_("solo change"));
364 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
365 _session.set_all_solo (!_route->soloed());
367 _session.add_command (cmd);
368 _session.commit_reversible_command ();
369 multiple_solo_change = true;
370 if (was_not_latched) {
371 Config->set_solo_latched (false);
374 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
376 // Primary-Secondary-click: exclusively solo this track, not a toggle */
378 _session.begin_reversible_command (_("solo change"));
379 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
380 _session.set_all_solo (false);
381 _route->set_solo (true, this);
383 _session.add_command(cmd);
384 _session.commit_reversible_command ();
386 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
388 // shift-click: set this route to solo safe
390 if (Profile->get_sae() && ev->button == 1) {
391 // button 1 and shift-click: disables solo_latched for this click
392 if (!Config->get_solo_latched ()) {
393 Config->set_solo_latched (true);
394 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
395 Config->set_solo_latched (false);
398 _route->set_solo_isolated (!_route->solo_isolated(), this);
399 wait_for_release = false;
402 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
404 /* Primary-button1: solo mix group.
405 NOTE: Primary-button2 is MIDI learn.
408 if (ev->button == 1) {
409 set_mix_group_solo (_route, !_route->soloed());
414 /* click: solo this route */
415 if (wait_for_release) {
416 _route->set_solo (!_route->soloed(), this);
418 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
429 RouteUI::solo_release(GdkEventButton* ev)
431 if (!ignore_toggle) {
432 if (wait_for_release) {
433 wait_for_release = false;
434 if (multiple_solo_change) {
435 multiple_solo_change = false;
437 // because the press was the last undoable thing we did
440 // we don't use "undo the last op"
441 // here because its expensive for the GUI
442 _route->set_solo (!_route->soloed(), this);
451 RouteUI::rec_enable_press(GdkEventButton* ev)
453 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
457 if (!_session.engine().connected()) {
458 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
463 if (!ignore_toggle && is_track() && rec_enable_button) {
465 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
467 // do nothing on midi bind event
470 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
472 _session.begin_reversible_command (_("rec-enable change"));
473 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
475 if (rec_enable_button->get_active()) {
476 _session.record_disenable_all ();
478 _session.record_enable_all ();
482 _session.add_command(cmd);
483 _session.commit_reversible_command ();
485 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
487 /* Primary-button1 applies change to the mix group.
488 NOTE: Primary-button2 is MIDI learn.
491 set_mix_group_rec_enable (_route, !_route->record_enabled());
495 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
503 RouteUI::rec_enable_release (GdkEventButton* ev)
509 RouteUI::build_sends_menu ()
511 using namespace Menu_Helpers;
513 sends_menu = new Menu;
514 sends_menu->set_name ("ArdourContextMenu");
515 MenuList& items = sends_menu->items();
517 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
518 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
519 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
523 RouteUI::set_sends_gain_from_track ()
528 RouteUI::set_sends_gain_to_zero ()
533 RouteUI::set_sends_gain_to_unity ()
538 RouteUI::show_sends_press(GdkEventButton* ev)
540 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
544 if (!ignore_toggle && !is_track() && show_sends_button) {
546 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
548 // do nothing on midi bind event
551 } else if (Keyboard::is_context_menu_event (ev)) {
553 if (sends_menu == 0) {
557 sends_menu->popup (0, ev->time);
561 /* change button state */
563 show_sends_button->set_active (!show_sends_button->get_active());
567 if (show_sends_button->get_active()) {
568 /* show sends to this bus */
569 MixerStrip::SwitchIO (_route);
570 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
572 /* everybody back to normal */
573 send_blink_connection.disconnect ();
574 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
584 RouteUI::show_sends_release (GdkEventButton* ev)
590 RouteUI::send_blink (bool onoff)
592 if (!show_sends_button) {
597 show_sends_button->set_state (STATE_ACTIVE);
599 show_sends_button->set_state (STATE_NORMAL);
604 RouteUI::solo_changed(void* src)
607 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
611 RouteUI::update_solo_display ()
614 vector<Gdk::Color> fg_colors;
617 if (solo_button->get_active() != (x = _route->soloed())){
618 ignore_toggle = true;
619 solo_button->set_active(x);
620 ignore_toggle = false;
623 if (_route->solo_isolated()) {
624 solo_button->set_visual_state (2);
625 } else if (_route->soloed()) {
626 solo_button->set_visual_state (1);
628 solo_button->set_visual_state (0);
633 RouteUI::solo_changed_so_update_mute ()
635 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
639 RouteUI::mute_changed(void* src)
641 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
645 RouteUI::update_mute_display ()
647 bool model = _route->muted();
648 bool view = mute_button->get_active();
650 /* first make sure the button's "depressed" visual
655 ignore_toggle = true;
656 mute_button->set_active (model);
657 ignore_toggle = false;
660 /* now attend to visual state */
662 if (Config->get_show_solo_mutes()) {
663 if (_route->muted()) {
664 mute_button->set_visual_state (2);
665 } else if (!_route->soloed() && _session.soloing()) {
666 mute_button->set_visual_state (1);
668 mute_button->set_visual_state (0);
671 if (_route->muted()) {
672 mute_button->set_visual_state (2);
674 mute_button->set_visual_state (0);
681 RouteUI::route_rec_enable_changed ()
683 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
687 RouteUI::session_rec_enable_changed ()
689 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
693 RouteUI::update_rec_display ()
695 bool model = _route->record_enabled();
696 bool view = rec_enable_button->get_active();
698 /* first make sure the button's "depressed" visual
703 ignore_toggle = true;
704 rec_enable_button->set_active (model);
705 ignore_toggle = false;
708 /* now make sure its color state is correct */
712 switch (_session.record_status ()) {
713 case Session::Recording:
714 rec_enable_button->set_visual_state (1);
717 case Session::Disabled:
718 case Session::Enabled:
719 rec_enable_button->set_visual_state (2);
725 rec_enable_button->set_visual_state (0);
730 RouteUI::build_remote_control_menu ()
732 remote_control_menu = new Menu;
733 refresh_remote_control_menu ();
737 RouteUI::refresh_remote_control_menu ()
739 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
741 // only refresh the menu if it has been instantiated
743 if (remote_control_menu == 0) {
747 using namespace Menu_Helpers;
749 RadioMenuItem::Group rc_group;
750 CheckMenuItem* rc_active;
751 uint32_t limit = _session.ntracks() + _session.nbusses();
754 MenuList& rc_items = remote_control_menu->items();
757 /* note that this menu list starts at zero, not 1, because zero
758 is a valid, if useless, ID.
761 limit += 4; /* leave some breathing room */
763 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
764 if (_route->remote_control_id() == 0) {
765 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
766 rc_active->set_active ();
769 for (uint32_t i = 1; i < limit; ++i) {
770 snprintf (buf, sizeof (buf), "%u", i);
771 rc_items.push_back (RadioMenuElem (rc_group, buf));
772 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
773 if (_route->remote_control_id() == i) {
774 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
775 rc_active->set_active ();
777 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
782 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
784 /* this is called when the radio menu item is toggled, and so
785 is actually invoked twice per menu selection. we only
786 care about the invocation for the item that was being
790 if (item->get_active()) {
791 _route->set_remote_control_id (id);
796 RouteUI::build_solo_menu (void)
798 using namespace Menu_Helpers;
800 solo_menu = new Menu;
801 solo_menu->set_name ("ArdourContextMenu");
802 MenuList& items = solo_menu->items();
803 CheckMenuItem* check;
805 check = new CheckMenuItem(_("Solo Isolate"));
806 check->set_active (_route->solo_isolated());
807 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
808 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
809 items.push_back (CheckMenuElem(*check));
812 //items.push_back (SeparatorElem());
813 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
818 RouteUI::build_mute_menu(void)
820 using namespace Menu_Helpers;
822 mute_menu = new Menu;
823 mute_menu->set_name ("ArdourContextMenu");
826 MenuList& items = mute_menu->items();
827 CheckMenuItem* check;
829 check = new CheckMenuItem(_("Pre Fader"));
830 init_mute_menu(PRE_FADER, check);
831 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
832 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
833 items.push_back (CheckMenuElem(*check));
836 check = new CheckMenuItem(_("Post Fader"));
837 init_mute_menu(POST_FADER, check);
838 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
839 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
840 items.push_back (CheckMenuElem(*check));
843 check = new CheckMenuItem(_("Control Outs"));
844 init_mute_menu(CONTROL_OUTS, check);
845 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
846 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
847 items.push_back (CheckMenuElem(*check));
850 check = new CheckMenuItem(_("Main Outs"));
851 init_mute_menu(MAIN_OUTS, check);
852 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
853 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
854 items.push_back (CheckMenuElem(*check));
857 //items.push_back (SeparatorElem());
858 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
862 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
864 check->set_active (_route->mute_master()->muted_at (mp));
868 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
870 // _route->set_mute_config(type, check->get_active(), this);
874 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
876 _route->set_solo_isolated (check->get_active(), this);
880 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
882 RouteGroup* mix_group;
884 if((mix_group = route->mix_group()) != 0){
885 _session.begin_reversible_command (_("mix group solo change"));
886 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
887 mix_group->apply(&Route::set_solo, yn, this);
889 _session.add_command (cmd);
890 _session.commit_reversible_command ();
892 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
897 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
899 _session.begin_reversible_command (name);
900 XMLNode &before = _route->get_state();
901 bind(mem_fun(*_route, func), yn, arg)();
902 XMLNode &after = _route->get_state();
903 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
904 _session.commit_reversible_command ();
908 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
910 _session.begin_reversible_command (name);
911 XMLNode &before = track()->get_state();
912 bind (mem_fun (*track(), func), yn, arg)();
913 XMLNode &after = track()->get_state();
914 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
915 _session.commit_reversible_command ();
919 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
921 RouteGroup* mix_group;
923 if((mix_group = route->mix_group()) != 0){
924 _session.begin_reversible_command (_("mix group mute change"));
925 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
926 mix_group->apply(&Route::set_mute, yn, this);
928 _session.add_command(cmd);
929 _session.commit_reversible_command ();
931 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
936 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
938 RouteGroup* mix_group;
940 if((mix_group = route->mix_group()) != 0){
941 _session.begin_reversible_command (_("mix group rec-enable change"));
942 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
943 mix_group->apply (&Route::set_record_enable, yn, this);
945 _session.add_command(cmd);
946 _session.commit_reversible_command ();
948 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
954 RouteUI::choose_color()
959 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
969 RouteUI::set_color (const Gdk::Color & c)
976 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
977 xml_node->add_property ("color", buf);
979 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
984 RouteUI::ensure_xml_node ()
987 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
988 xml_node = new XMLNode ("GUI");
989 _route->add_extra_xml (*xml_node);
995 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
999 XMLNodeList kids = xml_node->children();
1000 XMLNodeConstIterator iter;
1002 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1004 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1005 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1006 XMLProperty* type = (*iter)->property("automation-id");
1007 if (type && type->value() == sym)
1012 // Didn't find it, make a new one
1013 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1014 child->add_property("automation-id", sym);
1015 xml_node->add_child_nocopy (*child);
1021 RouteUI::set_color_from_route ()
1025 RouteUI::ensure_xml_node ();
1027 if ((prop = xml_node->property ("color")) != 0) {
1029 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1031 _color.set_green(g);
1039 RouteUI::remove_this_route ()
1041 vector<string> choices;
1045 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());
1047 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1050 choices.push_back (_("No, do nothing."));
1051 choices.push_back (_("Yes, remove it."));
1053 Choice prompter (prompt, choices);
1055 if (prompter.run () == 1) {
1056 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1061 RouteUI::idle_remove_this_route (RouteUI *rui)
1063 rui->_session.remove_route (rui->_route);
1068 RouteUI::route_rename ()
1070 ArdourPrompter name_prompter (true);
1072 name_prompter.set_prompt (_("New Name: "));
1073 name_prompter.set_initial_text (_route->name());
1074 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1075 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1076 name_prompter.show_all ();
1078 switch (name_prompter.run ()) {
1080 case Gtk::RESPONSE_ACCEPT:
1081 name_prompter.get_result (result);
1082 if (result.length()) {
1083 _route->set_name (result);
1093 RouteUI::name_changed ()
1095 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1097 name_label.set_text (_route->name());
1101 RouteUI::toggle_route_active ()
1105 if (route_active_menu_item) {
1106 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1107 _route->set_active (!yn);
1113 RouteUI::route_active_changed ()
1115 if (route_active_menu_item) {
1116 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1121 RouteUI::toggle_polarity ()
1123 if (polarity_menu_item) {
1127 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1129 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1130 _route->set_phase_invert (x, this);
1132 name_label.set_text (X_("Ø ") + name_label.get_text());
1134 name_label.set_text (_route->name());
1141 RouteUI::polarity_changed ()
1143 /* no signal for this yet */
1147 RouteUI::toggle_denormal_protection ()
1149 if (denormal_menu_item) {
1153 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1155 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1156 _route->set_denormal_protection (x, this);
1162 RouteUI::denormal_protection_changed ()
1164 /* no signal for this yet */
1168 RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
1170 bool yn = _route->solo_isolated ();
1172 if (check->get_active() != yn) {
1173 check->set_active (yn);
1177 #ifdef FIX_THIS_FOR_3_0
1179 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1181 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1183 bool yn = _route->get_mute_config(PRE_FADER);
1184 if (check->get_active() != yn) {
1185 check->set_active (yn);
1190 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1192 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1194 bool yn = _route->get_mute_config(POST_FADER);
1195 if (check->get_active() != yn) {
1196 check->set_active (yn);
1201 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1203 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1205 bool yn = _route->get_mute_config(CONTROL_OUTS);
1206 if (check->get_active() != yn) {
1207 check->set_active (yn);
1212 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1214 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1216 bool yn = _route->get_mute_config(MAIN_OUTS);
1217 if (check->get_active() != yn) {
1218 check->set_active (yn);
1224 RouteUI::disconnect_input ()
1226 _route->input()->disconnect (this);
1230 RouteUI::disconnect_output ()
1232 _route->output()->disconnect (this);
1236 RouteUI::is_track () const
1238 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1241 boost::shared_ptr<Track>
1242 RouteUI::track() const
1244 return boost::dynamic_pointer_cast<Track>(_route);
1248 RouteUI::is_audio_track () const
1250 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1253 boost::shared_ptr<AudioTrack>
1254 RouteUI::audio_track() const
1256 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1260 RouteUI::is_midi_track () const
1262 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1265 boost::shared_ptr<MidiTrack>
1266 RouteUI::midi_track() const
1268 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1271 boost::shared_ptr<Diskstream>
1272 RouteUI::get_diskstream () const
1274 boost::shared_ptr<Track> t;
1276 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1277 return t->diskstream();
1279 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1284 RouteUI::name() const
1286 return _route->name();
1290 RouteUI::map_frozen ()
1292 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1294 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1297 switch (at->freeze_state()) {
1298 case AudioTrack::Frozen:
1299 rec_enable_button->set_sensitive (false);
1302 rec_enable_button->set_sensitive (true);
1309 RouteUI::adjust_latency ()
1311 LatencyDialog dialog (_route->name() + _("latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1315 RouteUI::save_as_template ()
1318 Glib::ustring safe_name;
1321 path = ARDOUR::user_route_template_directory ();
1323 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1324 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1328 Prompter p (true); // modal
1330 p.set_prompt (_("Template name:"));
1332 case RESPONSE_ACCEPT:
1339 p.get_result (name, true);
1341 safe_name = legalize_for_path (name);
1342 safe_name += template_suffix;
1346 _route->save_as_template (path.to_string(), name);