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>
26 #include <ardour/route_group.h>
27 #include <pbd/memento_command.h>
28 #include <pbd/stacktrace.h>
29 #include <pbd/shiva.h>
35 #include "gui_thread.h"
37 #include <ardour/route.h>
38 #include <ardour/session.h>
39 #include <ardour/audioengine.h>
40 #include <ardour/audio_track.h>
41 #include <ardour/audio_diskstream.h>
46 using namespace Gtkmm2ext;
47 using namespace ARDOUR;
50 RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
54 set_button_names (mute_name, solo_name, rec_name);
57 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
58 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
62 set_button_names (mute_name, solo_name, rec_name);
72 remote_control_menu = 0;
73 ignore_toggle = false;
74 wait_for_release = false;
75 route_active_menu_item = 0;
76 was_solo_safe = false;
77 polarity_menu_item = 0;
78 denormal_menu_item = 0;
80 mute_button = manage (new BindableToggleButton (0, ""));
81 mute_button->set_self_managed (true);
82 mute_button->set_name ("MuteButton");
84 solo_button = manage (new BindableToggleButton (0, ""));
85 solo_button->set_self_managed (true);
86 solo_button->set_name ("SoloButton");
88 rec_enable_button = manage (new BindableToggleButton (0, ""));
89 rec_enable_button->set_name ("RecordEnableButton");
90 rec_enable_button->set_self_managed (true);
108 if (remote_control_menu) {
109 delete remote_control_menu;
110 remote_control_menu = 0;
114 /* do not delete the node - its owned by the route */
118 route_active_menu_item = 0;
119 polarity_menu_item = 0;
120 denormal_menu_item = 0;
124 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
132 RouteUI::set_route (boost::shared_ptr<Route> rp)
135 /* first time it is set */
136 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
143 if (set_color_from_route()) {
144 set_color (unique_random_color());
147 /* no, there is no memory leak here. This object cleans itself (and other stuff)
148 up when the route is destroyed.
151 new PairedShiva<Route,RouteUI> (*_route, *this);
153 mute_button->set_controllable (&_route->mute_control());
154 mute_button->set_label (m_name);
156 solo_button->set_controllable (&_route->solo_control());
157 solo_button->set_label (s_name);
159 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
160 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
161 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
162 connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
164 /* when solo changes, update mute state too, in case the user wants us to display it */
166 update_solo_display ();
167 update_mute_display ();
170 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
172 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
174 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
176 rec_enable_button->set_controllable (&t->rec_enable_control());
177 rec_enable_button->set_label (r_name);
179 update_rec_display ();
182 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
184 /* map the current state */
191 GoingAway (); /* EMIT SIGNAL */
200 if (remote_control_menu) {
201 delete remote_control_menu;
206 RouteUI::mute_press(GdkEventButton* ev)
208 if (ev->type == GDK_2BUTTON_PRESS) {
212 if (!ignore_toggle) {
214 if (Keyboard::is_context_menu_event (ev)) {
220 mute_menu->popup(0,ev->time);
224 if (ev->button == 2) {
225 // Primary-button2 click is the midi binding click
226 // button2-click is "momentary"
228 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
229 wait_for_release = true;
235 if (ev->button == 1 || ev->button == 2) {
237 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
239 /* Primary-Tertiary-click applies change to all routes */
241 _session.begin_reversible_command (_("mute change"));
242 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
243 _session.set_all_mute (!_route->muted());
245 _session.add_command(cmd);
246 _session.commit_reversible_command ();
248 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
250 /* Primary-button1 applies change to the mix group.
251 NOTE: Primary-button2 is MIDI learn.
254 if (ev->button == 1) {
255 set_mix_group_mute (_route, !_route->muted());
260 /* plain click applies change to this route */
262 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
273 RouteUI::mute_release(GdkEventButton* ev)
275 if (!ignore_toggle) {
276 if (wait_for_release){
277 wait_for_release = false;
279 // because the press was the last undoable thing we did
287 RouteUI::solo_press(GdkEventButton* ev)
289 /* ignore double clicks */
291 if (ev->type == GDK_2BUTTON_PRESS) {
295 if (!ignore_toggle) {
297 if (Keyboard::is_context_menu_event (ev)) {
299 if (solo_menu == 0) {
303 solo_menu->popup (1, ev->time);
307 if (ev->button == 2) {
309 // Primary-button2 click is the midi binding click
310 // button2-click is "momentary"
312 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
313 wait_for_release = true;
319 if (ev->button == 1 || ev->button == 2) {
321 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
323 /* Primary-Tertiary-click applies change to all routes */
325 _session.begin_reversible_command (_("solo change"));
326 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
327 _session.set_all_solo (!_route->soloed());
329 _session.add_command (cmd);
330 _session.commit_reversible_command ();
332 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
334 // Primary-Secondary-click: exclusively solo this track, not a toggle */
336 _session.begin_reversible_command (_("solo change"));
337 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
338 _session.set_all_solo (false);
339 _route->set_solo (true, this);
341 _session.add_command(cmd);
342 _session.commit_reversible_command ();
344 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
346 // shift-click: set this route to solo safe
348 _route->set_solo_safe (!_route->solo_safe(), this);
349 wait_for_release = false;
351 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
353 /* Primary-button1: solo mix group.
354 NOTE: Primary-button2 is MIDI learn.
357 if (ev->button == 1) {
358 set_mix_group_solo (_route, !_route->soloed());
363 /* click: solo this route */
364 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
374 RouteUI::solo_release(GdkEventButton* ev)
376 if (!ignore_toggle) {
377 if (wait_for_release) {
378 wait_for_release = false;
380 // because the press was the last undoable thing we did
390 RouteUI::rec_enable_press(GdkEventButton* ev)
392 if (ev->type == GDK_2BUTTON_PRESS) {
396 if (!_session.engine().connected()) {
397 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
402 if (!ignore_toggle && is_track() && rec_enable_button) {
404 if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
406 // do nothing on midi bind event
409 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
411 _session.begin_reversible_command (_("rec-enable change"));
412 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
414 if (rec_enable_button->get_active()) {
415 _session.record_disenable_all ();
417 _session.record_enable_all ();
421 _session.add_command(cmd);
422 _session.commit_reversible_command ();
424 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
426 /* Primary-button1 applies change to the mix group.
427 NOTE: Primary-button2 is MIDI learn.
430 set_mix_group_rec_enable (_route, !_route->record_enabled());
434 reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
442 RouteUI::rec_enable_release (GdkEventButton* ev)
448 RouteUI::solo_changed(void* src)
450 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
454 RouteUI::update_solo_display ()
457 vector<Gdk::Color> fg_colors;
460 if (solo_button->get_active() != (x = _route->soloed())){
461 ignore_toggle = true;
462 solo_button->set_active(x);
463 ignore_toggle = false;
466 if (_route->solo_safe()) {
467 solo_button->set_visual_state (2);
468 } else if (_route->soloed()) {
469 solo_button->set_visual_state (1);
471 solo_button->set_visual_state (0);
476 RouteUI::solo_changed_so_update_mute ()
478 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
482 RouteUI::mute_changed(void* src)
484 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
488 RouteUI::update_mute_display ()
490 bool model = _route->muted();
491 bool view = mute_button->get_active();
493 /* first make sure the button's "depressed" visual
498 ignore_toggle = true;
499 mute_button->set_active (model);
500 ignore_toggle = false;
503 /* now attend to visual state */
505 if (Config->get_show_solo_mutes()) {
506 if (_route->muted()) {
507 mute_button->set_visual_state (2);
508 } else if (!_route->soloed() && _route->solo_muted()) {
510 mute_button->set_visual_state (1);
512 mute_button->set_visual_state (0);
515 if (_route->muted()) {
516 mute_button->set_visual_state (2);
518 mute_button->set_visual_state (0);
525 RouteUI::route_rec_enable_changed ()
527 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
531 RouteUI::session_rec_enable_changed ()
533 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
537 RouteUI::update_rec_display ()
539 bool model = _route->record_enabled();
540 bool view = rec_enable_button->get_active();
542 /* first make sure the button's "depressed" visual
547 ignore_toggle = true;
548 rec_enable_button->set_active (model);
549 ignore_toggle = false;
552 /* now make sure its color state is correct */
556 switch (_session.record_status ()) {
557 case Session::Recording:
558 rec_enable_button->set_visual_state (1);
561 case Session::Disabled:
562 case Session::Enabled:
563 rec_enable_button->set_visual_state (2);
569 rec_enable_button->set_visual_state (0);
574 RouteUI::build_remote_control_menu ()
576 remote_control_menu = new Menu;
577 refresh_remote_control_menu ();
581 RouteUI::refresh_remote_control_menu ()
583 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
585 // only refresh the menu if it has been instantiated
587 if (remote_control_menu == 0) {
591 using namespace Menu_Helpers;
593 RadioMenuItem::Group rc_group;
594 CheckMenuItem* rc_active;
595 uint32_t limit = _session.ntracks() + _session.nbusses();
598 MenuList& rc_items = remote_control_menu->items();
601 /* note that this menu list starts at zero, not 1, because zero
602 is a valid, if useless, ID.
605 limit += 4; /* leave some breathing room */
607 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
608 if (_route->remote_control_id() == 0) {
609 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
610 rc_active->set_active ();
613 for (uint32_t i = 1; i < limit; ++i) {
614 snprintf (buf, sizeof (buf), "%u", i);
615 rc_items.push_back (RadioMenuElem (rc_group, buf));
616 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
617 if (_route->remote_control_id() == i) {
618 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
619 rc_active->set_active ();
621 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
626 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
628 /* this is called when the radio menu item is toggled, and so
629 is actually invoked twice per menu selection. we only
630 care about the invocation for the item that was being
634 if (item->get_active()) {
635 _route->set_remote_control_id (id);
640 RouteUI::build_solo_menu (void)
642 using namespace Menu_Helpers;
644 solo_menu = new Menu;
645 solo_menu->set_name ("ArdourContextMenu");
646 MenuList& items = solo_menu->items();
647 CheckMenuItem* check;
649 check = new CheckMenuItem(_("Solo-safe"));
650 check->set_active (_route->solo_safe());
651 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
652 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
653 items.push_back (CheckMenuElem(*check));
656 //items.push_back (SeparatorElem());
657 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
662 RouteUI::build_mute_menu(void)
664 using namespace Menu_Helpers;
666 mute_menu = new Menu;
667 mute_menu->set_name ("ArdourContextMenu");
668 MenuList& items = mute_menu->items();
669 CheckMenuItem* check;
671 check = new CheckMenuItem(_("Pre Fader"));
672 init_mute_menu(PRE_FADER, check);
673 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
674 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
675 items.push_back (CheckMenuElem(*check));
678 check = new CheckMenuItem(_("Post Fader"));
679 init_mute_menu(POST_FADER, check);
680 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
681 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
682 items.push_back (CheckMenuElem(*check));
685 check = new CheckMenuItem(_("Control Outs"));
686 init_mute_menu(CONTROL_OUTS, check);
687 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
688 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
689 items.push_back (CheckMenuElem(*check));
692 check = new CheckMenuItem(_("Main Outs"));
693 init_mute_menu(MAIN_OUTS, check);
694 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
695 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
696 items.push_back (CheckMenuElem(*check));
699 //items.push_back (SeparatorElem());
700 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
704 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
706 if (_route->get_mute_config (type)) {
707 check->set_active (true);
712 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
714 _route->set_mute_config(type, check->get_active(), this);
718 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
720 _route->set_solo_safe (check->get_active(), this);
724 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
726 RouteGroup* mix_group;
728 if((mix_group = route->mix_group()) != 0){
729 _session.begin_reversible_command (_("mix group solo change"));
730 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
731 mix_group->apply(&Route::set_solo, yn, this);
733 _session.add_command (cmd);
734 _session.commit_reversible_command ();
736 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
741 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
743 _session.begin_reversible_command (name);
744 XMLNode &before = _route->get_state();
745 bind(mem_fun(*_route, func), yn, arg)();
746 XMLNode &after = _route->get_state();
747 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
748 _session.commit_reversible_command ();
752 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
754 _session.begin_reversible_command (name);
755 XMLNode &before = audio_track()->get_state();
756 bind (mem_fun (*audio_track(), func), yn, arg)();
757 XMLNode &after = audio_track()->get_state();
758 _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), &before, &after));
759 _session.commit_reversible_command ();
763 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
765 RouteGroup* mix_group;
767 if((mix_group = route->mix_group()) != 0){
768 _session.begin_reversible_command (_("mix group mute change"));
769 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
770 mix_group->apply(&Route::set_mute, yn, this);
772 _session.add_command(cmd);
773 _session.commit_reversible_command ();
775 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
780 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
782 RouteGroup* mix_group;
784 if((mix_group = route->mix_group()) != 0){
785 _session.begin_reversible_command (_("mix group rec-enable change"));
786 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
787 mix_group->apply (&Route::set_record_enable, yn, this);
789 _session.add_command(cmd);
790 _session.commit_reversible_command ();
792 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
798 RouteUI::choose_color()
803 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
813 RouteUI::set_color (const Gdk::Color & c)
820 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
821 xml_node->add_property ("color", buf);
823 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
828 RouteUI::ensure_xml_node ()
831 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
832 xml_node = new XMLNode ("GUI");
833 _route->add_extra_xml (*xml_node);
839 RouteUI::get_child_xml_node (const string & childname)
846 if ((child = find_named_node (*xml_node, childname)) == 0) {
847 child = new XMLNode (childname);
848 xml_node->add_child_nocopy (*child);
855 RouteUI::set_color_from_route ()
859 RouteUI::ensure_xml_node ();
861 if ((prop = xml_node->property ("color")) != 0) {
863 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
873 RouteUI::remove_this_route ()
875 vector<string> choices;
879 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());
881 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
884 choices.push_back (_("No, do nothing."));
885 choices.push_back (_("Yes, remove it."));
887 Choice prompter (prompt, choices);
889 if (prompter.run () == 1) {
890 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
895 RouteUI::idle_remove_this_route (RouteUI *rui)
897 rui->_session.remove_route (rui->_route);
902 RouteUI::route_rename ()
904 ArdourPrompter name_prompter (true);
906 name_prompter.set_prompt (_("New Name: "));
907 name_prompter.set_initial_text (_route->name());
908 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
909 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
910 name_prompter.show_all ();
912 switch (name_prompter.run ()) {
914 case Gtk::RESPONSE_ACCEPT:
915 name_prompter.get_result (result);
916 if (result.length()) {
917 _route->set_name (result, this);
927 RouteUI::name_changed (void *src)
929 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
931 name_label.set_text (_route->name());
935 RouteUI::toggle_route_active ()
939 if (route_active_menu_item) {
940 if (route_active_menu_item->get_active() != (yn = _route->active())) {
941 _route->set_active (!yn);
947 RouteUI::route_active_changed ()
949 if (route_active_menu_item) {
950 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
955 RouteUI::toggle_polarity ()
957 if (polarity_menu_item) {
961 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
963 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
964 _route->set_phase_invert (x, this);
966 name_label.set_text (X_("Ø ") + name_label.get_text());
968 name_label.set_text (_route->name());
975 RouteUI::polarity_changed ()
977 /* no signal for this yet */
981 RouteUI::toggle_denormal_protection ()
983 if (denormal_menu_item) {
987 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
989 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
990 _route->set_denormal_protection (x, this);
996 RouteUI::denormal_protection_changed ()
998 /* no signal for this yet */
1003 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1005 bool yn = _route->solo_safe ();
1007 if (check->get_active() != yn) {
1008 check->set_active (yn);
1012 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1014 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1016 bool yn = _route->get_mute_config(PRE_FADER);
1017 if (check->get_active() != yn) {
1018 check->set_active (yn);
1023 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1025 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1027 bool yn = _route->get_mute_config(POST_FADER);
1028 if (check->get_active() != yn) {
1029 check->set_active (yn);
1034 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1036 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1038 bool yn = _route->get_mute_config(CONTROL_OUTS);
1039 if (check->get_active() != yn) {
1040 check->set_active (yn);
1045 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1047 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1049 bool yn = _route->get_mute_config(MAIN_OUTS);
1050 if (check->get_active() != yn) {
1051 check->set_active (yn);
1056 RouteUI::disconnect_input ()
1058 _route->disconnect_inputs (this);
1062 RouteUI::disconnect_output ()
1064 _route->disconnect_outputs (this);
1068 RouteUI::is_track () const
1070 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1073 boost::shared_ptr<Track>
1074 RouteUI::track() const
1076 return boost::dynamic_pointer_cast<Track>(_route);
1080 RouteUI::is_audio_track () const
1082 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1085 boost::shared_ptr<AudioTrack>
1086 RouteUI::audio_track() const
1088 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1091 boost::shared_ptr<Diskstream>
1092 RouteUI::get_diskstream () const
1094 boost::shared_ptr<Track> t;
1096 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1097 return t->diskstream();
1099 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1104 RouteUI::name() const
1106 return _route->name();
1110 RouteUI::map_frozen ()
1112 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1114 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1117 switch (at->freeze_state()) {
1118 case AudioTrack::Frozen:
1119 rec_enable_button->set_sensitive (false);
1122 rec_enable_button->set_sensitive (true);