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);
92 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
110 if (remote_control_menu) {
111 delete remote_control_menu;
112 remote_control_menu = 0;
116 /* do not delete the node - its owned by the route */
120 route_active_menu_item = 0;
121 polarity_menu_item = 0;
122 denormal_menu_item = 0;
126 RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
134 RouteUI::set_route (boost::shared_ptr<Route> rp)
140 if (set_color_from_route()) {
141 set_color (unique_random_color());
144 /* no, there is no memory leak here. This object cleans itself (and other stuff)
145 up when the route is destroyed.
148 new PairedShiva<Route,RouteUI> (*_route, *this);
150 mute_button->set_controllable (&_route->mute_control());
151 mute_button->set_label (m_name);
153 solo_button->set_controllable (&_route->solo_control());
154 solo_button->set_label (s_name);
156 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
157 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
158 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
159 connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
161 /* when solo changes, update mute state too, in case the user wants us to display it */
163 update_solo_display ();
164 update_mute_display ();
167 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
169 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
171 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
173 rec_enable_button->set_controllable (&t->rec_enable_control());
174 rec_enable_button->set_label (r_name);
176 update_rec_display ();
179 connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
181 /* map the current state */
188 GoingAway (); /* EMIT SIGNAL */
197 if (remote_control_menu) {
198 delete remote_control_menu;
203 RouteUI::mute_press(GdkEventButton* ev)
205 if (ev->type == GDK_2BUTTON_PRESS) {
209 if (!ignore_toggle) {
211 if (Keyboard::is_context_menu_event (ev)) {
217 mute_menu->popup(0,ev->time);
221 if (ev->button == 2) {
222 // Primary-button2 click is the midi binding click
223 // button2-click is "momentary"
225 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
226 wait_for_release = true;
232 if (ev->button == 1 || ev->button == 2) {
234 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
236 /* Primary-Tertiary-click applies change to all routes */
238 _session.begin_reversible_command (_("mute change"));
239 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
240 _session.set_all_mute (!_route->muted());
242 _session.add_command(cmd);
243 _session.commit_reversible_command ();
245 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
247 /* Primary-button1 applies change to the mix group.
248 NOTE: Primary-button2 is MIDI learn.
251 if (ev->button == 1) {
252 set_mix_group_mute (_route, !_route->muted());
257 /* plain click applies change to this route */
259 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
270 RouteUI::mute_release(GdkEventButton* ev)
272 if (!ignore_toggle) {
273 if (wait_for_release){
274 wait_for_release = false;
276 // because the press was the last undoable thing we did
284 RouteUI::solo_press(GdkEventButton* ev)
286 /* ignore double clicks */
288 if (ev->type == GDK_2BUTTON_PRESS) {
292 if (!ignore_toggle) {
294 if (Keyboard::is_context_menu_event (ev)) {
296 if (solo_menu == 0) {
300 solo_menu->popup (1, ev->time);
304 if (ev->button == 2) {
306 // Primary-button2 click is the midi binding click
307 // button2-click is "momentary"
309 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
310 wait_for_release = true;
316 if (ev->button == 1 || ev->button == 2) {
318 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
320 /* Primary-Tertiary-click applies change to all routes */
322 _session.begin_reversible_command (_("solo change"));
323 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
324 _session.set_all_solo (!_route->soloed());
326 _session.add_command (cmd);
327 _session.commit_reversible_command ();
329 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
331 // Primary-Secondary-click: exclusively solo this track, not a toggle */
333 _session.begin_reversible_command (_("solo change"));
334 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
335 _session.set_all_solo (false);
336 _route->set_solo (true, this);
338 _session.add_command(cmd);
339 _session.commit_reversible_command ();
341 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
343 // shift-click: set this route to solo safe
345 _route->set_solo_safe (!_route->solo_safe(), this);
346 wait_for_release = false;
348 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
350 /* Primary-button1: solo mix group.
351 NOTE: Primary-button2 is MIDI learn.
354 if (ev->button == 1) {
355 set_mix_group_solo (_route, !_route->soloed());
360 /* click: solo this route */
361 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
371 RouteUI::solo_release(GdkEventButton* ev)
373 if (!ignore_toggle) {
374 if (wait_for_release) {
375 wait_for_release = false;
377 // because the press was the last undoable thing we did
387 RouteUI::rec_enable_press(GdkEventButton* ev)
389 if (ev->type == GDK_2BUTTON_PRESS) {
393 if (!_session.engine().connected()) {
394 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
399 if (!ignore_toggle && is_track() && rec_enable_button) {
401 if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
403 // do nothing on midi bind event
406 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
408 _session.begin_reversible_command (_("rec-enable change"));
409 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
411 if (rec_enable_button->get_active()) {
412 _session.record_disenable_all ();
414 _session.record_enable_all ();
418 _session.add_command(cmd);
419 _session.commit_reversible_command ();
421 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
423 /* Primary-button1 applies change to the mix group.
424 NOTE: Primary-button2 is MIDI learn.
427 set_mix_group_rec_enable (_route, !_route->record_enabled());
431 reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable, !audio_track()->record_enabled(), this);
439 RouteUI::rec_enable_release (GdkEventButton* ev)
445 RouteUI::solo_changed(void* src)
447 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
451 RouteUI::update_solo_display ()
454 vector<Gdk::Color> fg_colors;
457 if (solo_button->get_active() != (x = _route->soloed())){
458 ignore_toggle = true;
459 solo_button->set_active(x);
460 ignore_toggle = false;
463 if (_route->solo_safe()) {
464 solo_button->set_visual_state (2);
465 } else if (_route->soloed()) {
466 solo_button->set_visual_state (1);
468 solo_button->set_visual_state (0);
473 RouteUI::solo_changed_so_update_mute ()
475 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
479 RouteUI::mute_changed(void* src)
481 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
485 RouteUI::update_mute_display ()
487 bool model = _route->muted();
488 bool view = mute_button->get_active();
490 /* first make sure the button's "depressed" visual
495 ignore_toggle = true;
496 mute_button->set_active (model);
497 ignore_toggle = false;
500 /* now attend to visual state */
502 if (Config->get_show_solo_mutes()) {
503 if (_route->muted()) {
504 mute_button->set_visual_state (2);
505 } else if (!_route->soloed() && _route->solo_muted()) {
507 mute_button->set_visual_state (1);
509 mute_button->set_visual_state (0);
512 if (_route->muted()) {
513 mute_button->set_visual_state (2);
515 mute_button->set_visual_state (0);
522 RouteUI::route_rec_enable_changed ()
524 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
528 RouteUI::session_rec_enable_changed ()
530 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
534 RouteUI::update_rec_display ()
536 bool model = _route->record_enabled();
537 bool view = rec_enable_button->get_active();
539 /* first make sure the button's "depressed" visual
544 ignore_toggle = true;
545 rec_enable_button->set_active (model);
546 ignore_toggle = false;
549 /* now make sure its color state is correct */
553 switch (_session.record_status ()) {
554 case Session::Recording:
555 rec_enable_button->set_visual_state (1);
558 case Session::Disabled:
559 case Session::Enabled:
560 rec_enable_button->set_visual_state (2);
566 rec_enable_button->set_visual_state (0);
571 RouteUI::build_remote_control_menu ()
573 remote_control_menu = manage (new Menu);
574 refresh_remote_control_menu ();
578 RouteUI::refresh_remote_control_menu ()
580 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
582 // only refresh the menu if it has been instantiated
584 if (remote_control_menu == 0) {
588 using namespace Menu_Helpers;
590 RadioMenuItem::Group rc_group;
591 CheckMenuItem* rc_active;
592 uint32_t limit = _session.ntracks() + _session.nbusses();
595 MenuList& rc_items = remote_control_menu->items();
598 /* note that this menu list starts at zero, not 1, because zero
599 is a valid, if useless, ID.
602 limit += 4; /* leave some breathing room */
604 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
605 if (_route->remote_control_id() == 0) {
606 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
607 rc_active->set_active ();
610 for (uint32_t i = 1; i < limit; ++i) {
611 snprintf (buf, sizeof (buf), "%u", i);
612 rc_items.push_back (RadioMenuElem (rc_group, buf));
613 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
614 if (_route->remote_control_id() == i) {
615 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
616 rc_active->set_active ();
618 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
623 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
625 /* this is called when the radio menu item is toggled, and so
626 is actually invoked twice per menu selection. we only
627 care about the invocation for the item that was being
631 if (item->get_active()) {
632 _route->set_remote_control_id (id);
637 RouteUI::build_solo_menu (void)
639 using namespace Menu_Helpers;
641 solo_menu = new Menu;
642 solo_menu->set_name ("ArdourContextMenu");
643 MenuList& items = solo_menu->items();
644 CheckMenuItem* check;
646 check = new CheckMenuItem(_("Solo-safe"));
647 check->set_active (_route->solo_safe());
648 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
649 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
650 items.push_back (CheckMenuElem(*check));
653 //items.push_back (SeparatorElem());
654 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
659 RouteUI::build_mute_menu(void)
661 using namespace Menu_Helpers;
663 mute_menu = new Menu;
664 mute_menu->set_name ("ArdourContextMenu");
665 MenuList& items = mute_menu->items();
666 CheckMenuItem* check;
668 check = new CheckMenuItem(_("Pre Fader"));
669 init_mute_menu(PRE_FADER, check);
670 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
671 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
672 items.push_back (CheckMenuElem(*check));
675 check = new CheckMenuItem(_("Post Fader"));
676 init_mute_menu(POST_FADER, check);
677 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
678 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
679 items.push_back (CheckMenuElem(*check));
682 check = new CheckMenuItem(_("Control Outs"));
683 init_mute_menu(CONTROL_OUTS, check);
684 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
685 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
686 items.push_back (CheckMenuElem(*check));
689 check = new CheckMenuItem(_("Main Outs"));
690 init_mute_menu(MAIN_OUTS, check);
691 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
692 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
693 items.push_back (CheckMenuElem(*check));
696 //items.push_back (SeparatorElem());
697 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
701 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
703 if (_route->get_mute_config (type)) {
704 check->set_active (true);
709 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
711 _route->set_mute_config(type, check->get_active(), this);
715 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
717 _route->set_solo_safe (check->get_active(), this);
721 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
723 RouteGroup* mix_group;
725 if((mix_group = route->mix_group()) != 0){
726 _session.begin_reversible_command (_("mix group solo change"));
727 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
728 mix_group->apply(&Route::set_solo, yn, this);
730 _session.add_command (cmd);
731 _session.commit_reversible_command ();
733 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
738 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
740 _session.begin_reversible_command (name);
741 XMLNode &before = _route->get_state();
742 bind(mem_fun(*_route, func), yn, arg)();
743 XMLNode &after = _route->get_state();
744 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
745 _session.commit_reversible_command ();
749 RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg)
751 _session.begin_reversible_command (name);
752 XMLNode &before = audio_track()->get_state();
753 bind (mem_fun (*audio_track(), func), yn, arg)();
754 XMLNode &after = audio_track()->get_state();
755 _session.add_command (new MementoCommand<AudioTrack>(*audio_track(), &before, &after));
756 _session.commit_reversible_command ();
760 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
762 RouteGroup* mix_group;
764 if((mix_group = route->mix_group()) != 0){
765 _session.begin_reversible_command (_("mix group mute change"));
766 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
767 mix_group->apply(&Route::set_mute, yn, this);
769 _session.add_command(cmd);
770 _session.commit_reversible_command ();
772 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
777 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
779 RouteGroup* mix_group;
781 if((mix_group = route->mix_group()) != 0){
782 _session.begin_reversible_command (_("mix group rec-enable change"));
783 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
784 mix_group->apply (&Route::set_record_enable, yn, this);
786 _session.add_command(cmd);
787 _session.commit_reversible_command ();
789 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
795 RouteUI::choose_color()
800 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
810 RouteUI::set_color (const Gdk::Color & c)
817 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
818 xml_node->add_property ("color", buf);
820 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
825 RouteUI::ensure_xml_node ()
828 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
829 xml_node = new XMLNode ("GUI");
830 _route->add_extra_xml (*xml_node);
836 RouteUI::get_child_xml_node (const string & childname)
843 if ((child = find_named_node (*xml_node, childname)) == 0) {
844 child = new XMLNode (childname);
845 xml_node->add_child_nocopy (*child);
852 RouteUI::set_color_from_route ()
856 RouteUI::ensure_xml_node ();
858 if ((prop = xml_node->property ("color")) != 0) {
860 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
870 RouteUI::remove_this_route ()
872 vector<string> choices;
876 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());
878 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
881 choices.push_back (_("No, do nothing."));
882 choices.push_back (_("Yes, remove it."));
884 Choice prompter (prompt, choices);
886 if (prompter.run () == 1) {
887 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
892 RouteUI::idle_remove_this_route (RouteUI *rui)
894 rui->_session.remove_route (rui->_route);
899 RouteUI::route_rename ()
901 ArdourPrompter name_prompter (true);
903 name_prompter.set_prompt (_("New Name: "));
904 name_prompter.set_initial_text (_route->name());
905 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
906 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
907 name_prompter.show_all ();
909 switch (name_prompter.run ()) {
911 case Gtk::RESPONSE_ACCEPT:
912 name_prompter.get_result (result);
913 if (result.length()) {
914 _route->set_name (result, this);
924 RouteUI::name_changed (void *src)
926 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed), src));
928 name_label.set_text (_route->name());
932 RouteUI::toggle_route_active ()
936 if (route_active_menu_item) {
937 if (route_active_menu_item->get_active() != (yn = _route->active())) {
938 _route->set_active (!yn);
944 RouteUI::route_active_changed ()
946 if (route_active_menu_item) {
947 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
952 RouteUI::toggle_polarity ()
954 if (polarity_menu_item) {
958 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
960 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
961 _route->set_phase_invert (x, this);
963 name_label.set_text (X_("Ø ") + name_label.get_text());
965 name_label.set_text (_route->name());
972 RouteUI::polarity_changed ()
974 /* no signal for this yet */
978 RouteUI::toggle_denormal_protection ()
980 if (denormal_menu_item) {
984 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
986 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
987 _route->set_denormal_protection (x, this);
993 RouteUI::denormal_protection_changed ()
995 /* no signal for this yet */
1000 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
1002 bool yn = _route->solo_safe ();
1004 if (check->get_active() != yn) {
1005 check->set_active (yn);
1009 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1011 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1013 bool yn = _route->get_mute_config(PRE_FADER);
1014 if (check->get_active() != yn) {
1015 check->set_active (yn);
1020 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1022 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1024 bool yn = _route->get_mute_config(POST_FADER);
1025 if (check->get_active() != yn) {
1026 check->set_active (yn);
1031 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1033 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1035 bool yn = _route->get_mute_config(CONTROL_OUTS);
1036 if (check->get_active() != yn) {
1037 check->set_active (yn);
1042 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1044 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1046 bool yn = _route->get_mute_config(MAIN_OUTS);
1047 if (check->get_active() != yn) {
1048 check->set_active (yn);
1053 RouteUI::disconnect_input ()
1055 _route->disconnect_inputs (this);
1059 RouteUI::disconnect_output ()
1061 _route->disconnect_outputs (this);
1065 RouteUI::is_track () const
1067 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1070 boost::shared_ptr<Track>
1071 RouteUI::track() const
1073 return boost::dynamic_pointer_cast<Track>(_route);
1077 RouteUI::is_audio_track () const
1079 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1082 boost::shared_ptr<AudioTrack>
1083 RouteUI::audio_track() const
1085 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1088 boost::shared_ptr<Diskstream>
1089 RouteUI::get_diskstream () const
1091 boost::shared_ptr<Track> t;
1093 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1094 return t->diskstream();
1096 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1101 RouteUI::name() const
1103 return _route->name();
1107 RouteUI::map_frozen ()
1109 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1111 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1114 switch (at->freeze_state()) {
1115 case AudioTrack::Frozen:
1116 rec_enable_button->set_sensitive (false);
1119 rec_enable_button->set_sensitive (true);