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>
27 #include <ardour/route_group.h>
28 #include <pbd/memento_command.h>
29 #include <pbd/stacktrace.h>
30 #include <pbd/shiva.h>
31 #include <pbd/controllable.h>
37 #include "gui_thread.h"
38 #include "ardour_dialog.h"
39 #include "latency_gui.h"
40 #include "automation_time_axis.h"
42 #include <ardour/route.h>
43 #include <ardour/session.h>
44 #include <ardour/audioengine.h>
45 #include <ardour/audio_track.h>
46 #include <ardour/audio_diskstream.h>
47 #include <ardour/midi_track.h>
48 #include <ardour/midi_diskstream.h>
53 using namespace Gtkmm2ext;
54 using namespace ARDOUR;
57 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name,
58 const char* s_name, const char* r_name)
68 remote_control_menu = 0;
69 ignore_toggle = false;
70 wait_for_release = false;
71 route_active_menu_item = 0;
72 was_solo_safe = false;
73 polarity_menu_item = 0;
74 denormal_menu_item = 0;
76 if (set_color_from_route()) {
77 set_color (unique_random_color());
80 new PairedShiva<Route,RouteUI> (*_route, *this);
82 _route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
84 mute_button = manage (new BindableToggleButton (*_route->mute_control().get(), m_name ));
85 mute_button->set_self_managed (true);
87 solo_button = manage (new BindableToggleButton (*_route->solo_control().get(), s_name ));
88 solo_button->set_self_managed (true);
90 mute_button->set_name ("MuteButton");
91 solo_button->set_name ("SoloButton");
93 _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
94 _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
95 _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
97 /* when solo changes, update mute state too, in case the user wants us to display it */
99 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
102 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
104 t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed));
106 _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
108 rec_enable_button = manage (new BindableToggleButton (*t->rec_enable_control().get(), r_name ));
109 rec_enable_button->set_name ("RecordEnableButton");
110 rec_enable_button->set_self_managed (true);
112 rec_enable_button->show();
113 update_rec_display ();
116 mute_button->unset_flags (Gtk::CAN_FOCUS);
117 solo_button->unset_flags (Gtk::CAN_FOCUS);
122 _route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu));
124 /* map the current state */
131 GoingAway (); /* EMIT SIGNAL */
136 RouteUI::mute_press(GdkEventButton* ev)
138 if (!ignore_toggle) {
140 if (Keyboard::is_context_menu_event (ev)) {
146 mute_menu->popup(0,ev->time);
150 if (ev->button == 2) {
151 // Primary-button2 click is the midi binding click
152 // button2-click is "momentary"
154 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
155 wait_for_release = true;
161 if (ev->button == 1 || ev->button == 2) {
163 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
165 /* Primary-Tertiary-click applies change to all routes */
167 _session.begin_reversible_command (_("mute change"));
168 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
169 _session.set_all_mute (!_route->muted());
171 _session.add_command(cmd);
172 _session.commit_reversible_command ();
174 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
176 /* Primary-button1 applies change to the mix group.
177 NOTE: Primary-button2 is MIDI learn.
180 if (ev->button == 1) {
181 set_mix_group_mute (_route, !_route->muted());
186 /* plain click applies change to this route */
188 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
199 RouteUI::mute_release(GdkEventButton* ev)
201 if (!ignore_toggle) {
202 if (wait_for_release){
203 wait_for_release = false;
205 // because the press was the last undoable thing we did
213 RouteUI::solo_press(GdkEventButton* ev)
215 if (!ignore_toggle) {
217 if (Keyboard::is_context_menu_event (ev)) {
219 if (solo_menu == 0) {
223 solo_menu->popup (1, ev->time);
227 if (ev->button == 2) {
229 // Primary-button2 click is the midi binding click
230 // button2-click is "momentary"
232 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
233 wait_for_release = true;
239 if (ev->button == 1 || ev->button == 2) {
241 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
243 /* Primary-Tertiary-click applies change to all routes */
245 _session.begin_reversible_command (_("solo change"));
246 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
247 _session.set_all_solo (!_route->soloed());
249 _session.add_command (cmd);
250 _session.commit_reversible_command ();
252 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
254 // Primary-Secondary-click: exclusively solo this track, not a toggle */
256 _session.begin_reversible_command (_("solo change"));
257 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
258 _session.set_all_solo (false);
259 _route->set_solo (true, this);
261 _session.add_command(cmd);
262 _session.commit_reversible_command ();
264 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
266 // shift-click: set this route to solo safe
268 _route->set_solo_safe (!_route->solo_safe(), this);
269 wait_for_release = false;
271 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
273 /* Primary-button1: solo mix group.
274 NOTE: Primary-button2 is MIDI learn.
277 if (ev->button == 1) {
278 set_mix_group_solo (_route, !_route->soloed());
283 /* click: solo this route */
285 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
295 RouteUI::solo_release(GdkEventButton* ev)
297 if (!ignore_toggle) {
298 if (wait_for_release) {
299 wait_for_release = false;
301 // because the press was the last undoable thing we did
311 RouteUI::rec_enable_press(GdkEventButton* ev)
313 if (!_session.engine().connected()) {
314 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
319 if (!ignore_toggle && is_track() && rec_enable_button) {
321 if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
323 // do nothing on midi bind event
326 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
328 _session.begin_reversible_command (_("rec-enable change"));
329 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
331 if (rec_enable_button->get_active()) {
332 _session.record_disenable_all ();
334 _session.record_enable_all ();
338 _session.add_command(cmd);
339 _session.commit_reversible_command ();
341 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
343 /* Primary-button1 applies change to the mix group.
344 NOTE: Primary-button2 is MIDI learn.
347 set_mix_group_rec_enable (_route, !_route->record_enabled());
351 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
359 RouteUI::rec_enable_release (GdkEventButton* ev)
365 RouteUI::solo_changed(void* src)
367 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
371 RouteUI::update_solo_display ()
374 vector<Gdk::Color> fg_colors;
377 if (solo_button->get_active() != (x = _route->soloed())){
378 ignore_toggle = true;
379 solo_button->set_active(x);
380 ignore_toggle = false;
383 if (_route->solo_safe()) {
384 solo_button->set_visual_state (2);
385 } else if (_route->soloed()) {
386 solo_button->set_visual_state (1);
388 solo_button->set_visual_state (0);
393 RouteUI::solo_changed_so_update_mute ()
395 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
399 RouteUI::mute_changed(void* src)
401 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
405 RouteUI::update_mute_display ()
407 bool model = _route->muted();
408 bool view = mute_button->get_active();
410 /* first make sure the button's "depressed" visual
415 ignore_toggle = true;
416 mute_button->set_active (model);
417 ignore_toggle = false;
420 /* now attend to visual state */
422 if (Config->get_show_solo_mutes()) {
423 if (_route->muted()) {
424 mute_button->set_visual_state (2);
425 } else if (!_route->soloed() && _route->solo_muted()) {
427 mute_button->set_visual_state (1);
429 mute_button->set_visual_state (0);
432 if (_route->muted()) {
433 mute_button->set_visual_state (2);
435 mute_button->set_visual_state (0);
442 RouteUI::route_rec_enable_changed ()
444 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
448 RouteUI::session_rec_enable_changed ()
450 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
454 RouteUI::update_rec_display ()
456 bool model = _route->record_enabled();
457 bool view = rec_enable_button->get_active();
459 /* first make sure the button's "depressed" visual
464 ignore_toggle = true;
465 rec_enable_button->set_active (model);
466 ignore_toggle = false;
469 /* now make sure its color state is correct */
473 switch (_session.record_status ()) {
474 case Session::Recording:
475 rec_enable_button->set_visual_state (1);
478 case Session::Disabled:
479 case Session::Enabled:
480 rec_enable_button->set_visual_state (2);
486 rec_enable_button->set_visual_state (0);
491 RouteUI::build_remote_control_menu ()
493 remote_control_menu = manage (new Menu);
494 refresh_remote_control_menu ();
498 RouteUI::refresh_remote_control_menu ()
500 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
502 // only refresh the menu if it has been instantiated
504 if (remote_control_menu == 0) {
508 using namespace Menu_Helpers;
510 RadioMenuItem::Group rc_group;
511 CheckMenuItem* rc_active;
512 uint32_t limit = _session.ntracks() + _session.nbusses();
515 MenuList& rc_items = remote_control_menu->items();
518 /* note that this menu list starts at zero, not 1, because zero
519 is a valid, if useless, ID.
522 limit += 4; /* leave some breathing room */
524 rc_items.push_back (RadioMenuElem (rc_group, _("None")));
525 if (_route->remote_control_id() == 0) {
526 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
527 rc_active->set_active ();
530 for (uint32_t i = 1; i < limit; ++i) {
531 snprintf (buf, sizeof (buf), "%u", i);
532 rc_items.push_back (RadioMenuElem (rc_group, buf));
533 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
534 if (_route->remote_control_id() == i) {
535 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
536 rc_active->set_active ();
538 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
543 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
545 /* this is called when the radio menu item is toggled, and so
546 is actually invoked twice per menu selection. we only
547 care about the invocation for the item that was being
551 if (item->get_active()) {
552 _route->set_remote_control_id (id);
557 RouteUI::build_solo_menu (void)
559 using namespace Menu_Helpers;
561 solo_menu = new Menu;
562 solo_menu->set_name ("ArdourContextMenu");
563 MenuList& items = solo_menu->items();
564 CheckMenuItem* check;
566 check = new CheckMenuItem(_("Solo-safe"));
567 check->set_active (_route->solo_safe());
568 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
569 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
570 items.push_back (CheckMenuElem(*check));
573 //items.push_back (SeparatorElem());
574 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
579 RouteUI::build_mute_menu(void)
581 using namespace Menu_Helpers;
583 mute_menu = new Menu;
584 mute_menu->set_name ("ArdourContextMenu");
585 MenuList& items = mute_menu->items();
586 CheckMenuItem* check;
588 check = new CheckMenuItem(_("Pre Fader"));
589 init_mute_menu(PRE_FADER, check);
590 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
591 _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
592 items.push_back (CheckMenuElem(*check));
595 check = new CheckMenuItem(_("Post Fader"));
596 init_mute_menu(POST_FADER, check);
597 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
598 _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
599 items.push_back (CheckMenuElem(*check));
602 check = new CheckMenuItem(_("Control Outs"));
603 init_mute_menu(CONTROL_OUTS, check);
604 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
605 _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
606 items.push_back (CheckMenuElem(*check));
609 check = new CheckMenuItem(_("Main Outs"));
610 init_mute_menu(MAIN_OUTS, check);
611 check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
612 _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
613 items.push_back (CheckMenuElem(*check));
616 //items.push_back (SeparatorElem());
617 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
621 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
623 if (_route->get_mute_config (type)) {
624 check->set_active (true);
629 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
631 _route->set_mute_config(type, check->get_active(), this);
635 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
637 _route->set_solo_safe (check->get_active(), this);
641 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
643 RouteGroup* mix_group;
645 if((mix_group = route->mix_group()) != 0){
646 _session.begin_reversible_command (_("mix group solo change"));
647 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
648 mix_group->apply(&Route::set_solo, yn, this);
650 _session.add_command (cmd);
651 _session.commit_reversible_command ();
653 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
658 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
660 _session.begin_reversible_command (name);
661 XMLNode &before = _route->get_state();
662 bind(mem_fun(*_route, func), yn, arg)();
663 XMLNode &after = _route->get_state();
664 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
665 _session.commit_reversible_command ();
669 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
671 _session.begin_reversible_command (name);
672 XMLNode &before = track()->get_state();
673 bind (mem_fun (*track(), func), yn, arg)();
674 XMLNode &after = track()->get_state();
675 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
676 _session.commit_reversible_command ();
680 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
682 RouteGroup* mix_group;
684 if((mix_group = route->mix_group()) != 0){
685 _session.begin_reversible_command (_("mix group mute change"));
686 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
687 mix_group->apply(&Route::set_mute, yn, this);
689 _session.add_command(cmd);
690 _session.commit_reversible_command ();
692 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
697 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
699 RouteGroup* mix_group;
701 if((mix_group = route->mix_group()) != 0){
702 _session.begin_reversible_command (_("mix group rec-enable change"));
703 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
704 mix_group->apply (&Route::set_record_enable, yn, this);
706 _session.add_command(cmd);
707 _session.commit_reversible_command ();
709 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
715 RouteUI::choose_color()
720 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
730 RouteUI::set_color (const Gdk::Color & c)
737 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
738 xml_node->add_property ("color", buf);
740 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
745 RouteUI::ensure_xml_node ()
748 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
749 xml_node = new XMLNode ("GUI");
750 _route->add_extra_xml (*xml_node);
756 RouteUI::get_automation_child_xml_node (Parameter param)
760 XMLNodeList kids = xml_node->children();
761 XMLNodeConstIterator iter;
763 for (iter = kids.begin(); iter != kids.end(); ++iter) {
764 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
765 XMLProperty* type = (*iter)->property("automation-id");
766 if (type && type->value() == param.to_string())
771 // Didn't find it, make a new one
772 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
773 child->add_property("automation-id", param.to_string());
774 xml_node->add_child_nocopy (*child);
780 RouteUI::set_color_from_route ()
784 RouteUI::ensure_xml_node ();
786 if ((prop = xml_node->property ("color")) != 0) {
788 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
798 RouteUI::remove_this_route ()
800 vector<string> choices;
804 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());
806 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
809 choices.push_back (_("No, do nothing."));
810 choices.push_back (_("Yes, remove it."));
812 Choice prompter (prompt, choices);
814 if (prompter.run () == 1) {
815 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
820 RouteUI::idle_remove_this_route (RouteUI *rui)
822 rui->_session.remove_route (rui->_route);
827 RouteUI::route_rename ()
829 ArdourPrompter name_prompter (true);
831 name_prompter.set_prompt (_("New Name: "));
832 name_prompter.set_initial_text (_route->name());
833 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
834 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
835 name_prompter.show_all ();
837 switch (name_prompter.run ()) {
839 case Gtk::RESPONSE_ACCEPT:
840 name_prompter.get_result (result);
841 if (result.length()) {
842 _route->set_name (result);
852 RouteUI::name_changed ()
854 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
856 name_label.set_text (_route->name());
860 RouteUI::toggle_route_active ()
864 if (route_active_menu_item) {
865 if (route_active_menu_item->get_active() != (yn = _route->active())) {
866 _route->set_active (!yn);
872 RouteUI::route_active_changed ()
874 if (route_active_menu_item) {
875 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
880 RouteUI::toggle_polarity ()
882 if (polarity_menu_item) {
886 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
888 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
889 _route->set_phase_invert (x, this);
891 name_label.set_text (X_("Ø ") + name_label.get_text());
893 name_label.set_text (_route->name());
900 RouteUI::polarity_changed ()
902 /* no signal for this yet */
906 RouteUI::toggle_denormal_protection ()
908 if (denormal_menu_item) {
912 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
914 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
915 _route->set_denormal_protection (x, this);
921 RouteUI::denormal_protection_changed ()
923 /* no signal for this yet */
928 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
930 bool yn = _route->solo_safe ();
932 if (check->get_active() != yn) {
933 check->set_active (yn);
937 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
939 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
941 bool yn = _route->get_mute_config(PRE_FADER);
942 if (check->get_active() != yn) {
943 check->set_active (yn);
948 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
950 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
952 bool yn = _route->get_mute_config(POST_FADER);
953 if (check->get_active() != yn) {
954 check->set_active (yn);
959 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
961 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
963 bool yn = _route->get_mute_config(CONTROL_OUTS);
964 if (check->get_active() != yn) {
965 check->set_active (yn);
970 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
972 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
974 bool yn = _route->get_mute_config(MAIN_OUTS);
975 if (check->get_active() != yn) {
976 check->set_active (yn);
981 RouteUI::disconnect_input ()
983 _route->disconnect_inputs (this);
987 RouteUI::disconnect_output ()
989 _route->disconnect_outputs (this);
993 RouteUI::is_track () const
995 return boost::dynamic_pointer_cast<Track>(_route) != 0;
998 boost::shared_ptr<Track>
999 RouteUI::track() const
1001 return boost::dynamic_pointer_cast<Track>(_route);
1005 RouteUI::is_audio_track () const
1007 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1010 boost::shared_ptr<AudioTrack>
1011 RouteUI::audio_track() const
1013 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1017 RouteUI::is_midi_track () const
1019 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1022 boost::shared_ptr<MidiTrack>
1023 RouteUI::midi_track() const
1025 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1028 boost::shared_ptr<Diskstream>
1029 RouteUI::get_diskstream () const
1031 boost::shared_ptr<Track> t;
1033 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1034 return t->diskstream();
1036 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1041 RouteUI::name() const
1043 return _route->name();
1047 RouteUI::map_frozen ()
1049 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1051 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1054 switch (at->freeze_state()) {
1055 case AudioTrack::Frozen:
1056 rec_enable_button->set_sensitive (false);
1059 rec_enable_button->set_sensitive (true);
1066 RouteUI::adjust_latency ()
1068 LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());