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/choice.h>
22 #include <gtkmm2ext/doi.h>
23 #include <gtkmm2ext/bindable_button.h>
24 #include <gtkmm2ext/barcontroller.h>
25 #include <gtkmm2ext/gtk_ui.h>
27 #include "ardour/route_group.h"
28 #include "ardour/dB.h"
29 #include "pbd/memento_command.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/controllable.h"
32 #include "pbd/enumwriter.h"
34 #include "ardour_ui.h"
37 #include "ardour_button.h"
41 #include "gui_thread.h"
42 #include "ardour_dialog.h"
43 #include "latency_gui.h"
44 #include "mixer_strip.h"
45 #include "automation_time_axis.h"
46 #include "route_time_axis.h"
47 #include "group_tabs.h"
49 #include "ardour/route.h"
50 #include "ardour/event_type_map.h"
51 #include "ardour/session.h"
52 #include "ardour/audioengine.h"
53 #include "ardour/audio_track.h"
54 #include "ardour/midi_track.h"
55 #include "ardour/template_utils.h"
56 #include "ardour/filename_extensions.h"
57 #include "ardour/directory_names.h"
58 #include "ardour/profile.h"
62 using namespace Gtkmm2ext;
63 using namespace ARDOUR;
66 uint32_t RouteUI::_max_invert_buttons = 3;
67 sigc::signal<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
68 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
70 RouteUI::RouteUI (ARDOUR::Session* sess)
78 _route.reset (); /* drop reference to route, so that it can be cleaned up */
79 route_connections.drop_connections ();
97 pre_fader_mute_check = 0;
98 post_fader_mute_check = 0;
99 listen_mute_check = 0;
102 solo_isolated_check = 0;
103 solo_isolated_led = 0;
107 denormal_menu_item = 0;
109 multiple_mute_change = false;
110 multiple_solo_change = false;
111 _i_am_the_modifier = 0;
113 setup_invert_buttons ();
115 mute_button = manage (new ArdourButton);
116 mute_button->set_name ("mute button");
117 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
119 solo_button = manage (new ArdourButton);
120 solo_button->set_name ("solo button");
121 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
122 solo_button->set_no_show_all (true);
124 rec_enable_button = manage (new ArdourButton);
125 rec_enable_button->set_name ("record enable button");
126 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
128 show_sends_button = manage (new ArdourButton);
129 show_sends_button->set_name ("send alert button");
130 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
132 monitor_input_button = manage (new ArdourButton (ArdourButton::led_default_elements));
133 monitor_input_button->set_name ("monitor");
134 monitor_input_button->set_text (_("In"));
135 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
136 monitor_input_button->set_no_show_all (true);
138 monitor_disk_button = manage (new ArdourButton (ArdourButton::led_default_elements));
139 monitor_disk_button->set_name ("monitor");
140 monitor_disk_button->set_text (_("Disk"));
141 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
142 monitor_disk_button->set_no_show_all (true);
144 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
145 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
146 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
148 _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
149 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
151 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
152 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
154 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
155 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
157 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
158 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
159 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
160 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
162 monitor_input_button->set_distinct_led_click (false);
163 monitor_disk_button->set_distinct_led_click (false);
165 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
166 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
168 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
169 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
171 BusSendDisplayChanged.connect (sigc::mem_fun (*this, &RouteUI::bus_send_display_changed));
177 route_connections.drop_connections ();
185 denormal_menu_item = 0;
189 RouteUI::self_delete ()
195 RouteUI::set_route (boost::shared_ptr<Route> rp)
201 if (set_color_from_route()) {
202 set_color (unique_random_color());
206 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
209 mute_button->set_controllable (_route->mute_control());
210 solo_button->set_controllable (_route->solo_control());
212 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
213 _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
215 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
216 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
217 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
218 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
220 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
221 _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
223 _route->io_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::setup_invert_buttons, this), gui_context ());
224 _route->gui_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
226 if (_session->writable() && is_track()) {
227 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
229 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
231 rec_enable_button->show();
232 rec_enable_button->set_controllable (t->rec_enable_control());
234 update_rec_display ();
236 if (is_midi_track()) {
237 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
238 ui_bind (&RouteUI::step_edit_changed, this, _1), gui_context());
244 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
245 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
247 update_monitoring_display ();
250 mute_button->unset_flags (Gtk::CAN_FOCUS);
251 solo_button->unset_flags (Gtk::CAN_FOCUS);
255 if (_route->is_monitor()) {
256 solo_button->hide ();
263 setup_invert_buttons ();
264 set_invert_button_state ();
266 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
267 bus_send_display_changed (s);
271 RouteUI::polarity_changed ()
277 set_invert_button_state ();
281 RouteUI::mute_press (GdkEventButton* ev)
283 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
287 multiple_mute_change = false;
289 if (!_i_am_the_modifier) {
291 if (Keyboard::is_context_menu_event (ev)) {
297 mute_menu->popup(0,ev->time);
301 if (Keyboard::is_button2_event (ev)) {
302 // Primary-button2 click is the midi binding click
303 // button2-click is "momentary"
306 if (mute_button->on_button_press_event (ev)) {
310 _mute_release = new SoloMuteRelease (_route->muted ());
313 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
315 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
318 _mute_release->routes = _session->get_routes ();
321 _session->set_mute (_session->get_routes(), !_route->muted());
323 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
325 /* Primary-button1 applies change to the mix group even if it is not active
326 NOTE: Primary-button2 is MIDI learn.
329 if (ev->button == 1 && _route->route_group()) {
331 _mute_release->routes = _session->get_routes ();
334 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
339 /* plain click applies change to this route */
341 boost::shared_ptr<RouteList> rl (new RouteList);
342 rl->push_back (_route);
345 _mute_release->routes = rl;
348 _session->set_mute (rl, !_route->muted());
360 RouteUI::mute_release (GdkEventButton*)
362 if (!_i_am_the_modifier) {
364 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
365 delete _mute_release;
374 RouteUI::solo_press(GdkEventButton* ev)
376 /* ignore double/triple clicks */
378 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
382 multiple_solo_change = false;
384 if (!_i_am_the_modifier) {
386 if (Keyboard::is_context_menu_event (ev)) {
388 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
389 ! (solo_safe_led && solo_safe_led->is_visible())) {
391 if (solo_menu == 0) {
395 solo_menu->popup (1, ev->time);
400 if (Keyboard::is_button2_event (ev)) {
402 // Primary-button2 click is the midi binding click
403 // button2-click is "momentary"
405 if (solo_button->on_button_press_event (ev)) {
409 _solo_release = new SoloMuteRelease (_route->self_soloed());
412 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
414 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
416 /* Primary-Tertiary-click applies change to all routes */
419 _solo_release->routes = _session->get_routes ();
422 if (Config->get_solo_control_is_listen_control()) {
423 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
425 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
428 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
430 // Primary-Secondary-click: exclusively solo this track
433 _solo_release->exclusive = true;
435 boost::shared_ptr<RouteList> routes = _session->get_routes();
437 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
438 if ((*i)->soloed ()) {
439 _solo_release->routes_on->push_back (*i);
441 _solo_release->routes_off->push_back (*i);
446 if (Config->get_solo_control_is_listen_control()) {
447 /* ??? we need a just_one_listen() method */
449 _session->set_just_one_solo (_route, true);
452 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
454 // shift-click: toggle solo isolated status
456 _route->set_solo_isolated (!_route->solo_isolated(), this);
457 delete _solo_release;
460 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
462 /* Primary-button1: solo mix group.
463 NOTE: Primary-button2 is MIDI learn.
466 if (ev->button == 1 && _route->route_group()) {
469 _solo_release->routes = _route->route_group()->route_list();
472 if (Config->get_solo_control_is_listen_control()) {
473 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
475 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
481 /* click: solo this route */
483 boost::shared_ptr<RouteList> rl (new RouteList);
484 rl->push_back (route());
487 _solo_release->routes = rl;
490 if (Config->get_solo_control_is_listen_control()) {
491 _session->set_listen (rl, !_route->listening_via_monitor());
493 _session->set_solo (rl, !_route->self_soloed());
504 RouteUI::solo_release (GdkEventButton*)
506 if (!_i_am_the_modifier) {
510 if (_solo_release->exclusive) {
513 if (Config->get_solo_control_is_listen_control()) {
514 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
516 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
520 delete _solo_release;
529 RouteUI::rec_enable_press(GdkEventButton* ev)
531 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
535 if (!_session->engine().connected()) {
536 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
541 if (is_midi_track()) {
543 /* cannot rec-enable while step-editing */
545 if (midi_track()->step_editing()) {
550 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
552 if (Keyboard::is_button2_event (ev)) {
554 // do nothing on midi sigc::bind event
555 return rec_enable_button->on_button_press_event (ev);
557 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
559 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
561 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
563 /* Primary-button1 applies change to the route group (even if it is not active)
564 NOTE: Primary-button2 is MIDI learn.
566 if (ev->button == 1 && _route->route_group()) {
567 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->active_state(), Session::rt_cleanup, true);
570 } else if (Keyboard::is_context_menu_event (ev)) {
572 /* do this on release */
576 boost::shared_ptr<RouteList> rl (new RouteList);
577 rl->push_back (route());
578 _session->set_record_enabled (rl, !rec_enable_button->active_state());
586 RouteUI::monitoring_changed ()
588 update_monitoring_display ();
592 RouteUI::update_monitoring_display ()
598 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
604 MonitorState ms = t->monitoring_state();
606 if (t->monitoring_choice() & MonitorInput) {
607 monitor_input_button->set_active_state (Gtkmm2ext::Active);
609 if (ms & MonitoringInput) {
610 monitor_input_button->set_active_state (Gtkmm2ext::Mid);
612 monitor_input_button->unset_active_state ();
616 if (t->monitoring_choice() & MonitorDisk) {
617 monitor_disk_button->set_active_state (Gtkmm2ext::Active);
619 if (ms & MonitoringDisk) {
620 monitor_disk_button->set_active_state (Gtkmm2ext::Mid);
622 monitor_disk_button->unset_active_state ();
628 RouteUI::monitor_input_press(GdkEventButton* ev)
634 RouteUI::monitor_input_release(GdkEventButton* ev)
636 return monitor_release (ev, MonitorInput);
640 RouteUI::monitor_disk_press (GdkEventButton* ev)
646 RouteUI::monitor_disk_release (GdkEventButton* ev)
648 return monitor_release (ev, MonitorDisk);
652 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
654 if (ev->button != 1) {
658 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
665 boost::shared_ptr<RouteList> rl;
667 /* XXX for now, monitoring choices are orthogonal. cue monitoring
668 will follow in 3.X but requires mixing the input and playback (disk)
669 signal together, which requires yet more buffers.
672 if (t->monitoring_choice() & monitor_choice) {
673 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
675 /* this line will change when the options are non-orthogonal */
676 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
680 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
681 rl = _session->get_routes ();
683 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
684 if (_route->route_group() && _route->route_group()->is_monitoring()) {
685 rl = _route->route_group()->route_list();
687 rl.reset (new RouteList);
688 rl->push_back (route());
691 rl.reset (new RouteList);
692 rl->push_back (route());
695 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
701 RouteUI::build_record_menu ()
707 /* no rec-button context menu for non-MIDI tracks
710 if (is_midi_track()) {
711 record_menu = new Menu;
712 record_menu->set_name ("ArdourContextMenu");
714 using namespace Menu_Helpers;
715 MenuList& items = record_menu->items();
717 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
718 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
720 if (_route->record_enabled()) {
721 step_edit_item->set_sensitive (false);
724 step_edit_item->set_active (midi_track()->step_editing());
729 RouteUI::toggle_step_edit ()
731 if (!is_midi_track() || _route->record_enabled()) {
735 midi_track()->set_step_editing (step_edit_item->get_active());
739 RouteUI::step_edit_changed (bool yn)
742 if (rec_enable_button) {
743 rec_enable_button->set_active_state (Active);
746 start_step_editing ();
748 if (step_edit_item) {
749 step_edit_item->set_active (true);
754 if (rec_enable_button) {
755 rec_enable_button->unset_active_state ();
758 stop_step_editing ();
760 if (step_edit_item) {
761 step_edit_item->set_active (false);
767 RouteUI::rec_enable_release (GdkEventButton* ev)
769 if (Keyboard::is_context_menu_event (ev)) {
770 build_record_menu ();
772 record_menu->popup (1, ev->time);
781 RouteUI::build_sends_menu ()
783 using namespace Menu_Helpers;
785 sends_menu = new Menu;
786 sends_menu->set_name ("ArdourContextMenu");
787 MenuList& items = sends_menu->items();
790 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
794 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
798 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
802 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
806 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
810 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
813 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
817 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
820 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
821 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
822 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
827 RouteUI::create_sends (Placement p, bool include_buses)
829 _session->globally_add_internal_sends (_route, p, include_buses);
833 RouteUI::create_selected_sends (Placement p, bool include_buses)
835 boost::shared_ptr<RouteList> rlist (new RouteList);
836 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
838 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
839 RouteTimeAxisView* rtv;
841 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
842 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
843 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
844 rlist->push_back (rui->route());
850 _session->add_internal_sends (_route, p, rlist);
854 RouteUI::set_sends_gain_from_track ()
856 _session->globally_set_send_gains_from_track (_route);
860 RouteUI::set_sends_gain_to_zero ()
862 _session->globally_set_send_gains_to_zero (_route);
866 RouteUI::set_sends_gain_to_unity ()
868 _session->globally_set_send_gains_to_unity (_route);
872 RouteUI::show_sends_press(GdkEventButton* ev)
874 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
878 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
880 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
882 // do nothing on midi sigc::bind event
885 } else if (Keyboard::is_context_menu_event (ev)) {
887 if (sends_menu == 0) {
891 sends_menu->popup (0, ev->time);
895 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
898 set_showing_sends_to (boost::shared_ptr<Route> ());
900 set_showing_sends_to (_route);
909 RouteUI::show_sends_release (GdkEventButton*)
915 RouteUI::send_blink (bool onoff)
917 if (!show_sends_button) {
922 show_sends_button->set_active_state (Gtkmm2ext::Active);
924 show_sends_button->unset_active_state ();
928 Gtkmm2ext::ActiveState
929 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
931 if (r->is_master() || r->is_monitor()) {
932 return ActiveState (0);
935 if (Config->get_solo_control_is_listen_control()) {
937 if (r->listening_via_monitor()) {
940 return ActiveState (0);
946 if (!r->self_soloed()) {
952 return ActiveState(0);
956 Gtkmm2ext::ActiveState
957 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
959 if (r->is_master() || r->is_monitor()) {
960 return ActiveState (0);
963 if (r->solo_isolated()) {
966 return ActiveState(0);
970 Gtkmm2ext::ActiveState
971 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
973 if (r->is_master() || r->is_monitor()) {
974 return ActiveState (0);
977 if (r->solo_safe()) {
980 return ActiveState (0);
985 RouteUI::update_solo_display ()
989 if (Config->get_solo_control_is_listen_control()) {
991 if ((bool) solo_button->active_state() != (x = _route->listening_via_monitor())) {
992 ++_i_am_the_modifier;
993 solo_button->set_active_state (Active);
994 --_i_am_the_modifier;
999 if ((bool) solo_button->active_state() != (x = _route->soloed())) {
1000 ++_i_am_the_modifier;
1002 solo_button->set_active_state (Active);
1004 solo_button->unset_active_state();
1006 --_i_am_the_modifier;
1011 bool yn = _route->solo_safe ();
1013 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1014 solo_safe_check->set_active (yn);
1017 yn = _route->solo_isolated ();
1019 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1020 solo_isolated_check->set_active (yn);
1023 set_button_names ();
1025 if (solo_isolated_led) {
1026 if (_route->solo_isolated()) {
1027 solo_isolated_led->set_active_state (Gtkmm2ext::Active);
1029 solo_isolated_led->unset_active_state ();
1033 if (solo_safe_led) {
1034 if (_route->solo_safe()) {
1035 solo_safe_led->set_active_state (Gtkmm2ext::Active);
1037 solo_safe_led->unset_active_state ();
1041 solo_button->set_active_state (solo_active_state (_route));
1043 /* some changes to solo status can affect mute display, so catch up
1046 update_mute_display ();
1050 RouteUI::solo_changed_so_update_mute ()
1052 update_mute_display ();
1056 RouteUI::mute_changed(void* /*src*/)
1058 update_mute_display ();
1062 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1064 if (r->is_monitor()) {
1065 return ActiveState(0);
1069 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1074 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1075 /* master is NEVER muted by others */
1078 /* no mute at all */
1079 return ActiveState(0);
1088 /* no mute at all */
1089 return ActiveState(0);
1093 return ActiveState(0);
1097 RouteUI::update_mute_display ()
1103 mute_button->set_active_state (mute_active_state (_session, _route));
1107 RouteUI::route_rec_enable_changed ()
1109 update_rec_display ();
1110 update_monitoring_display ();
1114 RouteUI::session_rec_enable_changed ()
1116 update_rec_display ();
1117 update_monitoring_display ();
1121 RouteUI::update_rec_display ()
1123 if (!rec_enable_button || !_route) {
1127 if (_route->record_enabled()) {
1128 switch (_session->record_status ()) {
1129 case Session::Recording:
1130 rec_enable_button->set_active_state (Active);
1133 case Session::Disabled:
1134 case Session::Enabled:
1135 rec_enable_button->set_active_state (Mid);
1140 if (step_edit_item) {
1141 step_edit_item->set_sensitive (false);
1145 rec_enable_button->unset_active_state ();
1147 if (step_edit_item) {
1148 step_edit_item->set_sensitive (true);
1153 check_rec_enable_sensitivity ();
1157 RouteUI::build_solo_menu (void)
1159 using namespace Menu_Helpers;
1161 solo_menu = new Menu;
1162 solo_menu->set_name ("ArdourContextMenu");
1163 MenuList& items = solo_menu->items();
1164 CheckMenuItem* check;
1166 check = new CheckMenuItem(_("Solo Isolate"));
1167 check->set_active (_route->solo_isolated());
1168 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1169 items.push_back (CheckMenuElem(*check));
1170 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1173 check = new CheckMenuItem(_("Solo Safe"));
1174 check->set_active (_route->solo_safe());
1175 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1176 items.push_back (CheckMenuElem(*check));
1177 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1180 //items.push_back (SeparatorElem());
1181 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1186 RouteUI::build_mute_menu(void)
1188 using namespace Menu_Helpers;
1190 mute_menu = new Menu;
1191 mute_menu->set_name ("ArdourContextMenu");
1193 MenuList& items = mute_menu->items();
1195 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1196 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1197 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1198 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1199 pre_fader_mute_check->show_all();
1201 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1202 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1203 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1204 items.push_back (CheckMenuElem(*post_fader_mute_check));
1205 post_fader_mute_check->show_all();
1207 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1208 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1209 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1210 items.push_back (CheckMenuElem(*listen_mute_check));
1211 listen_mute_check->show_all();
1213 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1214 init_mute_menu(MuteMaster::Main, main_mute_check);
1215 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1216 items.push_back (CheckMenuElem(*main_mute_check));
1217 main_mute_check->show_all();
1219 //items.push_back (SeparatorElem());
1220 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1222 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1226 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1228 check->set_active (_route->mute_points() & mp);
1232 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1234 if (check->get_active()) {
1235 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1237 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1242 RouteUI::muting_change ()
1244 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1247 MuteMaster::MutePoint current = _route->mute_points ();
1249 yn = (current & MuteMaster::PreFader);
1251 if (pre_fader_mute_check->get_active() != yn) {
1252 pre_fader_mute_check->set_active (yn);
1255 yn = (current & MuteMaster::PostFader);
1257 if (post_fader_mute_check->get_active() != yn) {
1258 post_fader_mute_check->set_active (yn);
1261 yn = (current & MuteMaster::Listen);
1263 if (listen_mute_check->get_active() != yn) {
1264 listen_mute_check->set_active (yn);
1267 yn = (current & MuteMaster::Main);
1269 if (main_mute_check->get_active() != yn) {
1270 main_mute_check->set_active (yn);
1275 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1277 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1281 bool view = solo_isolated_led->active_state();
1282 bool model = _route->solo_isolated();
1284 /* called BEFORE the view has changed */
1286 if (ev->button == 1) {
1287 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1290 /* disable isolate for all routes */
1291 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1295 if (model == view) {
1297 /* flip just this route */
1299 boost::shared_ptr<RouteList> rl (new RouteList);
1300 rl->push_back (_route);
1301 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1310 RouteUI::solo_safe_button_release (GdkEventButton*)
1312 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1317 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1319 bool view = check->get_active();
1320 bool model = _route->solo_isolated();
1322 /* called AFTER the view has changed */
1324 if (model != view) {
1325 _route->set_solo_isolated (view, this);
1330 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1332 _route->set_solo_safe (check->get_active(), this);
1335 /** Ask the user to choose a colour, and then set all selected tracks
1339 RouteUI::choose_color ()
1342 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1345 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1346 boost::bind (&RouteUI::set_color, _1, color)
1351 /** Set the route's own color. This may not be used for display if
1352 * the route is in a group which shares its color with its routes.
1355 RouteUI::set_color (const Gdk::Color & c)
1361 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1363 /* note: we use the route state ID here so that color is the same for both
1364 the time axis view and the mixer strip
1367 gui_object_state().set<string> (route_state_id(), X_("color"), buf);
1368 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1371 /** @return GUI state ID for things that are common to the route in all its representations */
1373 RouteUI::route_state_id () const
1375 return string_compose (X_("route %1"), _route->id().to_s());
1379 RouteUI::set_color_from_route ()
1381 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1389 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1392 _color.set_green (g);
1393 _color.set_blue (b);
1399 RouteUI::remove_this_route (bool apply_to_selection)
1401 if (apply_to_selection) {
1402 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1404 if ((route()->is_master() || route()->is_monitor()) &&
1405 !Config->get_allow_special_bus_removal()) {
1406 MessageDialog msg (_("That would be bad news ...."),
1410 msg.set_secondary_text (string_compose (_(
1411 "Removing the master or monitor bus is such a bad idea\n\
1412 that %1 is not going to allow it.\n\
1414 If you really want to do this sort of thing\n\
1415 edit your ardour.rc file to set the\n\
1416 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1423 vector<string> choices;
1427 prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1429 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1432 choices.push_back (_("No, do nothing."));
1433 choices.push_back (_("Yes, remove it."));
1437 title = _("Remove track");
1439 title = _("Remove bus");
1442 Choice prompter (title, prompt, choices);
1444 if (prompter.run () == 1) {
1445 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1451 RouteUI::idle_remove_this_route (RouteUI *rui)
1453 rui->_session->remove_route (rui->route());
1457 /** @return true if this name should be used for the route, otherwise false */
1459 RouteUI::verify_new_route_name (const std::string& name)
1461 if (name.find (':') == string::npos) {
1465 MessageDialog colon_msg (
1466 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1467 false, MESSAGE_QUESTION, BUTTONS_NONE
1470 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1471 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1473 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1477 RouteUI::route_rename ()
1479 ArdourPrompter name_prompter (true);
1484 name_prompter.set_title (_("Rename Track"));
1486 name_prompter.set_title (_("Rename Bus"));
1488 name_prompter.set_prompt (_("New name:"));
1489 name_prompter.set_initial_text (_route->name());
1490 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1491 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1492 name_prompter.show_all ();
1495 switch (name_prompter.run ()) {
1496 case Gtk::RESPONSE_ACCEPT:
1497 name_prompter.get_result (result);
1498 name_prompter.hide ();
1499 if (result.length()) {
1500 if (verify_new_route_name (result)) {
1501 _route->set_name (result);
1504 /* back to name prompter */
1508 /* nothing entered, just get out of here */
1520 RouteUI::property_changed (const PropertyChange& what_changed)
1522 if (what_changed.contains (ARDOUR::Properties::name)) {
1523 name_label.set_text (_route->name());
1528 RouteUI::set_route_active (bool a, bool apply_to_selection)
1530 if (apply_to_selection) {
1531 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1533 _route->set_active (a, this);
1538 RouteUI::toggle_denormal_protection ()
1540 if (denormal_menu_item) {
1544 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1546 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1547 _route->set_denormal_protection (x);
1553 RouteUI::denormal_protection_changed ()
1555 if (denormal_menu_item) {
1556 denormal_menu_item->set_active (_route->denormal_protection());
1561 RouteUI::disconnect_input ()
1563 _route->input()->disconnect (this);
1567 RouteUI::disconnect_output ()
1569 _route->output()->disconnect (this);
1573 RouteUI::is_track () const
1575 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1578 boost::shared_ptr<Track>
1579 RouteUI::track() const
1581 return boost::dynamic_pointer_cast<Track>(_route);
1585 RouteUI::is_audio_track () const
1587 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1590 boost::shared_ptr<AudioTrack>
1591 RouteUI::audio_track() const
1593 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1597 RouteUI::is_midi_track () const
1599 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1602 boost::shared_ptr<MidiTrack>
1603 RouteUI::midi_track() const
1605 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1609 RouteUI::has_audio_outputs () const
1611 return (_route->n_outputs().n_audio() > 0);
1615 RouteUI::name() const
1617 return _route->name();
1621 RouteUI::map_frozen ()
1623 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1625 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1628 switch (at->freeze_state()) {
1629 case AudioTrack::Frozen:
1630 rec_enable_button->set_sensitive (false);
1633 rec_enable_button->set_sensitive (true);
1640 RouteUI::adjust_latency ()
1642 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1646 RouteUI::save_as_template ()
1649 std::string safe_name;
1652 path = ARDOUR::user_route_template_directory ();
1654 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1655 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1659 Prompter p (true); // modal
1661 p.set_title (_("Save As Template"));
1662 p.set_prompt (_("Template name:"));
1663 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1665 case RESPONSE_ACCEPT:
1672 p.get_result (name, true);
1674 safe_name = legalize_for_path (name);
1675 safe_name += template_suffix;
1679 _route->save_as_template (path.to_string(), name);
1683 RouteUI::check_rec_enable_sensitivity ()
1685 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1686 rec_enable_button->set_sensitive (false);
1688 rec_enable_button->set_sensitive (true);
1691 update_monitoring_display ();
1695 RouteUI::parameter_changed (string const & p)
1697 /* this handles RC and per-session parameter changes */
1699 if (p == "disable-disarm-during-roll") {
1700 check_rec_enable_sensitivity ();
1701 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1702 set_button_names ();
1703 } else if (p == "auto-input") {
1704 update_monitoring_display ();
1709 RouteUI::step_gain_up ()
1711 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1715 RouteUI::page_gain_up ()
1717 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1721 RouteUI::step_gain_down ()
1723 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1727 RouteUI::page_gain_down ()
1729 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1733 RouteUI::open_remote_control_id_dialog ()
1735 ArdourDialog dialog (_("Remote Control ID"));
1737 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1739 HBox* hbox = manage (new HBox);
1740 hbox->set_spacing (6);
1741 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1742 SpinButton* spin = manage (new SpinButton);
1743 spin->set_digits (0);
1744 spin->set_increments (1, 10);
1745 spin->set_range (0, limit);
1746 spin->set_value (_route->remote_control_id());
1747 hbox->pack_start (*spin);
1748 dialog.get_vbox()->pack_start (*hbox);
1750 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1751 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1754 int const r = dialog.run ();
1756 if (r == RESPONSE_ACCEPT) {
1757 _route->set_remote_control_id (spin->get_value_as_int ());
1762 RouteUI::setup_invert_buttons ()
1764 /* remove old invert buttons */
1765 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1766 _invert_button_box.remove (**i);
1769 _invert_buttons.clear ();
1771 if (!_route || !_route->input()) {
1775 uint32_t const N = _route->input()->n_ports().n_audio ();
1777 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1779 for (uint32_t i = 0; i < to_add; ++i) {
1780 BindableToggleButton* b = manage (new BindableToggleButton);
1781 b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_toggled), i, b));
1782 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1784 b->set_name (X_("MixerInvertButton"));
1786 b->add (*manage (new Label (X_("Ø"))));
1788 b->add (*manage (new Label (string_compose (X_("Ø%1"), i + 1))));
1792 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track. Right-click to show menu."), i + 1));
1794 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) all channels of this track. Right-click to show menu."), i + 1));
1797 _invert_buttons.push_back (b);
1798 _invert_button_box.pack_start (*b);
1801 _invert_button_box.show_all ();
1805 RouteUI::set_invert_button_state ()
1807 ++_i_am_the_modifier;
1809 uint32_t const N = _route->input()->n_ports().n_audio();
1810 if (N > _max_invert_buttons) {
1811 _invert_buttons.front()->set_active (_route->phase_invert().any());
1812 --_i_am_the_modifier;
1817 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1818 (*i)->set_active (_route->phase_invert (j));
1821 --_i_am_the_modifier;
1825 RouteUI::invert_toggled (uint32_t i, BindableToggleButton* b)
1827 if (_i_am_the_modifier) {
1831 uint32_t const N = _route->input()->n_ports().n_audio();
1832 if (N <= _max_invert_buttons) {
1833 _route->set_phase_invert (i, b->get_active ());
1835 boost::dynamic_bitset<> p (N);
1836 if (b->get_active ()) {
1839 _route->set_phase_invert (p);
1844 RouteUI::invert_press (GdkEventButton* ev)
1846 using namespace Menu_Helpers;
1848 if (ev->button != 3) {
1852 delete _invert_menu;
1853 _invert_menu = new Menu;
1854 _invert_menu->set_name ("ArdourContextMenu");
1855 MenuList& items = _invert_menu->items ();
1857 uint32_t const N = _route->input()->n_ports().n_audio();
1858 for (uint32_t i = 0; i < N; ++i) {
1859 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1860 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1861 ++_i_am_the_modifier;
1862 e->set_active (_route->phase_invert (i));
1863 --_i_am_the_modifier;
1866 _invert_menu->popup (0, ev->time);
1872 RouteUI::invert_menu_toggled (uint32_t c)
1874 if (_i_am_the_modifier) {
1878 _route->set_phase_invert (c, !_route->phase_invert (c));
1882 RouteUI::set_invert_sensitive (bool yn)
1884 for (list<BindableToggleButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1885 (*b)->set_sensitive (yn);
1890 RouteUI::request_redraw ()
1893 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1897 /** The Route's gui_changed signal has been emitted */
1899 RouteUI::route_gui_changed (string what_changed)
1901 if (what_changed == "color") {
1902 if (set_color_from_route () == 0) {
1903 route_color_changed ();
1908 /** @return the color that this route should use; it maybe its own,
1909 or it maybe that of its route group.
1912 RouteUI::color () const
1914 RouteGroup* g = _route->route_group ();
1916 if (g && g->is_color()) {
1917 return GroupTabs::group_color (g);
1924 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
1926 _showing_sends_to = send_to;
1927 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
1931 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1933 if (_route == send_to) {
1934 show_sends_button->set_active_state (Gtkmm2ext::Active);
1935 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
1937 show_sends_button->unset_active_state ();
1938 send_blink_connection.disconnect ();
1943 RouteUI::route_group() const
1945 return _route->route_group();