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"
38 #include "gui_thread.h"
39 #include "ardour_dialog.h"
40 #include "latency_gui.h"
41 #include "mixer_strip.h"
42 #include "automation_time_axis.h"
44 #include "ardour/route.h"
45 #include "ardour/session.h"
46 #include "ardour/audioengine.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/audio_diskstream.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/midi_diskstream.h"
51 #include "ardour/template_utils.h"
52 #include "ardour/filename_extensions.h"
53 #include "ardour/directory_names.h"
54 #include "ardour/profile.h"
59 using namespace Gtkmm2ext;
60 using namespace ARDOUR;
63 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
67 set_button_names (mute_name, solo_name, rec_name);
70 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
71 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
75 set_button_names (mute_name, solo_name, rec_name);
81 /* derived classes should emit GoingAway so that they receive the signal
82 when the object is still a legal derived instance.
87 delete remote_control_menu;
98 remote_control_menu = 0;
100 ignore_toggle = false;
101 wait_for_release = false;
102 route_active_menu_item = 0;
103 was_solo_safe = false;
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 ("ShowSendsButton");
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_safe_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_safe (!_route->solo_safe(), 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());
565 if (show_sends_button->get_active()) {
566 /* show sends to this bus */
567 MixerStrip::SwitchIO (_route);
569 /* everybody back to normal */
570 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
580 RouteUI::show_sends_release (GdkEventButton* ev)
586 RouteUI::solo_changed(void* src)
589 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
593 RouteUI::update_solo_display ()
596 vector<Gdk::Color> fg_colors;
599 if (solo_button->get_active() != (x = _route->soloed())){
600 ignore_toggle = true;
601 solo_button->set_active(x);
602 ignore_toggle = false;
605 if (_route->solo_safe()) {
606 solo_button->set_visual_state (2);
607 } else if (_route->soloed()) {
608 solo_button->set_visual_state (1);
610 solo_button->set_visual_state (0);
615 RouteUI::solo_changed_so_update_mute ()
617 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
621 RouteUI::mute_changed(void* src)
623 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
627 RouteUI::update_mute_display ()
629 bool model = _route->muted();
630 bool view = mute_button->get_active();
632 /* first make sure the button's "depressed" visual
637 ignore_toggle = true;
638 mute_button->set_active (model);
639 ignore_toggle = false;
642 /* now attend to visual state */
644 if (Config->get_show_solo_mutes()) {
645 if (_route->muted()) {
646 mute_button->set_visual_state (2);
647 } else if (!_route->soloed() && _route->solo_muted()) {
649 mute_button->set_visual_state (1);
651 mute_button->set_visual_state (0);
654 if (_route->muted()) {
655 mute_button->set_visual_state (2);
657 mute_button->set_visual_state (0);
664 RouteUI::route_rec_enable_changed ()
666 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
670 RouteUI::session_rec_enable_changed ()
672 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
676 RouteUI::update_rec_display ()
678 bool model = _route->record_enabled();
679 bool view = rec_enable_button->get_active();
681 /* first make sure the button's "depressed" visual
686 ignore_toggle = true;
687 rec_enable_button->set_active (model);
688 ignore_toggle = false;
691 /* now make sure its color state is correct */
695 switch (_session.record_status ()) {
696 case Session::Recording:
697 rec_enable_button->set_visual_state (1);
700 case Session::Disabled:
701 case Session::Enabled:
702 rec_enable_button->set_visual_state (2);
708 rec_enable_button->set_visual_state (0);
713 RouteUI::build_remote_control_menu ()
715 remote_control_menu = new Menu;
716 refresh_remote_control_menu ();
720 RouteUI::refresh_remote_control_menu ()
722 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
724 // only refresh the menu if it has been instantiated
726 if (remote_control_menu == 0) {
730 using namespace Menu_Helpers;
732 RadioMenuItem::Group rc_group;
733 CheckMenuItem* rc_active;
734 uint32_t limit = _session.ntracks() + _session.nbusses();
737 MenuList& rc_items = remote_control_menu->items();
740 /* note that this menu list starts at zero, not 1, because zero
741 is a valid, if useless, ID.
744 limit += 4; /* leave some breathing room */
746 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
747 if (_route->remote_control_id() == 0) {
748 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
749 rc_active->set_active ();
752 for (uint32_t i = 1; i < limit; ++i) {
753 snprintf (buf, sizeof (buf), "%u", i);
754 rc_items.push_back (RadioMenuElem (rc_group, buf));
755 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
756 if (_route->remote_control_id() == i) {
757 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
758 rc_active->set_active ();
760 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
765 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
767 /* this is called when the radio menu item is toggled, and so
768 is actually invoked twice per menu selection. we only
769 care about the invocation for the item that was being
773 if (item->get_active()) {
774 _route->set_remote_control_id (id);
779 RouteUI::build_solo_menu (void)
781 using namespace Menu_Helpers;
783 solo_menu = new Menu;
784 solo_menu->set_name ("ArdourContextMenu");
785 MenuList& items = solo_menu->items();
786 CheckMenuItem* check;
788 check = new CheckMenuItem(_("Solo-safe"));
789 check->set_active (_route->solo_safe());
790 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
791 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
792 items.push_back (CheckMenuElem(*check));
795 //items.push_back (SeparatorElem());
796 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
801 RouteUI::build_mute_menu(void)
803 using namespace Menu_Helpers;
805 mute_menu = new Menu;
806 mute_menu->set_name ("ArdourContextMenu");
807 MenuList& items = mute_menu->items();
808 CheckMenuItem* check;
810 check = new CheckMenuItem(_("Pre Fader"));
811 init_mute_menu(PRE_FADER, check);
812 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
813 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
814 items.push_back (CheckMenuElem(*check));
817 check = new CheckMenuItem(_("Post Fader"));
818 init_mute_menu(POST_FADER, check);
819 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
820 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
821 items.push_back (CheckMenuElem(*check));
824 check = new CheckMenuItem(_("Control Outs"));
825 init_mute_menu(CONTROL_OUTS, check);
826 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
827 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
828 items.push_back (CheckMenuElem(*check));
831 check = new CheckMenuItem(_("Main Outs"));
832 init_mute_menu(MAIN_OUTS, check);
833 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
834 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
835 items.push_back (CheckMenuElem(*check));
838 //items.push_back (SeparatorElem());
839 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
843 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
845 if (_route->get_mute_config (type)) {
846 check->set_active (true);
851 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
853 _route->set_mute_config(type, check->get_active(), this);
857 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
859 _route->set_solo_safe (check->get_active(), this);
863 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
865 RouteGroup* mix_group;
867 if((mix_group = route->mix_group()) != 0){
868 _session.begin_reversible_command (_("mix group solo change"));
869 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
870 mix_group->apply(&Route::set_solo, yn, this);
872 _session.add_command (cmd);
873 _session.commit_reversible_command ();
875 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
880 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
882 _session.begin_reversible_command (name);
883 XMLNode &before = _route->get_state();
884 bind(mem_fun(*_route, func), yn, arg)();
885 XMLNode &after = _route->get_state();
886 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
887 _session.commit_reversible_command ();
891 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
893 _session.begin_reversible_command (name);
894 XMLNode &before = track()->get_state();
895 bind (mem_fun (*track(), func), yn, arg)();
896 XMLNode &after = track()->get_state();
897 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
898 _session.commit_reversible_command ();
902 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
904 RouteGroup* mix_group;
906 if((mix_group = route->mix_group()) != 0){
907 _session.begin_reversible_command (_("mix group mute change"));
908 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
909 mix_group->apply(&Route::set_mute, yn, this);
911 _session.add_command(cmd);
912 _session.commit_reversible_command ();
914 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
919 RouteUI::set_mix_group_rec_enable(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 rec-enable change"));
925 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
926 mix_group->apply (&Route::set_record_enable, yn, this);
928 _session.add_command(cmd);
929 _session.commit_reversible_command ();
931 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
937 RouteUI::choose_color()
942 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
952 RouteUI::set_color (const Gdk::Color & c)
959 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
960 xml_node->add_property ("color", buf);
962 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
967 RouteUI::ensure_xml_node ()
970 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
971 xml_node = new XMLNode ("GUI");
972 _route->add_extra_xml (*xml_node);
978 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
982 XMLNodeList kids = xml_node->children();
983 XMLNodeConstIterator iter;
985 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
987 for (iter = kids.begin(); iter != kids.end(); ++iter) {
988 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
989 XMLProperty* type = (*iter)->property("automation-id");
990 if (type && type->value() == sym)
995 // Didn't find it, make a new one
996 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
997 child->add_property("automation-id", sym);
998 xml_node->add_child_nocopy (*child);
1004 RouteUI::set_color_from_route ()
1008 RouteUI::ensure_xml_node ();
1010 if ((prop = xml_node->property ("color")) != 0) {
1012 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1014 _color.set_green(g);
1022 RouteUI::remove_this_route ()
1024 vector<string> choices;
1028 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());
1030 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1033 choices.push_back (_("No, do nothing."));
1034 choices.push_back (_("Yes, remove it."));
1036 Choice prompter (prompt, choices);
1038 if (prompter.run () == 1) {
1039 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1044 RouteUI::idle_remove_this_route (RouteUI *rui)
1046 rui->_session.remove_route (rui->_route);
1051 RouteUI::route_rename ()
1053 ArdourPrompter name_prompter (true);
1055 name_prompter.set_prompt (_("New Name: "));
1056 name_prompter.set_initial_text (_route->name());
1057 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1058 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1059 name_prompter.show_all ();
1061 switch (name_prompter.run ()) {
1063 case Gtk::RESPONSE_ACCEPT:
1064 name_prompter.get_result (result);
1065 if (result.length()) {
1066 _route->set_name (result);
1076 RouteUI::name_changed ()
1078 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1080 name_label.set_text (_route->name());
1084 RouteUI::toggle_route_active ()
1088 if (route_active_menu_item) {
1089 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1090 _route->set_active (!yn);
1096 RouteUI::route_active_changed ()
1098 if (route_active_menu_item) {
1099 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1104 RouteUI::toggle_polarity ()
1106 if (polarity_menu_item) {
1110 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1112 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1113 _route->set_phase_invert (x, this);
1115 name_label.set_text (X_("Ø ") + name_label.get_text());
1117 name_label.set_text (_route->name());
1124 RouteUI::polarity_changed ()
1126 /* no signal for this yet */
1130 RouteUI::toggle_denormal_protection ()
1132 if (denormal_menu_item) {
1136 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1138 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1139 _route->set_denormal_protection (x, this);
1145 RouteUI::denormal_protection_changed ()
1147 /* no signal for this yet */
1152 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1154 bool yn = _route->solo_safe ();
1156 if (check->get_active() != yn) {
1157 check->set_active (yn);
1161 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1163 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1165 bool yn = _route->get_mute_config(PRE_FADER);
1166 if (check->get_active() != yn) {
1167 check->set_active (yn);
1172 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1174 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1176 bool yn = _route->get_mute_config(POST_FADER);
1177 if (check->get_active() != yn) {
1178 check->set_active (yn);
1183 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1185 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1187 bool yn = _route->get_mute_config(CONTROL_OUTS);
1188 if (check->get_active() != yn) {
1189 check->set_active (yn);
1194 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1196 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1198 bool yn = _route->get_mute_config(MAIN_OUTS);
1199 if (check->get_active() != yn) {
1200 check->set_active (yn);
1205 RouteUI::disconnect_input ()
1207 _route->disconnect_inputs (this);
1211 RouteUI::disconnect_output ()
1213 _route->disconnect_outputs (this);
1217 RouteUI::is_track () const
1219 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1222 boost::shared_ptr<Track>
1223 RouteUI::track() const
1225 return boost::dynamic_pointer_cast<Track>(_route);
1229 RouteUI::is_audio_track () const
1231 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1234 boost::shared_ptr<AudioTrack>
1235 RouteUI::audio_track() const
1237 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1241 RouteUI::is_midi_track () const
1243 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1246 boost::shared_ptr<MidiTrack>
1247 RouteUI::midi_track() const
1249 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1252 boost::shared_ptr<Diskstream>
1253 RouteUI::get_diskstream () const
1255 boost::shared_ptr<Track> t;
1257 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1258 return t->diskstream();
1260 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1265 RouteUI::name() const
1267 return _route->name();
1271 RouteUI::map_frozen ()
1273 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1275 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1278 switch (at->freeze_state()) {
1279 case AudioTrack::Frozen:
1280 rec_enable_button->set_sensitive (false);
1283 rec_enable_button->set_sensitive (true);
1290 RouteUI::adjust_latency ()
1292 LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());
1296 RouteUI::save_as_template ()
1299 Glib::ustring safe_name;
1302 path = ARDOUR::user_route_template_directory ();
1304 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1305 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1309 Prompter p (true); // modal
1311 p.set_prompt (_("Template name:"));
1313 case RESPONSE_ACCEPT:
1320 p.get_result (name, true);
1322 safe_name = legalize_for_path (name);
1323 safe_name += template_suffix;
1327 _route->save_as_template (path.to_string(), name);