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 update_rec_display ();
234 if (is_midi_track()) {
235 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
236 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
242 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
243 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
245 update_monitoring_display ();
248 mute_button->unset_flags (Gtk::CAN_FOCUS);
249 solo_button->unset_flags (Gtk::CAN_FOCUS);
253 if (_route->is_monitor()) {
254 solo_button->hide ();
261 setup_invert_buttons ();
262 set_invert_button_state ();
264 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
265 bus_send_display_changed (s);
267 update_mute_display ();
268 update_solo_display ();
272 RouteUI::polarity_changed ()
278 set_invert_button_state ();
282 RouteUI::mute_press (GdkEventButton* ev)
284 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
288 multiple_mute_change = false;
290 if (!_i_am_the_modifier) {
292 if (Keyboard::is_context_menu_event (ev)) {
298 mute_menu->popup(0,ev->time);
302 if (Keyboard::is_button2_event (ev)) {
303 // Primary-button2 click is the midi binding click
304 // button2-click is "momentary"
307 if (mute_button->on_button_press_event (ev)) {
311 _mute_release = new SoloMuteRelease (_route->muted ());
314 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
316 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
319 _mute_release->routes = _session->get_routes ();
322 _session->set_mute (_session->get_routes(), !_route->muted());
324 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
326 /* Primary-button1 applies change to the mix group even if it is not active
327 NOTE: Primary-button2 is MIDI learn.
330 if (ev->button == 1 && _route->route_group()) {
332 _mute_release->routes = _session->get_routes ();
335 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
340 /* plain click applies change to this route */
342 boost::shared_ptr<RouteList> rl (new RouteList);
343 rl->push_back (_route);
346 _mute_release->routes = rl;
349 _session->set_mute (rl, !_route->muted());
361 RouteUI::mute_release (GdkEventButton*)
363 if (!_i_am_the_modifier) {
365 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
366 delete _mute_release;
375 RouteUI::solo_press(GdkEventButton* ev)
377 /* ignore double/triple clicks */
379 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
383 multiple_solo_change = false;
385 if (!_i_am_the_modifier) {
387 if (Keyboard::is_context_menu_event (ev)) {
389 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
390 ! (solo_safe_led && solo_safe_led->is_visible())) {
392 if (solo_menu == 0) {
396 solo_menu->popup (1, ev->time);
401 if (Keyboard::is_button2_event (ev)) {
403 // Primary-button2 click is the midi binding click
404 // button2-click is "momentary"
406 if (solo_button->on_button_press_event (ev)) {
410 _solo_release = new SoloMuteRelease (_route->self_soloed());
413 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
415 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
417 /* Primary-Tertiary-click applies change to all routes */
420 _solo_release->routes = _session->get_routes ();
423 if (Config->get_solo_control_is_listen_control()) {
424 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
426 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
429 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
431 // Primary-Secondary-click: exclusively solo this track
434 _solo_release->exclusive = true;
436 boost::shared_ptr<RouteList> routes = _session->get_routes();
438 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
439 if ((*i)->soloed ()) {
440 _solo_release->routes_on->push_back (*i);
442 _solo_release->routes_off->push_back (*i);
447 if (Config->get_solo_control_is_listen_control()) {
448 /* ??? we need a just_one_listen() method */
450 _session->set_just_one_solo (_route, true);
453 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
455 // shift-click: toggle solo isolated status
457 _route->set_solo_isolated (!_route->solo_isolated(), this);
458 delete _solo_release;
461 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
463 /* Primary-button1: solo mix group.
464 NOTE: Primary-button2 is MIDI learn.
467 if (ev->button == 1 && _route->route_group()) {
470 _solo_release->routes = _route->route_group()->route_list();
473 if (Config->get_solo_control_is_listen_control()) {
474 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
476 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
482 /* click: solo this route */
484 boost::shared_ptr<RouteList> rl (new RouteList);
485 rl->push_back (route());
488 _solo_release->routes = rl;
491 if (Config->get_solo_control_is_listen_control()) {
492 _session->set_listen (rl, !_route->listening_via_monitor());
494 _session->set_solo (rl, !_route->self_soloed());
505 RouteUI::solo_release (GdkEventButton*)
507 if (!_i_am_the_modifier) {
511 if (_solo_release->exclusive) {
514 if (Config->get_solo_control_is_listen_control()) {
515 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
517 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
521 delete _solo_release;
530 RouteUI::rec_enable_press(GdkEventButton* ev)
532 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
536 if (!_session->engine().connected()) {
537 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
542 if (is_midi_track()) {
544 /* rec-enable button exits from step editing */
546 if (midi_track()->step_editing()) {
547 midi_track()->set_step_editing (false);
552 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
554 if (Keyboard::is_button2_event (ev)) {
556 // do nothing on midi sigc::bind event
557 return rec_enable_button->on_button_press_event (ev);
559 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
561 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
563 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
565 /* Primary-button1 applies change to the route group (even if it is not active)
566 NOTE: Primary-button2 is MIDI learn.
568 if (ev->button == 1 && _route->route_group()) {
569 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->active_state(), Session::rt_cleanup, true);
572 } else if (Keyboard::is_context_menu_event (ev)) {
574 /* do this on release */
578 boost::shared_ptr<RouteList> rl (new RouteList);
579 rl->push_back (route());
580 _session->set_record_enabled (rl, !rec_enable_button->active_state());
588 RouteUI::monitoring_changed ()
590 update_monitoring_display ();
594 RouteUI::update_monitoring_display ()
600 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
606 MonitorState ms = t->monitoring_state();
608 if (t->monitoring_choice() & MonitorInput) {
609 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
611 if (ms & MonitoringInput) {
612 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
614 monitor_input_button->unset_active_state ();
618 if (t->monitoring_choice() & MonitorDisk) {
619 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
621 if (ms & MonitoringDisk) {
622 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
624 monitor_disk_button->unset_active_state ();
630 RouteUI::monitor_input_press(GdkEventButton*)
636 RouteUI::monitor_input_release(GdkEventButton* ev)
638 return monitor_release (ev, MonitorInput);
642 RouteUI::monitor_disk_press (GdkEventButton*)
648 RouteUI::monitor_disk_release (GdkEventButton* ev)
650 return monitor_release (ev, MonitorDisk);
654 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
656 if (ev->button != 1) {
660 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
667 boost::shared_ptr<RouteList> rl;
669 /* XXX for now, monitoring choices are orthogonal. cue monitoring
670 will follow in 3.X but requires mixing the input and playback (disk)
671 signal together, which requires yet more buffers.
674 if (t->monitoring_choice() & monitor_choice) {
675 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
677 /* this line will change when the options are non-orthogonal */
678 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
682 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
683 rl = _session->get_routes ();
685 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
686 if (_route->route_group() && _route->route_group()->is_monitoring()) {
687 rl = _route->route_group()->route_list();
689 rl.reset (new RouteList);
690 rl->push_back (route());
693 rl.reset (new RouteList);
694 rl->push_back (route());
697 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
703 RouteUI::build_record_menu ()
709 /* no rec-button context menu for non-MIDI tracks
712 if (is_midi_track()) {
713 record_menu = new Menu;
714 record_menu->set_name ("ArdourContextMenu");
716 using namespace Menu_Helpers;
717 MenuList& items = record_menu->items();
719 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
720 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
722 if (_route->record_enabled()) {
723 step_edit_item->set_sensitive (false);
726 step_edit_item->set_active (midi_track()->step_editing());
731 RouteUI::toggle_step_edit ()
733 if (!is_midi_track() || _route->record_enabled()) {
737 midi_track()->set_step_editing (step_edit_item->get_active());
741 RouteUI::step_edit_changed (bool yn)
744 if (rec_enable_button) {
745 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
748 start_step_editing ();
750 if (step_edit_item) {
751 step_edit_item->set_active (true);
756 if (rec_enable_button) {
757 rec_enable_button->unset_active_state ();
760 stop_step_editing ();
762 if (step_edit_item) {
763 step_edit_item->set_active (false);
769 RouteUI::rec_enable_release (GdkEventButton* ev)
771 if (Keyboard::is_context_menu_event (ev)) {
772 build_record_menu ();
774 record_menu->popup (1, ev->time);
783 RouteUI::build_sends_menu ()
785 using namespace Menu_Helpers;
787 sends_menu = new Menu;
788 sends_menu->set_name ("ArdourContextMenu");
789 MenuList& items = sends_menu->items();
792 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
796 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
800 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
804 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
808 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
812 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
815 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
819 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
822 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
823 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
824 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
829 RouteUI::create_sends (Placement p, bool include_buses)
831 _session->globally_add_internal_sends (_route, p, include_buses);
835 RouteUI::create_selected_sends (Placement p, bool include_buses)
837 boost::shared_ptr<RouteList> rlist (new RouteList);
838 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
840 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
841 RouteTimeAxisView* rtv;
843 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
844 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
845 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
846 rlist->push_back (rui->route());
852 _session->add_internal_sends (_route, p, rlist);
856 RouteUI::set_sends_gain_from_track ()
858 _session->globally_set_send_gains_from_track (_route);
862 RouteUI::set_sends_gain_to_zero ()
864 _session->globally_set_send_gains_to_zero (_route);
868 RouteUI::set_sends_gain_to_unity ()
870 _session->globally_set_send_gains_to_unity (_route);
874 RouteUI::show_sends_press(GdkEventButton* ev)
876 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
880 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
882 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
884 // do nothing on midi sigc::bind event
887 } else if (Keyboard::is_context_menu_event (ev)) {
889 if (sends_menu == 0) {
893 sends_menu->popup (0, ev->time);
897 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
900 set_showing_sends_to (boost::shared_ptr<Route> ());
902 set_showing_sends_to (_route);
911 RouteUI::show_sends_release (GdkEventButton*)
917 RouteUI::send_blink (bool onoff)
919 if (!show_sends_button) {
924 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
926 show_sends_button->unset_active_state ();
930 Gtkmm2ext::ActiveState
931 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
933 if (r->is_master() || r->is_monitor()) {
934 return Gtkmm2ext::Off;
937 if (Config->get_solo_control_is_listen_control()) {
939 if (r->listening_via_monitor()) {
940 return Gtkmm2ext::ExplicitActive;
942 return Gtkmm2ext::Off;
948 if (!r->self_soloed()) {
949 return Gtkmm2ext::ImplicitActive;
951 return Gtkmm2ext::ExplicitActive;
954 return Gtkmm2ext::Off;
958 Gtkmm2ext::ActiveState
959 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
961 if (r->is_master() || r->is_monitor()) {
962 return Gtkmm2ext::Off;
965 if (r->solo_isolated()) {
966 return Gtkmm2ext::ExplicitActive;
968 return Gtkmm2ext::Off;
972 Gtkmm2ext::ActiveState
973 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
975 if (r->is_master() || r->is_monitor()) {
976 return Gtkmm2ext::Off;
979 if (r->solo_safe()) {
980 return Gtkmm2ext::ExplicitActive;
982 return Gtkmm2ext::Off;
987 RouteUI::update_solo_display ()
989 bool yn = _route->solo_safe ();
991 if (solo_safe_check && solo_safe_check->get_active() != yn) {
992 solo_safe_check->set_active (yn);
995 yn = _route->solo_isolated ();
997 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
998 solo_isolated_check->set_active (yn);
1001 set_button_names ();
1003 if (solo_isolated_led) {
1004 if (_route->solo_isolated()) {
1005 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1007 solo_isolated_led->unset_active_state ();
1011 if (solo_safe_led) {
1012 if (_route->solo_safe()) {
1013 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1015 solo_safe_led->unset_active_state ();
1019 solo_button->set_active_state (solo_active_state (_route));
1021 /* some changes to solo status can affect mute display, so catch up
1024 update_mute_display ();
1028 RouteUI::solo_changed_so_update_mute ()
1030 update_mute_display ();
1034 RouteUI::mute_changed(void* /*src*/)
1036 update_mute_display ();
1040 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1042 if (r->is_monitor()) {
1043 return ActiveState(0);
1047 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1051 return Gtkmm2ext::ExplicitActive;
1052 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1053 /* master is NEVER muted by others */
1054 return Gtkmm2ext::ImplicitActive;
1056 /* no mute at all */
1057 return Gtkmm2ext::Off;
1064 return Gtkmm2ext::ExplicitActive;
1066 /* no mute at all */
1067 return Gtkmm2ext::Off;
1071 return ActiveState(0);
1075 RouteUI::update_mute_display ()
1081 mute_button->set_active_state (mute_active_state (_session, _route));
1085 RouteUI::route_rec_enable_changed ()
1087 update_rec_display ();
1088 update_monitoring_display ();
1092 RouteUI::session_rec_enable_changed ()
1094 update_rec_display ();
1095 update_monitoring_display ();
1099 RouteUI::update_rec_display ()
1101 if (!rec_enable_button || !_route) {
1105 if (_route->record_enabled()) {
1106 switch (_session->record_status ()) {
1107 case Session::Recording:
1108 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1111 case Session::Disabled:
1112 case Session::Enabled:
1113 rec_enable_button->set_active_state (Gtkmm2ext::ImplicitActive);
1118 if (step_edit_item) {
1119 step_edit_item->set_sensitive (false);
1123 rec_enable_button->unset_active_state ();
1125 if (step_edit_item) {
1126 step_edit_item->set_sensitive (true);
1131 check_rec_enable_sensitivity ();
1135 RouteUI::build_solo_menu (void)
1137 using namespace Menu_Helpers;
1139 solo_menu = new Menu;
1140 solo_menu->set_name ("ArdourContextMenu");
1141 MenuList& items = solo_menu->items();
1142 CheckMenuItem* check;
1144 check = new CheckMenuItem(_("Solo Isolate"));
1145 check->set_active (_route->solo_isolated());
1146 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1147 items.push_back (CheckMenuElem(*check));
1148 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1151 check = new CheckMenuItem(_("Solo Safe"));
1152 check->set_active (_route->solo_safe());
1153 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1154 items.push_back (CheckMenuElem(*check));
1155 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1158 //items.push_back (SeparatorElem());
1159 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1164 RouteUI::build_mute_menu(void)
1166 using namespace Menu_Helpers;
1168 mute_menu = new Menu;
1169 mute_menu->set_name ("ArdourContextMenu");
1171 MenuList& items = mute_menu->items();
1173 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1174 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1175 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1176 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1177 pre_fader_mute_check->show_all();
1179 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1180 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1181 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1182 items.push_back (CheckMenuElem(*post_fader_mute_check));
1183 post_fader_mute_check->show_all();
1185 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1186 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1187 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1188 items.push_back (CheckMenuElem(*listen_mute_check));
1189 listen_mute_check->show_all();
1191 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1192 init_mute_menu(MuteMaster::Main, main_mute_check);
1193 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1194 items.push_back (CheckMenuElem(*main_mute_check));
1195 main_mute_check->show_all();
1197 //items.push_back (SeparatorElem());
1198 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1200 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1204 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1206 check->set_active (_route->mute_points() & mp);
1210 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1212 if (check->get_active()) {
1213 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1215 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1220 RouteUI::muting_change ()
1222 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1225 MuteMaster::MutePoint current = _route->mute_points ();
1227 yn = (current & MuteMaster::PreFader);
1229 if (pre_fader_mute_check->get_active() != yn) {
1230 pre_fader_mute_check->set_active (yn);
1233 yn = (current & MuteMaster::PostFader);
1235 if (post_fader_mute_check->get_active() != yn) {
1236 post_fader_mute_check->set_active (yn);
1239 yn = (current & MuteMaster::Listen);
1241 if (listen_mute_check->get_active() != yn) {
1242 listen_mute_check->set_active (yn);
1245 yn = (current & MuteMaster::Main);
1247 if (main_mute_check->get_active() != yn) {
1248 main_mute_check->set_active (yn);
1253 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1255 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1259 bool view = solo_isolated_led->active_state();
1260 bool model = _route->solo_isolated();
1262 /* called BEFORE the view has changed */
1264 if (ev->button == 1) {
1265 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1268 /* disable isolate for all routes */
1269 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1273 if (model == view) {
1275 /* flip just this route */
1277 boost::shared_ptr<RouteList> rl (new RouteList);
1278 rl->push_back (_route);
1279 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1288 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1290 if (ev->button == 1) {
1291 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1298 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1300 bool view = check->get_active();
1301 bool model = _route->solo_isolated();
1303 /* called AFTER the view has changed */
1305 if (model != view) {
1306 _route->set_solo_isolated (view, this);
1311 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1313 _route->set_solo_safe (check->get_active(), this);
1316 /** Ask the user to choose a colour, and then set all selected tracks
1320 RouteUI::choose_color ()
1323 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1326 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1327 boost::bind (&RouteUI::set_color, _1, color)
1332 /** Set the route's own color. This may not be used for display if
1333 * the route is in a group which shares its color with its routes.
1336 RouteUI::set_color (const Gdk::Color & c)
1338 /* leave _color alone in the group case so that tracks can retain their
1339 * own pre-group colors.
1344 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1346 /* note: we use the route state ID here so that color is the same for both
1347 the time axis view and the mixer strip
1350 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1351 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1354 /** @return GUI state ID for things that are common to the route in all its representations */
1356 RouteUI::route_state_id () const
1358 return string_compose (X_("route %1"), _route->id().to_s());
1362 RouteUI::set_color_from_route ()
1364 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1372 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1375 _color.set_green (g);
1376 _color.set_blue (b);
1382 RouteUI::remove_this_route (bool apply_to_selection)
1384 if (apply_to_selection) {
1385 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1387 if ((route()->is_master() || route()->is_monitor()) &&
1388 !Config->get_allow_special_bus_removal()) {
1389 MessageDialog msg (_("That would be bad news ...."),
1393 msg.set_secondary_text (string_compose (_(
1394 "Removing the master or monitor bus is such a bad idea\n\
1395 that %1 is not going to allow it.\n\
1397 If you really want to do this sort of thing\n\
1398 edit your ardour.rc file to set the\n\
1399 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1406 vector<string> choices;
1410 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());
1412 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());
1415 choices.push_back (_("No, do nothing."));
1416 choices.push_back (_("Yes, remove it."));
1420 title = _("Remove track");
1422 title = _("Remove bus");
1425 Choice prompter (title, prompt, choices);
1427 if (prompter.run () == 1) {
1428 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1434 RouteUI::idle_remove_this_route (RouteUI *rui)
1436 rui->_session->remove_route (rui->route());
1440 /** @return true if this name should be used for the route, otherwise false */
1442 RouteUI::verify_new_route_name (const std::string& name)
1444 if (name.find (':') == string::npos) {
1448 MessageDialog colon_msg (
1449 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1450 false, MESSAGE_QUESTION, BUTTONS_NONE
1453 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1454 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1456 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1460 RouteUI::route_rename ()
1462 ArdourPrompter name_prompter (true);
1467 name_prompter.set_title (_("Rename Track"));
1469 name_prompter.set_title (_("Rename Bus"));
1471 name_prompter.set_prompt (_("New name:"));
1472 name_prompter.set_initial_text (_route->name());
1473 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1474 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1475 name_prompter.show_all ();
1478 switch (name_prompter.run ()) {
1479 case Gtk::RESPONSE_ACCEPT:
1480 name_prompter.get_result (result);
1481 name_prompter.hide ();
1482 if (result.length()) {
1483 if (verify_new_route_name (result)) {
1484 _route->set_name (result);
1487 /* back to name prompter */
1491 /* nothing entered, just get out of here */
1506 RouteUI::property_changed (const PropertyChange& what_changed)
1508 if (what_changed.contains (ARDOUR::Properties::name)) {
1509 name_label.set_text (_route->name());
1514 RouteUI::set_route_active (bool a, bool apply_to_selection)
1516 if (apply_to_selection) {
1517 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1519 _route->set_active (a, this);
1524 RouteUI::toggle_denormal_protection ()
1526 if (denormal_menu_item) {
1530 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1532 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1533 _route->set_denormal_protection (x);
1539 RouteUI::denormal_protection_changed ()
1541 if (denormal_menu_item) {
1542 denormal_menu_item->set_active (_route->denormal_protection());
1547 RouteUI::disconnect_input ()
1549 _route->input()->disconnect (this);
1553 RouteUI::disconnect_output ()
1555 _route->output()->disconnect (this);
1559 RouteUI::is_track () const
1561 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1564 boost::shared_ptr<Track>
1565 RouteUI::track() const
1567 return boost::dynamic_pointer_cast<Track>(_route);
1571 RouteUI::is_audio_track () const
1573 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1576 boost::shared_ptr<AudioTrack>
1577 RouteUI::audio_track() const
1579 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1583 RouteUI::is_midi_track () const
1585 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1588 boost::shared_ptr<MidiTrack>
1589 RouteUI::midi_track() const
1591 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1595 RouteUI::has_audio_outputs () const
1597 return (_route->n_outputs().n_audio() > 0);
1601 RouteUI::name() const
1603 return _route->name();
1607 RouteUI::map_frozen ()
1609 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1611 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1614 switch (at->freeze_state()) {
1615 case AudioTrack::Frozen:
1616 rec_enable_button->set_sensitive (false);
1619 rec_enable_button->set_sensitive (true);
1626 RouteUI::adjust_latency ()
1628 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1632 RouteUI::save_as_template ()
1635 std::string safe_name;
1638 path = ARDOUR::user_route_template_directory ();
1640 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1641 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1645 Prompter p (true); // modal
1647 p.set_title (_("Save As Template"));
1648 p.set_prompt (_("Template name:"));
1649 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1651 case RESPONSE_ACCEPT:
1658 p.get_result (name, true);
1660 safe_name = legalize_for_path (name);
1661 safe_name += template_suffix;
1663 path = Glib::build_filename (path, safe_name);
1665 _route->save_as_template (path, name);
1669 RouteUI::check_rec_enable_sensitivity ()
1671 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1672 rec_enable_button->set_sensitive (false);
1674 rec_enable_button->set_sensitive (true);
1677 update_monitoring_display ();
1681 RouteUI::parameter_changed (string const & p)
1683 /* this handles RC and per-session parameter changes */
1685 if (p == "disable-disarm-during-roll") {
1686 check_rec_enable_sensitivity ();
1687 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1688 set_button_names ();
1689 } else if (p == "auto-input") {
1690 update_monitoring_display ();
1695 RouteUI::step_gain_up ()
1697 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1701 RouteUI::page_gain_up ()
1703 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1707 RouteUI::step_gain_down ()
1709 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1713 RouteUI::page_gain_down ()
1715 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1719 RouteUI::open_remote_control_id_dialog ()
1721 ArdourDialog dialog (_("Remote Control ID"));
1722 SpinButton* spin = 0;
1724 dialog.get_vbox()->set_border_width (18);
1726 if (Config->get_remote_model() == UserOrdered) {
1727 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1729 HBox* hbox = manage (new HBox);
1730 hbox->set_spacing (6);
1731 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1732 spin = manage (new SpinButton);
1733 spin->set_digits (0);
1734 spin->set_increments (1, 10);
1735 spin->set_range (0, limit);
1736 spin->set_value (_route->remote_control_id());
1737 hbox->pack_start (*spin);
1738 dialog.get_vbox()->pack_start (*hbox);
1740 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1741 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1743 Label* l = manage (new Label());
1744 if (_route->is_master() || _route->is_monitor()) {
1745 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
1746 "The remote control ID of %3 cannot be changed."),
1747 Glib::Markup::escape_text (_route->name()),
1748 _route->remote_control_id(),
1749 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
1751 l->set_markup (string_compose (_("The remote control ID of %6 is: %3\n\n\n"
1752 "Remote Control IDs are currently determined by track/bus ordering in %1\n\n"
1753 "%4Use the User Interaction tab of the Preferences window if you want to change this%5"),
1754 (Config->get_remote_model() == MixerOrdered ? _("the mixer") : ("the editor")),
1755 (is_track() ? _("track") : _("bus")),
1756 _route->remote_control_id(),
1757 "<span size=\"small\" style=\"italic\">",
1759 Glib::Markup::escape_text (_route->name())));
1761 dialog.get_vbox()->pack_start (*l);
1762 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1766 int const r = dialog.run ();
1768 if (r == RESPONSE_ACCEPT && spin) {
1769 _route->set_remote_control_id (spin->get_value_as_int ());
1774 RouteUI::setup_invert_buttons ()
1776 /* remove old invert buttons */
1777 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1778 _invert_button_box.remove (**i);
1781 _invert_buttons.clear ();
1783 if (!_route || !_route->input()) {
1787 uint32_t const N = _route->input()->n_ports().n_audio ();
1789 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1791 for (uint32_t i = 0; i < to_add; ++i) {
1792 ArdourButton* b = manage (new ArdourButton);
1793 b->set_size_request(20,20);
1794 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1795 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
1797 b->set_name (X_("invert button"));
1800 b->set_text (string_compose (X_("Ø (%1)"), N));
1802 b->set_text (X_("Ø"));
1805 b->set_text (string_compose (X_("Ø%1"), i + 1));
1808 if (N <= _max_invert_buttons) {
1809 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));
1811 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
1814 _invert_buttons.push_back (b);
1815 _invert_button_box.pack_start (*b);
1818 _invert_button_box.set_spacing (1);
1819 _invert_button_box.show_all ();
1823 RouteUI::set_invert_button_state ()
1825 ++_i_am_the_modifier;
1827 uint32_t const N = _route->input()->n_ports().n_audio();
1828 if (N > _max_invert_buttons) {
1830 /* One button for many channels; explicit active if all channels are inverted,
1831 implicit active if some are, off if none are.
1834 ArdourButton* b = _invert_buttons.front ();
1836 if (_route->phase_invert().count() == _route->phase_invert().size()) {
1837 b->set_active_state (Gtkmm2ext::ExplicitActive);
1838 } else if (_route->phase_invert().any()) {
1839 b->set_active_state (Gtkmm2ext::ImplicitActive);
1841 b->set_active_state (Gtkmm2ext::Off);
1846 /* One button per channel; just set active */
1849 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1850 (*i)->set_active (_route->phase_invert (j));
1855 --_i_am_the_modifier;
1859 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
1861 if (ev->button == 1 && i < _invert_buttons.size()) {
1862 uint32_t const N = _route->input()->n_ports().n_audio ();
1863 if (N <= _max_invert_buttons) {
1864 /* left-click inverts phase so long as we have a button per channel */
1865 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
1874 RouteUI::invert_press (GdkEventButton* ev)
1876 using namespace Menu_Helpers;
1878 uint32_t const N = _route->input()->n_ports().n_audio();
1879 if (N <= _max_invert_buttons && ev->button != 3) {
1880 /* If we have an invert button per channel, we only pop
1881 up a menu on right-click; left click is handled
1887 delete _invert_menu;
1888 _invert_menu = new Menu;
1889 _invert_menu->set_name ("ArdourContextMenu");
1890 MenuList& items = _invert_menu->items ();
1892 for (uint32_t i = 0; i < N; ++i) {
1893 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1894 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1895 ++_i_am_the_modifier;
1896 e->set_active (_route->phase_invert (i));
1897 --_i_am_the_modifier;
1900 _invert_menu->popup (0, ev->time);
1906 RouteUI::invert_menu_toggled (uint32_t c)
1908 if (_i_am_the_modifier) {
1912 _route->set_phase_invert (c, !_route->phase_invert (c));
1916 RouteUI::set_invert_sensitive (bool yn)
1918 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1919 (*b)->set_sensitive (yn);
1924 RouteUI::request_redraw ()
1927 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1931 /** The Route's gui_changed signal has been emitted */
1933 RouteUI::route_gui_changed (string what_changed)
1935 if (what_changed == "color") {
1936 if (set_color_from_route () == 0) {
1937 route_color_changed ();
1942 /** @return the color that this route should use; it maybe its own,
1943 or it maybe that of its route group.
1946 RouteUI::color () const
1948 RouteGroup* g = _route->route_group ();
1950 if (g && g->is_color()) {
1951 return GroupTabs::group_color (g);
1958 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
1960 _showing_sends_to = send_to;
1961 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
1965 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1967 if (_route == send_to) {
1968 show_sends_button->set_active (true);
1969 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
1971 show_sends_button->set_active (false);
1972 send_blink_connection.disconnect ();
1977 RouteUI::route_group() const
1979 return _route->route_group();