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 RouteGroup* g = _route->route_group ();
1340 /* leave _color alone in the group case so that tracks can retain their
1341 * own pre-group colors.
1344 if (g && g->is_color()) {
1345 GroupTabs::set_group_color (g, c);
1349 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1351 /* note: we use the route state ID here so that color is the same for both
1352 the time axis view and the mixer strip
1355 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1356 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1360 /** @return GUI state ID for things that are common to the route in all its representations */
1362 RouteUI::route_state_id () const
1364 return string_compose (X_("route %1"), _route->id().to_s());
1368 RouteUI::set_color_from_route ()
1370 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1378 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1381 _color.set_green (g);
1382 _color.set_blue (b);
1388 RouteUI::remove_this_route (bool apply_to_selection)
1390 if (apply_to_selection) {
1391 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1393 if ((route()->is_master() || route()->is_monitor()) &&
1394 !Config->get_allow_special_bus_removal()) {
1395 MessageDialog msg (_("That would be bad news ...."),
1399 msg.set_secondary_text (string_compose (_(
1400 "Removing the master or monitor bus is such a bad idea\n\
1401 that %1 is not going to allow it.\n\
1403 If you really want to do this sort of thing\n\
1404 edit your ardour.rc file to set the\n\
1405 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1412 vector<string> choices;
1416 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());
1418 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());
1421 choices.push_back (_("No, do nothing."));
1422 choices.push_back (_("Yes, remove it."));
1426 title = _("Remove track");
1428 title = _("Remove bus");
1431 Choice prompter (title, prompt, choices);
1433 if (prompter.run () == 1) {
1434 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1440 RouteUI::idle_remove_this_route (RouteUI *rui)
1442 rui->_session->remove_route (rui->route());
1446 /** @return true if this name should be used for the route, otherwise false */
1448 RouteUI::verify_new_route_name (const std::string& name)
1450 if (name.find (':') == string::npos) {
1454 MessageDialog colon_msg (
1455 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1456 false, MESSAGE_QUESTION, BUTTONS_NONE
1459 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1460 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1462 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1466 RouteUI::route_rename ()
1468 ArdourPrompter name_prompter (true);
1473 name_prompter.set_title (_("Rename Track"));
1475 name_prompter.set_title (_("Rename Bus"));
1477 name_prompter.set_prompt (_("New name:"));
1478 name_prompter.set_initial_text (_route->name());
1479 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1480 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1481 name_prompter.show_all ();
1484 switch (name_prompter.run ()) {
1485 case Gtk::RESPONSE_ACCEPT:
1486 name_prompter.get_result (result);
1487 name_prompter.hide ();
1488 if (result.length()) {
1489 if (verify_new_route_name (result)) {
1490 _route->set_name (result);
1493 /* back to name prompter */
1497 /* nothing entered, just get out of here */
1512 RouteUI::property_changed (const PropertyChange& what_changed)
1514 if (what_changed.contains (ARDOUR::Properties::name)) {
1515 name_label.set_text (_route->name());
1520 RouteUI::set_route_active (bool a, bool apply_to_selection)
1522 if (apply_to_selection) {
1523 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1525 _route->set_active (a, this);
1530 RouteUI::toggle_denormal_protection ()
1532 if (denormal_menu_item) {
1536 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1538 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1539 _route->set_denormal_protection (x);
1545 RouteUI::denormal_protection_changed ()
1547 if (denormal_menu_item) {
1548 denormal_menu_item->set_active (_route->denormal_protection());
1553 RouteUI::disconnect_input ()
1555 _route->input()->disconnect (this);
1559 RouteUI::disconnect_output ()
1561 _route->output()->disconnect (this);
1565 RouteUI::is_track () const
1567 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1570 boost::shared_ptr<Track>
1571 RouteUI::track() const
1573 return boost::dynamic_pointer_cast<Track>(_route);
1577 RouteUI::is_audio_track () const
1579 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1582 boost::shared_ptr<AudioTrack>
1583 RouteUI::audio_track() const
1585 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1589 RouteUI::is_midi_track () const
1591 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1594 boost::shared_ptr<MidiTrack>
1595 RouteUI::midi_track() const
1597 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1601 RouteUI::has_audio_outputs () const
1603 return (_route->n_outputs().n_audio() > 0);
1607 RouteUI::name() const
1609 return _route->name();
1613 RouteUI::map_frozen ()
1615 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1617 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1620 switch (at->freeze_state()) {
1621 case AudioTrack::Frozen:
1622 rec_enable_button->set_sensitive (false);
1625 rec_enable_button->set_sensitive (true);
1632 RouteUI::adjust_latency ()
1634 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1638 RouteUI::save_as_template ()
1641 std::string safe_name;
1644 path = ARDOUR::user_route_template_directory ();
1646 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1647 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1651 Prompter p (true); // modal
1653 p.set_title (_("Save As Template"));
1654 p.set_prompt (_("Template name:"));
1655 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1657 case RESPONSE_ACCEPT:
1664 p.get_result (name, true);
1666 safe_name = legalize_for_path (name);
1667 safe_name += template_suffix;
1669 path = Glib::build_filename (path, safe_name);
1671 _route->save_as_template (path, name);
1675 RouteUI::check_rec_enable_sensitivity ()
1677 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1678 rec_enable_button->set_sensitive (false);
1680 rec_enable_button->set_sensitive (true);
1683 update_monitoring_display ();
1687 RouteUI::parameter_changed (string const & p)
1689 /* this handles RC and per-session parameter changes */
1691 if (p == "disable-disarm-during-roll") {
1692 check_rec_enable_sensitivity ();
1693 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1694 set_button_names ();
1695 } else if (p == "auto-input") {
1696 update_monitoring_display ();
1701 RouteUI::step_gain_up ()
1703 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1707 RouteUI::page_gain_up ()
1709 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1713 RouteUI::step_gain_down ()
1715 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1719 RouteUI::page_gain_down ()
1721 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1725 RouteUI::open_remote_control_id_dialog ()
1727 ArdourDialog dialog (_("Remote Control ID"));
1728 SpinButton* spin = 0;
1730 dialog.get_vbox()->set_border_width (18);
1732 if (Config->get_remote_model() == UserOrdered) {
1733 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1735 HBox* hbox = manage (new HBox);
1736 hbox->set_spacing (6);
1737 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1738 spin = manage (new SpinButton);
1739 spin->set_digits (0);
1740 spin->set_increments (1, 10);
1741 spin->set_range (0, limit);
1742 spin->set_value (_route->remote_control_id());
1743 hbox->pack_start (*spin);
1744 dialog.get_vbox()->pack_start (*hbox);
1746 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1747 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1749 Label* l = manage (new Label());
1750 if (_route->is_master() || _route->is_monitor()) {
1751 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
1752 "The remote control ID of %3 cannot be changed."),
1753 Glib::Markup::escape_text (_route->name()),
1754 _route->remote_control_id(),
1755 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
1757 l->set_markup (string_compose (_("The remote control ID of %6 is: %3\n\n\n"
1758 "Remote Control IDs are currently determined by track/bus ordering in %1\n\n"
1759 "%4Use the User Interaction tab of the Preferences window if you want to change this%5"),
1760 (Config->get_remote_model() == MixerOrdered ? _("the mixer") : ("the editor")),
1761 (is_track() ? _("track") : _("bus")),
1762 _route->remote_control_id(),
1763 "<span size=\"small\" style=\"italic\">",
1765 Glib::Markup::escape_text (_route->name())));
1767 dialog.get_vbox()->pack_start (*l);
1768 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1772 int const r = dialog.run ();
1774 if (r == RESPONSE_ACCEPT && spin) {
1775 _route->set_remote_control_id (spin->get_value_as_int ());
1780 RouteUI::setup_invert_buttons ()
1782 /* remove old invert buttons */
1783 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1784 _invert_button_box.remove (**i);
1787 _invert_buttons.clear ();
1789 if (!_route || !_route->input()) {
1793 uint32_t const N = _route->input()->n_ports().n_audio ();
1795 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1797 for (uint32_t i = 0; i < to_add; ++i) {
1798 ArdourButton* b = manage (new ArdourButton);
1799 b->set_size_request(20,20);
1800 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1801 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
1803 b->set_name (X_("invert button"));
1806 b->set_text (string_compose (X_("Ø (%1)"), N));
1808 b->set_text (X_("Ø"));
1811 b->set_text (string_compose (X_("Ø%1"), i + 1));
1814 if (N <= _max_invert_buttons) {
1815 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));
1817 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
1820 _invert_buttons.push_back (b);
1821 _invert_button_box.pack_start (*b);
1824 _invert_button_box.set_spacing (1);
1825 _invert_button_box.show_all ();
1829 RouteUI::set_invert_button_state ()
1831 ++_i_am_the_modifier;
1833 uint32_t const N = _route->input()->n_ports().n_audio();
1834 if (N > _max_invert_buttons) {
1836 /* One button for many channels; explicit active if all channels are inverted,
1837 implicit active if some are, off if none are.
1840 ArdourButton* b = _invert_buttons.front ();
1842 if (_route->phase_invert().count() == _route->phase_invert().size()) {
1843 b->set_active_state (Gtkmm2ext::ExplicitActive);
1844 } else if (_route->phase_invert().any()) {
1845 b->set_active_state (Gtkmm2ext::ImplicitActive);
1847 b->set_active_state (Gtkmm2ext::Off);
1852 /* One button per channel; just set active */
1855 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1856 (*i)->set_active (_route->phase_invert (j));
1861 --_i_am_the_modifier;
1865 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
1867 if (ev->button == 1 && i < _invert_buttons.size()) {
1868 uint32_t const N = _route->input()->n_ports().n_audio ();
1869 if (N <= _max_invert_buttons) {
1870 /* left-click inverts phase so long as we have a button per channel */
1871 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
1880 RouteUI::invert_press (GdkEventButton* ev)
1882 using namespace Menu_Helpers;
1884 uint32_t const N = _route->input()->n_ports().n_audio();
1885 if (N <= _max_invert_buttons && ev->button != 3) {
1886 /* If we have an invert button per channel, we only pop
1887 up a menu on right-click; left click is handled
1893 delete _invert_menu;
1894 _invert_menu = new Menu;
1895 _invert_menu->set_name ("ArdourContextMenu");
1896 MenuList& items = _invert_menu->items ();
1898 for (uint32_t i = 0; i < N; ++i) {
1899 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1900 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1901 ++_i_am_the_modifier;
1902 e->set_active (_route->phase_invert (i));
1903 --_i_am_the_modifier;
1906 _invert_menu->popup (0, ev->time);
1912 RouteUI::invert_menu_toggled (uint32_t c)
1914 if (_i_am_the_modifier) {
1918 _route->set_phase_invert (c, !_route->phase_invert (c));
1922 RouteUI::set_invert_sensitive (bool yn)
1924 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1925 (*b)->set_sensitive (yn);
1930 RouteUI::request_redraw ()
1933 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1937 /** The Route's gui_changed signal has been emitted */
1939 RouteUI::route_gui_changed (string what_changed)
1941 if (what_changed == "color") {
1942 if (set_color_from_route () == 0) {
1943 route_color_changed ();
1948 /** @return the color that this route should use; it maybe its own,
1949 or it maybe that of its route group.
1952 RouteUI::color () const
1954 RouteGroup* g = _route->route_group ();
1956 if (g && g->is_color()) {
1957 return GroupTabs::group_color (g);
1964 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
1966 _showing_sends_to = send_to;
1967 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
1971 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1973 if (_route == send_to) {
1974 show_sends_button->set_active (true);
1975 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
1977 show_sends_button->set_active (false);
1978 send_blink_connection.disconnect ();
1983 RouteUI::route_group() const
1985 return _route->route_group();