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/audio_track.h"
50 #include "ardour/audioengine.h"
51 #include "ardour/filename_extensions.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/route.h"
54 #include "ardour/session.h"
55 #include "ardour/template_utils.h"
59 using namespace Gtkmm2ext;
60 using namespace ARDOUR;
63 uint32_t RouteUI::_max_invert_buttons = 3;
64 sigc::signal<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
65 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
67 RouteUI::RouteUI (ARDOUR::Session* sess)
75 _route.reset (); /* drop reference to route, so that it can be cleaned up */
76 route_connections.drop_connections ();
94 pre_fader_mute_check = 0;
95 post_fader_mute_check = 0;
96 listen_mute_check = 0;
99 solo_isolated_check = 0;
100 solo_isolated_led = 0;
104 denormal_menu_item = 0;
106 multiple_mute_change = false;
107 multiple_solo_change = false;
108 _i_am_the_modifier = 0;
110 setup_invert_buttons ();
112 mute_button = manage (new ArdourButton);
113 mute_button->set_name ("mute button");
114 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
116 solo_button = manage (new ArdourButton);
117 solo_button->set_name ("solo button");
118 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
119 solo_button->set_no_show_all (true);
121 rec_enable_button = manage (new ArdourButton);
122 rec_enable_button->set_name ("record enable button");
123 rec_enable_button->set_tweaks (ArdourButton::ImplicitUsesSolidColor);
124 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
126 show_sends_button = manage (new ArdourButton);
127 show_sends_button->set_name ("send alert button");
128 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
130 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
131 monitor_input_button->set_name ("monitor button");
132 monitor_input_button->set_text (_("In"));
133 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
134 monitor_input_button->set_no_show_all (true);
136 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
137 monitor_disk_button->set_name ("monitor button");
138 monitor_disk_button->set_text (_("Disk"));
139 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
140 monitor_disk_button->set_no_show_all (true);
142 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
143 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
144 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
146 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
147 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
149 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
150 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
152 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
153 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
155 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
156 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
157 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
158 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
160 monitor_input_button->set_distinct_led_click (false);
161 monitor_disk_button->set_distinct_led_click (false);
163 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
164 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
166 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
167 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
169 BusSendDisplayChanged.connect (sigc::mem_fun (*this, &RouteUI::bus_send_display_changed));
175 route_connections.drop_connections ();
183 denormal_menu_item = 0;
187 RouteUI::self_delete ()
193 RouteUI::set_route (boost::shared_ptr<Route> rp)
199 if (set_color_from_route()) {
200 set_color (unique_random_color());
204 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
207 mute_button->set_controllable (_route->mute_control());
208 solo_button->set_controllable (_route->solo_control());
210 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
211 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::mute_changed, this, _1), gui_context());
213 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
214 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
215 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
216 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
218 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
219 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
221 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
222 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
224 if (_session->writable() && is_track()) {
225 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
227 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
229 rec_enable_button->show();
230 rec_enable_button->set_controllable (t->rec_enable_control());
232 if (is_midi_track()) {
233 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
234 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
239 /* this will work for busses and tracks, and needs to be called to
240 set up the name entry/name label display.
243 update_rec_display ();
246 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
247 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
249 update_monitoring_display ();
252 mute_button->unset_flags (Gtk::CAN_FOCUS);
253 solo_button->unset_flags (Gtk::CAN_FOCUS);
257 if (_route->is_monitor()) {
258 solo_button->hide ();
265 setup_invert_buttons ();
266 set_invert_button_state ();
268 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
269 bus_send_display_changed (s);
271 update_mute_display ();
272 update_solo_display ();
276 RouteUI::polarity_changed ()
282 set_invert_button_state ();
286 RouteUI::mute_press (GdkEventButton* ev)
288 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
292 multiple_mute_change = false;
294 if (!_i_am_the_modifier) {
296 if (Keyboard::is_context_menu_event (ev)) {
302 mute_menu->popup(0,ev->time);
306 if (Keyboard::is_button2_event (ev)) {
307 // Primary-button2 click is the midi binding click
308 // button2-click is "momentary"
311 if (mute_button->on_button_press_event (ev)) {
315 _mute_release = new SoloMuteRelease (_route->muted ());
318 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
320 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
323 _mute_release->routes = _session->get_routes ();
326 _session->set_mute (_session->get_routes(), !_route->muted());
328 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
330 /* Primary-button1 applies change to the mix group even if it is not active
331 NOTE: Primary-button2 is MIDI learn.
334 if (ev->button == 1 && _route->route_group()) {
336 _mute_release->routes = _session->get_routes ();
339 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
344 /* plain click applies change to this route */
346 boost::shared_ptr<RouteList> rl (new RouteList);
347 rl->push_back (_route);
350 _mute_release->routes = rl;
353 _session->set_mute (rl, !_route->muted());
365 RouteUI::mute_release (GdkEventButton*)
367 if (!_i_am_the_modifier) {
369 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
370 delete _mute_release;
379 RouteUI::solo_press(GdkEventButton* ev)
381 /* ignore double/triple clicks */
383 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
387 multiple_solo_change = false;
389 if (!_i_am_the_modifier) {
391 if (Keyboard::is_context_menu_event (ev)) {
393 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
394 ! (solo_safe_led && solo_safe_led->is_visible())) {
396 if (solo_menu == 0) {
400 solo_menu->popup (1, ev->time);
405 if (Keyboard::is_button2_event (ev)) {
407 // Primary-button2 click is the midi binding click
408 // button2-click is "momentary"
410 if (solo_button->on_button_press_event (ev)) {
414 _solo_release = new SoloMuteRelease (_route->self_soloed());
417 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
419 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
421 /* Primary-Tertiary-click applies change to all routes */
424 _solo_release->routes = _session->get_routes ();
427 if (Config->get_solo_control_is_listen_control()) {
428 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
430 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
433 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
435 // Primary-Secondary-click: exclusively solo this track
438 _solo_release->exclusive = true;
440 boost::shared_ptr<RouteList> routes = _session->get_routes();
442 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
443 if ((*i)->soloed ()) {
444 _solo_release->routes_on->push_back (*i);
446 _solo_release->routes_off->push_back (*i);
451 if (Config->get_solo_control_is_listen_control()) {
452 /* ??? we need a just_one_listen() method */
454 _session->set_just_one_solo (_route, true);
457 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
459 // shift-click: toggle solo isolated status
461 _route->set_solo_isolated (!_route->solo_isolated(), this);
462 delete _solo_release;
465 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
467 /* Primary-button1: solo mix group.
468 NOTE: Primary-button2 is MIDI learn.
471 if (ev->button == 1 && _route->route_group()) {
474 _solo_release->routes = _route->route_group()->route_list();
477 if (Config->get_solo_control_is_listen_control()) {
478 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
480 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
486 /* click: solo this route */
488 boost::shared_ptr<RouteList> rl (new RouteList);
489 rl->push_back (route());
492 _solo_release->routes = rl;
495 if (Config->get_solo_control_is_listen_control()) {
496 _session->set_listen (rl, !_route->listening_via_monitor());
498 _session->set_solo (rl, !_route->self_soloed());
509 RouteUI::solo_release (GdkEventButton*)
511 if (!_i_am_the_modifier) {
515 if (_solo_release->exclusive) {
518 if (Config->get_solo_control_is_listen_control()) {
519 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
521 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
525 delete _solo_release;
534 RouteUI::rec_enable_press(GdkEventButton* ev)
536 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
540 if (!_session->engine().connected()) {
541 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
546 if (is_midi_track()) {
548 /* rec-enable button exits from step editing */
550 if (midi_track()->step_editing()) {
551 midi_track()->set_step_editing (false);
556 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
558 if (Keyboard::is_button2_event (ev)) {
560 // do nothing on midi sigc::bind event
561 return rec_enable_button->on_button_press_event (ev);
563 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
565 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
567 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
569 /* Primary-button1 applies change to the route group (even if it is not active)
570 NOTE: Primary-button2 is MIDI learn.
572 if (ev->button == 1 && _route->route_group()) {
573 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->active_state(), Session::rt_cleanup, true);
576 } else if (Keyboard::is_context_menu_event (ev)) {
578 /* do this on release */
582 boost::shared_ptr<RouteList> rl (new RouteList);
583 rl->push_back (route());
584 _session->set_record_enabled (rl, !rec_enable_button->active_state());
592 RouteUI::monitoring_changed ()
594 update_monitoring_display ();
598 RouteUI::update_monitoring_display ()
604 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
610 MonitorState ms = t->monitoring_state();
612 if (t->monitoring_choice() & MonitorInput) {
613 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
615 if (ms & MonitoringInput) {
616 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
618 monitor_input_button->unset_active_state ();
622 if (t->monitoring_choice() & MonitorDisk) {
623 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
625 if (ms & MonitoringDisk) {
626 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
628 monitor_disk_button->unset_active_state ();
634 RouteUI::monitor_input_press(GdkEventButton*)
640 RouteUI::monitor_input_release(GdkEventButton* ev)
642 return monitor_release (ev, MonitorInput);
646 RouteUI::monitor_disk_press (GdkEventButton*)
652 RouteUI::monitor_disk_release (GdkEventButton* ev)
654 return monitor_release (ev, MonitorDisk);
658 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
660 if (ev->button != 1) {
664 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
671 boost::shared_ptr<RouteList> rl;
673 /* XXX for now, monitoring choices are orthogonal. cue monitoring
674 will follow in 3.X but requires mixing the input and playback (disk)
675 signal together, which requires yet more buffers.
678 if (t->monitoring_choice() & monitor_choice) {
679 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
681 /* this line will change when the options are non-orthogonal */
682 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
686 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
687 rl = _session->get_routes ();
689 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
690 if (_route->route_group() && _route->route_group()->is_monitoring()) {
691 rl = _route->route_group()->route_list();
693 rl.reset (new RouteList);
694 rl->push_back (route());
697 rl.reset (new RouteList);
698 rl->push_back (route());
701 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
707 RouteUI::build_record_menu ()
713 /* no rec-button context menu for non-MIDI tracks
716 if (is_midi_track()) {
717 record_menu = new Menu;
718 record_menu->set_name ("ArdourContextMenu");
720 using namespace Menu_Helpers;
721 MenuList& items = record_menu->items();
723 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
724 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
726 if (_route->record_enabled()) {
727 step_edit_item->set_sensitive (false);
730 step_edit_item->set_active (midi_track()->step_editing());
735 RouteUI::toggle_step_edit ()
737 if (!is_midi_track() || _route->record_enabled()) {
741 midi_track()->set_step_editing (step_edit_item->get_active());
745 RouteUI::step_edit_changed (bool yn)
748 if (rec_enable_button) {
749 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
752 start_step_editing ();
754 if (step_edit_item) {
755 step_edit_item->set_active (true);
760 if (rec_enable_button) {
761 rec_enable_button->unset_active_state ();
764 stop_step_editing ();
766 if (step_edit_item) {
767 step_edit_item->set_active (false);
773 RouteUI::rec_enable_release (GdkEventButton* ev)
775 if (Keyboard::is_context_menu_event (ev)) {
776 build_record_menu ();
778 record_menu->popup (1, ev->time);
787 RouteUI::build_sends_menu ()
789 using namespace Menu_Helpers;
791 sends_menu = new Menu;
792 sends_menu->set_name ("ArdourContextMenu");
793 MenuList& items = sends_menu->items();
796 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
800 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
804 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
808 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
812 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
816 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
819 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
823 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
826 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
827 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
828 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
833 RouteUI::create_sends (Placement p, bool include_buses)
835 _session->globally_add_internal_sends (_route, p, include_buses);
839 RouteUI::create_selected_sends (Placement p, bool include_buses)
841 boost::shared_ptr<RouteList> rlist (new RouteList);
842 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
844 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
845 RouteTimeAxisView* rtv;
847 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
848 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
849 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
850 rlist->push_back (rui->route());
856 _session->add_internal_sends (_route, p, rlist);
860 RouteUI::set_sends_gain_from_track ()
862 _session->globally_set_send_gains_from_track (_route);
866 RouteUI::set_sends_gain_to_zero ()
868 _session->globally_set_send_gains_to_zero (_route);
872 RouteUI::set_sends_gain_to_unity ()
874 _session->globally_set_send_gains_to_unity (_route);
878 RouteUI::show_sends_press(GdkEventButton* ev)
880 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
884 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
886 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
888 // do nothing on midi sigc::bind event
891 } else if (Keyboard::is_context_menu_event (ev)) {
893 if (sends_menu == 0) {
897 sends_menu->popup (0, ev->time);
901 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
904 set_showing_sends_to (boost::shared_ptr<Route> ());
906 set_showing_sends_to (_route);
915 RouteUI::show_sends_release (GdkEventButton*)
921 RouteUI::send_blink (bool onoff)
923 if (!show_sends_button) {
928 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
930 show_sends_button->unset_active_state ();
934 Gtkmm2ext::ActiveState
935 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
937 if (r->is_master() || r->is_monitor()) {
938 return Gtkmm2ext::Off;
941 if (Config->get_solo_control_is_listen_control()) {
943 if (r->listening_via_monitor()) {
944 return Gtkmm2ext::ExplicitActive;
946 return Gtkmm2ext::Off;
952 if (!r->self_soloed()) {
953 return Gtkmm2ext::ImplicitActive;
955 return Gtkmm2ext::ExplicitActive;
958 return Gtkmm2ext::Off;
962 Gtkmm2ext::ActiveState
963 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
965 if (r->is_master() || r->is_monitor()) {
966 return Gtkmm2ext::Off;
969 if (r->solo_isolated()) {
970 return Gtkmm2ext::ExplicitActive;
972 return Gtkmm2ext::Off;
976 Gtkmm2ext::ActiveState
977 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
979 if (r->is_master() || r->is_monitor()) {
980 return Gtkmm2ext::Off;
983 if (r->solo_safe()) {
984 return Gtkmm2ext::ExplicitActive;
986 return Gtkmm2ext::Off;
991 RouteUI::update_solo_display ()
993 bool yn = _route->solo_safe ();
995 if (solo_safe_check && solo_safe_check->get_active() != yn) {
996 solo_safe_check->set_active (yn);
999 yn = _route->solo_isolated ();
1001 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1002 solo_isolated_check->set_active (yn);
1005 set_button_names ();
1007 if (solo_isolated_led) {
1008 if (_route->solo_isolated()) {
1009 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1011 solo_isolated_led->unset_active_state ();
1015 if (solo_safe_led) {
1016 if (_route->solo_safe()) {
1017 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1019 solo_safe_led->unset_active_state ();
1023 solo_button->set_active_state (solo_active_state (_route));
1025 /* some changes to solo status can affect mute display, so catch up
1028 update_mute_display ();
1032 RouteUI::solo_changed_so_update_mute ()
1034 update_mute_display ();
1038 RouteUI::mute_changed(void* /*src*/)
1040 update_mute_display ();
1044 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1046 if (r->is_monitor()) {
1047 return ActiveState(0);
1051 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1055 return Gtkmm2ext::ExplicitActive;
1056 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1057 /* master is NEVER muted by others */
1058 return Gtkmm2ext::ImplicitActive;
1060 /* no mute at all */
1061 return Gtkmm2ext::Off;
1068 return Gtkmm2ext::ExplicitActive;
1070 /* no mute at all */
1071 return Gtkmm2ext::Off;
1075 return ActiveState(0);
1079 RouteUI::update_mute_display ()
1085 mute_button->set_active_state (mute_active_state (_session, _route));
1089 RouteUI::route_rec_enable_changed ()
1091 update_rec_display ();
1092 update_monitoring_display ();
1096 RouteUI::session_rec_enable_changed ()
1098 update_rec_display ();
1099 update_monitoring_display ();
1103 RouteUI::update_rec_display ()
1105 if (!rec_enable_button || !_route) {
1109 if (_route->record_enabled()) {
1110 switch (_session->record_status ()) {
1111 case Session::Recording:
1112 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1115 case Session::Disabled:
1116 case Session::Enabled:
1117 rec_enable_button->set_active_state (Gtkmm2ext::ImplicitActive);
1122 if (step_edit_item) {
1123 step_edit_item->set_sensitive (false);
1127 rec_enable_button->unset_active_state ();
1129 if (step_edit_item) {
1130 step_edit_item->set_sensitive (true);
1135 check_rec_enable_sensitivity ();
1139 RouteUI::build_solo_menu (void)
1141 using namespace Menu_Helpers;
1143 solo_menu = new Menu;
1144 solo_menu->set_name ("ArdourContextMenu");
1145 MenuList& items = solo_menu->items();
1146 CheckMenuItem* check;
1148 check = new CheckMenuItem(_("Solo Isolate"));
1149 check->set_active (_route->solo_isolated());
1150 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1151 items.push_back (CheckMenuElem(*check));
1152 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1155 check = new CheckMenuItem(_("Solo Safe"));
1156 check->set_active (_route->solo_safe());
1157 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1158 items.push_back (CheckMenuElem(*check));
1159 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1162 //items.push_back (SeparatorElem());
1163 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1168 RouteUI::build_mute_menu(void)
1170 using namespace Menu_Helpers;
1172 mute_menu = new Menu;
1173 mute_menu->set_name ("ArdourContextMenu");
1175 MenuList& items = mute_menu->items();
1177 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1178 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1179 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1180 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1181 pre_fader_mute_check->show_all();
1183 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1184 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1185 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1186 items.push_back (CheckMenuElem(*post_fader_mute_check));
1187 post_fader_mute_check->show_all();
1189 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1190 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1191 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1192 items.push_back (CheckMenuElem(*listen_mute_check));
1193 listen_mute_check->show_all();
1195 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1196 init_mute_menu(MuteMaster::Main, main_mute_check);
1197 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1198 items.push_back (CheckMenuElem(*main_mute_check));
1199 main_mute_check->show_all();
1201 //items.push_back (SeparatorElem());
1202 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1204 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1208 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1210 check->set_active (_route->mute_points() & mp);
1214 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1216 if (check->get_active()) {
1217 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1219 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1224 RouteUI::muting_change ()
1226 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1229 MuteMaster::MutePoint current = _route->mute_points ();
1231 yn = (current & MuteMaster::PreFader);
1233 if (pre_fader_mute_check->get_active() != yn) {
1234 pre_fader_mute_check->set_active (yn);
1237 yn = (current & MuteMaster::PostFader);
1239 if (post_fader_mute_check->get_active() != yn) {
1240 post_fader_mute_check->set_active (yn);
1243 yn = (current & MuteMaster::Listen);
1245 if (listen_mute_check->get_active() != yn) {
1246 listen_mute_check->set_active (yn);
1249 yn = (current & MuteMaster::Main);
1251 if (main_mute_check->get_active() != yn) {
1252 main_mute_check->set_active (yn);
1257 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1259 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1263 bool view = solo_isolated_led->active_state();
1264 bool model = _route->solo_isolated();
1266 /* called BEFORE the view has changed */
1268 if (ev->button == 1) {
1269 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1272 /* disable isolate for all routes */
1273 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1277 if (model == view) {
1279 /* flip just this route */
1281 boost::shared_ptr<RouteList> rl (new RouteList);
1282 rl->push_back (_route);
1283 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1292 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1294 if (ev->button == 1) {
1295 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1302 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1304 bool view = check->get_active();
1305 bool model = _route->solo_isolated();
1307 /* called AFTER the view has changed */
1309 if (model != view) {
1310 _route->set_solo_isolated (view, this);
1315 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1317 _route->set_solo_safe (check->get_active(), this);
1320 /** Ask the user to choose a colour, and then set all selected tracks
1324 RouteUI::choose_color ()
1327 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1330 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1331 boost::bind (&RouteUI::set_color, _1, color)
1336 /** Set the route's own color. This may not be used for display if
1337 * the route is in a group which shares its color with its routes.
1340 RouteUI::set_color (const Gdk::Color & c)
1342 /* leave _color alone in the group case so that tracks can retain their
1343 * own pre-group colors.
1348 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1350 /* note: we use the route state ID here so that color is the same for both
1351 the time axis view and the mixer strip
1354 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1355 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1358 /** @return GUI state ID for things that are common to the route in all its representations */
1360 RouteUI::route_state_id () const
1362 return string_compose (X_("route %1"), _route->id().to_s());
1366 RouteUI::set_color_from_route ()
1368 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1376 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1379 _color.set_green (g);
1380 _color.set_blue (b);
1386 RouteUI::remove_this_route (bool apply_to_selection)
1388 if (apply_to_selection) {
1389 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1391 if ((route()->is_master() || route()->is_monitor()) &&
1392 !Config->get_allow_special_bus_removal()) {
1393 MessageDialog msg (_("That would be bad news ...."),
1397 msg.set_secondary_text (string_compose (_(
1398 "Removing the master or monitor bus is such a bad idea\n\
1399 that %1 is not going to allow it.\n\
1401 If you really want to do this sort of thing\n\
1402 edit your ardour.rc file to set the\n\
1403 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1410 vector<string> choices;
1414 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());
1416 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());
1419 choices.push_back (_("No, do nothing."));
1420 choices.push_back (_("Yes, remove it."));
1424 title = _("Remove track");
1426 title = _("Remove bus");
1429 Choice prompter (title, prompt, choices);
1431 if (prompter.run () == 1) {
1432 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1438 RouteUI::idle_remove_this_route (RouteUI *rui)
1440 rui->_session->remove_route (rui->route());
1444 /** @return true if this name should be used for the route, otherwise false */
1446 RouteUI::verify_new_route_name (const std::string& name)
1448 if (name.find (':') == string::npos) {
1452 MessageDialog colon_msg (
1453 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1454 false, MESSAGE_QUESTION, BUTTONS_NONE
1457 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1458 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1460 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1464 RouteUI::route_rename ()
1466 ArdourPrompter name_prompter (true);
1471 name_prompter.set_title (_("Rename Track"));
1473 name_prompter.set_title (_("Rename Bus"));
1475 name_prompter.set_prompt (_("New name:"));
1476 name_prompter.set_initial_text (_route->name());
1477 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1478 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1479 name_prompter.show_all ();
1482 switch (name_prompter.run ()) {
1483 case Gtk::RESPONSE_ACCEPT:
1484 name_prompter.get_result (result);
1485 name_prompter.hide ();
1486 if (result.length()) {
1487 if (verify_new_route_name (result)) {
1488 _route->set_name (result);
1491 /* back to name prompter */
1495 /* nothing entered, just get out of here */
1510 RouteUI::property_changed (const PropertyChange& what_changed)
1512 if (what_changed.contains (ARDOUR::Properties::name)) {
1513 name_label.set_text (_route->name());
1518 RouteUI::set_route_active (bool a, bool apply_to_selection)
1520 if (apply_to_selection) {
1521 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1523 _route->set_active (a, this);
1528 RouteUI::toggle_denormal_protection ()
1530 if (denormal_menu_item) {
1534 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1536 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1537 _route->set_denormal_protection (x);
1543 RouteUI::denormal_protection_changed ()
1545 if (denormal_menu_item) {
1546 denormal_menu_item->set_active (_route->denormal_protection());
1551 RouteUI::disconnect_input ()
1553 _route->input()->disconnect (this);
1557 RouteUI::disconnect_output ()
1559 _route->output()->disconnect (this);
1563 RouteUI::is_track () const
1565 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1568 boost::shared_ptr<Track>
1569 RouteUI::track() const
1571 return boost::dynamic_pointer_cast<Track>(_route);
1575 RouteUI::is_audio_track () const
1577 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1580 boost::shared_ptr<AudioTrack>
1581 RouteUI::audio_track() const
1583 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1587 RouteUI::is_midi_track () const
1589 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1592 boost::shared_ptr<MidiTrack>
1593 RouteUI::midi_track() const
1595 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1599 RouteUI::has_audio_outputs () const
1601 return (_route->n_outputs().n_audio() > 0);
1605 RouteUI::name() const
1607 return _route->name();
1611 RouteUI::map_frozen ()
1613 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1615 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1618 switch (at->freeze_state()) {
1619 case AudioTrack::Frozen:
1620 rec_enable_button->set_sensitive (false);
1623 rec_enable_button->set_sensitive (true);
1630 RouteUI::adjust_latency ()
1632 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1636 RouteUI::save_as_template ()
1639 std::string safe_name;
1642 path = ARDOUR::user_route_template_directory ();
1644 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1645 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1649 Prompter p (true); // modal
1651 p.set_title (_("Save As Template"));
1652 p.set_prompt (_("Template name:"));
1653 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1655 case RESPONSE_ACCEPT:
1662 p.get_result (name, true);
1664 safe_name = legalize_for_path (name);
1665 safe_name += template_suffix;
1667 path = Glib::build_filename (path, safe_name);
1669 _route->save_as_template (path, name);
1673 RouteUI::check_rec_enable_sensitivity ()
1675 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1676 rec_enable_button->set_sensitive (false);
1678 rec_enable_button->set_sensitive (true);
1681 update_monitoring_display ();
1685 RouteUI::parameter_changed (string const & p)
1687 /* this handles RC and per-session parameter changes */
1689 if (p == "disable-disarm-during-roll") {
1690 check_rec_enable_sensitivity ();
1691 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1692 set_button_names ();
1693 } else if (p == "auto-input") {
1694 update_monitoring_display ();
1699 RouteUI::step_gain_up ()
1701 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1705 RouteUI::page_gain_up ()
1707 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1711 RouteUI::step_gain_down ()
1713 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1717 RouteUI::page_gain_down ()
1719 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1723 RouteUI::open_remote_control_id_dialog ()
1725 ArdourDialog dialog (_("Remote Control ID"));
1726 SpinButton* spin = 0;
1728 dialog.get_vbox()->set_border_width (18);
1730 if (Config->get_remote_model() == UserOrdered) {
1731 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1733 HBox* hbox = manage (new HBox);
1734 hbox->set_spacing (6);
1735 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1736 spin = manage (new SpinButton);
1737 spin->set_digits (0);
1738 spin->set_increments (1, 10);
1739 spin->set_range (0, limit);
1740 spin->set_value (_route->remote_control_id());
1741 hbox->pack_start (*spin);
1742 dialog.get_vbox()->pack_start (*hbox);
1744 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1745 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1747 Label* l = manage (new Label());
1748 if (_route->is_master() || _route->is_monitor()) {
1749 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
1750 "The remote control ID of %3 cannot be changed."),
1751 Glib::Markup::escape_text (_route->name()),
1752 _route->remote_control_id(),
1753 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
1755 l->set_markup (string_compose (_("The remote control ID of %6 is: %3\n\n\n"
1756 "Remote Control IDs are currently determined by track/bus ordering in %1\n\n"
1757 "%4Use the User Interaction tab of the Preferences window if you want to change this%5"),
1758 (Config->get_remote_model() == MixerOrdered ? _("the mixer") : _("the editor")),
1759 (is_track() ? _("track") : _("bus")),
1760 _route->remote_control_id(),
1761 "<span size=\"small\" style=\"italic\">",
1763 Glib::Markup::escape_text (_route->name())));
1765 dialog.get_vbox()->pack_start (*l);
1766 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1770 int const r = dialog.run ();
1772 if (r == RESPONSE_ACCEPT && spin) {
1773 _route->set_remote_control_id (spin->get_value_as_int ());
1778 RouteUI::setup_invert_buttons ()
1780 /* remove old invert buttons */
1781 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1782 _invert_button_box.remove (**i);
1785 _invert_buttons.clear ();
1787 if (!_route || !_route->input()) {
1791 uint32_t const N = _route->input()->n_ports().n_audio ();
1793 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1795 for (uint32_t i = 0; i < to_add; ++i) {
1796 ArdourButton* b = manage (new ArdourButton);
1797 b->set_size_request(20,20);
1798 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1799 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
1801 b->set_name (X_("invert button"));
1804 b->set_text (string_compose (X_("Ø (%1)"), N));
1806 b->set_text (X_("Ø"));
1809 b->set_text (string_compose (X_("Ø%1"), i + 1));
1812 if (N <= _max_invert_buttons) {
1813 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));
1815 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
1818 _invert_buttons.push_back (b);
1819 _invert_button_box.pack_start (*b);
1822 _invert_button_box.set_spacing (1);
1823 _invert_button_box.show_all ();
1827 RouteUI::set_invert_button_state ()
1829 ++_i_am_the_modifier;
1831 uint32_t const N = _route->input()->n_ports().n_audio();
1832 if (N > _max_invert_buttons) {
1834 /* One button for many channels; explicit active if all channels are inverted,
1835 implicit active if some are, off if none are.
1838 ArdourButton* b = _invert_buttons.front ();
1840 if (_route->phase_invert().count() == _route->phase_invert().size()) {
1841 b->set_active_state (Gtkmm2ext::ExplicitActive);
1842 } else if (_route->phase_invert().any()) {
1843 b->set_active_state (Gtkmm2ext::ImplicitActive);
1845 b->set_active_state (Gtkmm2ext::Off);
1850 /* One button per channel; just set active */
1853 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1854 (*i)->set_active (_route->phase_invert (j));
1859 --_i_am_the_modifier;
1863 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
1865 if (ev->button == 1 && i < _invert_buttons.size()) {
1866 uint32_t const N = _route->input()->n_ports().n_audio ();
1867 if (N <= _max_invert_buttons) {
1868 /* left-click inverts phase so long as we have a button per channel */
1869 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
1878 RouteUI::invert_press (GdkEventButton* ev)
1880 using namespace Menu_Helpers;
1882 uint32_t const N = _route->input()->n_ports().n_audio();
1883 if (N <= _max_invert_buttons && ev->button != 3) {
1884 /* If we have an invert button per channel, we only pop
1885 up a menu on right-click; left click is handled
1891 delete _invert_menu;
1892 _invert_menu = new Menu;
1893 _invert_menu->set_name ("ArdourContextMenu");
1894 MenuList& items = _invert_menu->items ();
1896 for (uint32_t i = 0; i < N; ++i) {
1897 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1898 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1899 ++_i_am_the_modifier;
1900 e->set_active (_route->phase_invert (i));
1901 --_i_am_the_modifier;
1904 _invert_menu->popup (0, ev->time);
1910 RouteUI::invert_menu_toggled (uint32_t c)
1912 if (_i_am_the_modifier) {
1916 _route->set_phase_invert (c, !_route->phase_invert (c));
1920 RouteUI::set_invert_sensitive (bool yn)
1922 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1923 (*b)->set_sensitive (yn);
1928 RouteUI::request_redraw ()
1931 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1935 /** The Route's gui_changed signal has been emitted */
1937 RouteUI::route_gui_changed (string what_changed)
1939 if (what_changed == "color") {
1940 if (set_color_from_route () == 0) {
1941 route_color_changed ();
1946 /** @return the color that this route should use; it maybe its own,
1947 or it maybe that of its route group.
1950 RouteUI::color () const
1952 RouteGroup* g = _route->route_group ();
1954 if (g && g->is_color()) {
1955 return GroupTabs::group_color (g);
1962 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
1964 _showing_sends_to = send_to;
1965 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
1969 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1971 if (_route == send_to) {
1972 show_sends_button->set_active (true);
1973 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
1975 show_sends_button->set_active (false);
1976 send_blink_connection.disconnect ();
1981 RouteUI::route_group() const
1983 return _route->route_group();