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 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
125 show_sends_button = manage (new ArdourButton);
126 show_sends_button->set_name ("send alert button");
127 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
129 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
130 monitor_input_button->set_name ("monitor button");
131 monitor_input_button->set_text (_("In"));
132 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
133 monitor_input_button->set_no_show_all (true);
135 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
136 monitor_disk_button->set_name ("monitor button");
137 monitor_disk_button->set_text (_("Disk"));
138 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
139 monitor_disk_button->set_no_show_all (true);
141 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
142 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
143 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
145 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
146 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
148 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
149 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
151 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
152 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
154 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
155 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
156 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
157 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
159 monitor_input_button->set_distinct_led_click (false);
160 monitor_disk_button->set_distinct_led_click (false);
162 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
163 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
165 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
166 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
168 BusSendDisplayChanged.connect (sigc::mem_fun (*this, &RouteUI::bus_send_display_changed));
174 route_connections.drop_connections ();
182 denormal_menu_item = 0;
186 RouteUI::self_delete ()
192 RouteUI::set_route (boost::shared_ptr<Route> rp)
198 if (set_color_from_route()) {
199 set_color (unique_random_color());
203 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
206 mute_button->set_controllable (_route->mute_control());
207 solo_button->set_controllable (_route->solo_control());
209 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
210 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::mute_changed, this, _1), gui_context());
212 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
213 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
214 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
215 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
217 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
218 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
220 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
221 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
223 if (_session->writable() && is_track()) {
224 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
226 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
228 rec_enable_button->show();
229 rec_enable_button->set_controllable (t->rec_enable_control());
231 update_rec_display ();
233 if (is_midi_track()) {
234 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
235 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
241 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
242 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
244 update_monitoring_display ();
247 mute_button->unset_flags (Gtk::CAN_FOCUS);
248 solo_button->unset_flags (Gtk::CAN_FOCUS);
252 if (_route->is_monitor()) {
253 solo_button->hide ();
260 setup_invert_buttons ();
261 set_invert_button_state ();
263 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
264 bus_send_display_changed (s);
266 update_mute_display ();
267 update_solo_display ();
271 RouteUI::polarity_changed ()
277 set_invert_button_state ();
281 RouteUI::mute_press (GdkEventButton* ev)
283 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
287 multiple_mute_change = false;
289 if (!_i_am_the_modifier) {
291 if (Keyboard::is_context_menu_event (ev)) {
297 mute_menu->popup(0,ev->time);
301 if (Keyboard::is_button2_event (ev)) {
302 // Primary-button2 click is the midi binding click
303 // button2-click is "momentary"
306 if (mute_button->on_button_press_event (ev)) {
310 _mute_release = new SoloMuteRelease (_route->muted ());
313 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
315 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
318 _mute_release->routes = _session->get_routes ();
321 _session->set_mute (_session->get_routes(), !_route->muted());
323 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
325 /* Primary-button1 applies change to the mix group even if it is not active
326 NOTE: Primary-button2 is MIDI learn.
329 if (ev->button == 1 && _route->route_group()) {
331 _mute_release->routes = _session->get_routes ();
334 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
339 /* plain click applies change to this route */
341 boost::shared_ptr<RouteList> rl (new RouteList);
342 rl->push_back (_route);
345 _mute_release->routes = rl;
348 _session->set_mute (rl, !_route->muted());
360 RouteUI::mute_release (GdkEventButton*)
362 if (!_i_am_the_modifier) {
364 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
365 delete _mute_release;
374 RouteUI::solo_press(GdkEventButton* ev)
376 /* ignore double/triple clicks */
378 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
382 multiple_solo_change = false;
384 if (!_i_am_the_modifier) {
386 if (Keyboard::is_context_menu_event (ev)) {
388 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
389 ! (solo_safe_led && solo_safe_led->is_visible())) {
391 if (solo_menu == 0) {
395 solo_menu->popup (1, ev->time);
400 if (Keyboard::is_button2_event (ev)) {
402 // Primary-button2 click is the midi binding click
403 // button2-click is "momentary"
405 if (solo_button->on_button_press_event (ev)) {
409 _solo_release = new SoloMuteRelease (_route->self_soloed());
412 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
414 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
416 /* Primary-Tertiary-click applies change to all routes */
419 _solo_release->routes = _session->get_routes ();
422 if (Config->get_solo_control_is_listen_control()) {
423 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
425 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
428 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
430 // Primary-Secondary-click: exclusively solo this track
433 _solo_release->exclusive = true;
435 boost::shared_ptr<RouteList> routes = _session->get_routes();
437 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
438 if ((*i)->soloed ()) {
439 _solo_release->routes_on->push_back (*i);
441 _solo_release->routes_off->push_back (*i);
446 if (Config->get_solo_control_is_listen_control()) {
447 /* ??? we need a just_one_listen() method */
449 _session->set_just_one_solo (_route, true);
452 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
454 // shift-click: toggle solo isolated status
456 _route->set_solo_isolated (!_route->solo_isolated(), this);
457 delete _solo_release;
460 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
462 /* Primary-button1: solo mix group.
463 NOTE: Primary-button2 is MIDI learn.
466 if (ev->button == 1 && _route->route_group()) {
469 _solo_release->routes = _route->route_group()->route_list();
472 if (Config->get_solo_control_is_listen_control()) {
473 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
475 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
481 /* click: solo this route */
483 boost::shared_ptr<RouteList> rl (new RouteList);
484 rl->push_back (route());
487 _solo_release->routes = rl;
490 if (Config->get_solo_control_is_listen_control()) {
491 _session->set_listen (rl, !_route->listening_via_monitor());
493 _session->set_solo (rl, !_route->self_soloed());
504 RouteUI::solo_release (GdkEventButton*)
506 if (!_i_am_the_modifier) {
510 if (_solo_release->exclusive) {
513 if (Config->get_solo_control_is_listen_control()) {
514 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
516 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
520 delete _solo_release;
529 RouteUI::rec_enable_press(GdkEventButton* ev)
531 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
535 if (!_session->engine().connected()) {
536 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
541 if (is_midi_track()) {
543 /* rec-enable button exits from step editing */
545 if (midi_track()->step_editing()) {
546 midi_track()->set_step_editing (false);
551 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
553 if (Keyboard::is_button2_event (ev)) {
555 // do nothing on midi sigc::bind event
556 return rec_enable_button->on_button_press_event (ev);
558 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
560 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
562 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
564 /* Primary-button1 applies change to the route group (even if it is not active)
565 NOTE: Primary-button2 is MIDI learn.
567 if (ev->button == 1 && _route->route_group()) {
568 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->active_state(), Session::rt_cleanup, true);
571 } else if (Keyboard::is_context_menu_event (ev)) {
573 /* do this on release */
577 boost::shared_ptr<RouteList> rl (new RouteList);
578 rl->push_back (route());
579 _session->set_record_enabled (rl, !rec_enable_button->active_state());
587 RouteUI::monitoring_changed ()
589 update_monitoring_display ();
593 RouteUI::update_monitoring_display ()
599 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
605 MonitorState ms = t->monitoring_state();
607 if (t->monitoring_choice() & MonitorInput) {
608 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
610 if (ms & MonitoringInput) {
611 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
613 monitor_input_button->unset_active_state ();
617 if (t->monitoring_choice() & MonitorDisk) {
618 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
620 if (ms & MonitoringDisk) {
621 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
623 monitor_disk_button->unset_active_state ();
629 RouteUI::monitor_input_press(GdkEventButton*)
635 RouteUI::monitor_input_release(GdkEventButton* ev)
637 return monitor_release (ev, MonitorInput);
641 RouteUI::monitor_disk_press (GdkEventButton*)
647 RouteUI::monitor_disk_release (GdkEventButton* ev)
649 return monitor_release (ev, MonitorDisk);
653 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
655 if (ev->button != 1) {
659 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
666 boost::shared_ptr<RouteList> rl;
668 /* XXX for now, monitoring choices are orthogonal. cue monitoring
669 will follow in 3.X but requires mixing the input and playback (disk)
670 signal together, which requires yet more buffers.
673 if (t->monitoring_choice() & monitor_choice) {
674 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
676 /* this line will change when the options are non-orthogonal */
677 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
681 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
682 rl = _session->get_routes ();
684 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
685 if (_route->route_group() && _route->route_group()->is_monitoring()) {
686 rl = _route->route_group()->route_list();
688 rl.reset (new RouteList);
689 rl->push_back (route());
692 rl.reset (new RouteList);
693 rl->push_back (route());
696 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
702 RouteUI::build_record_menu ()
708 /* no rec-button context menu for non-MIDI tracks
711 if (is_midi_track()) {
712 record_menu = new Menu;
713 record_menu->set_name ("ArdourContextMenu");
715 using namespace Menu_Helpers;
716 MenuList& items = record_menu->items();
718 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
719 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
721 if (_route->record_enabled()) {
722 step_edit_item->set_sensitive (false);
725 step_edit_item->set_active (midi_track()->step_editing());
730 RouteUI::toggle_step_edit ()
732 if (!is_midi_track() || _route->record_enabled()) {
736 midi_track()->set_step_editing (step_edit_item->get_active());
740 RouteUI::step_edit_changed (bool yn)
743 if (rec_enable_button) {
744 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
747 start_step_editing ();
749 if (step_edit_item) {
750 step_edit_item->set_active (true);
755 if (rec_enable_button) {
756 rec_enable_button->unset_active_state ();
759 stop_step_editing ();
761 if (step_edit_item) {
762 step_edit_item->set_active (false);
768 RouteUI::rec_enable_release (GdkEventButton* ev)
770 if (Keyboard::is_context_menu_event (ev)) {
771 build_record_menu ();
773 record_menu->popup (1, ev->time);
782 RouteUI::build_sends_menu ()
784 using namespace Menu_Helpers;
786 sends_menu = new Menu;
787 sends_menu->set_name ("ArdourContextMenu");
788 MenuList& items = sends_menu->items();
791 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
795 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
799 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
803 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
807 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
811 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
814 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
818 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
821 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
822 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
823 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
828 RouteUI::create_sends (Placement p, bool include_buses)
830 _session->globally_add_internal_sends (_route, p, include_buses);
834 RouteUI::create_selected_sends (Placement p, bool include_buses)
836 boost::shared_ptr<RouteList> rlist (new RouteList);
837 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
839 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
840 RouteTimeAxisView* rtv;
842 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
843 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
844 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
845 rlist->push_back (rui->route());
851 _session->add_internal_sends (_route, p, rlist);
855 RouteUI::set_sends_gain_from_track ()
857 _session->globally_set_send_gains_from_track (_route);
861 RouteUI::set_sends_gain_to_zero ()
863 _session->globally_set_send_gains_to_zero (_route);
867 RouteUI::set_sends_gain_to_unity ()
869 _session->globally_set_send_gains_to_unity (_route);
873 RouteUI::show_sends_press(GdkEventButton* ev)
875 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
879 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
881 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
883 // do nothing on midi sigc::bind event
886 } else if (Keyboard::is_context_menu_event (ev)) {
888 if (sends_menu == 0) {
892 sends_menu->popup (0, ev->time);
896 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
899 set_showing_sends_to (boost::shared_ptr<Route> ());
901 set_showing_sends_to (_route);
910 RouteUI::show_sends_release (GdkEventButton*)
916 RouteUI::send_blink (bool onoff)
918 if (!show_sends_button) {
923 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
925 show_sends_button->unset_active_state ();
929 Gtkmm2ext::ActiveState
930 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
932 if (r->is_master() || r->is_monitor()) {
933 return Gtkmm2ext::Off;
936 if (Config->get_solo_control_is_listen_control()) {
938 if (r->listening_via_monitor()) {
939 return Gtkmm2ext::ExplicitActive;
941 return Gtkmm2ext::Off;
947 if (!r->self_soloed()) {
948 return Gtkmm2ext::ImplicitActive;
950 return Gtkmm2ext::ExplicitActive;
953 return Gtkmm2ext::Off;
957 Gtkmm2ext::ActiveState
958 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
960 if (r->is_master() || r->is_monitor()) {
961 return Gtkmm2ext::Off;
964 if (r->solo_isolated()) {
965 return Gtkmm2ext::ExplicitActive;
967 return Gtkmm2ext::Off;
971 Gtkmm2ext::ActiveState
972 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
974 if (r->is_master() || r->is_monitor()) {
975 return Gtkmm2ext::Off;
978 if (r->solo_safe()) {
979 return Gtkmm2ext::ExplicitActive;
981 return Gtkmm2ext::Off;
986 RouteUI::update_solo_display ()
988 bool yn = _route->solo_safe ();
990 if (solo_safe_check && solo_safe_check->get_active() != yn) {
991 solo_safe_check->set_active (yn);
994 yn = _route->solo_isolated ();
996 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
997 solo_isolated_check->set_active (yn);
1000 set_button_names ();
1002 if (solo_isolated_led) {
1003 if (_route->solo_isolated()) {
1004 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1006 solo_isolated_led->unset_active_state ();
1010 if (solo_safe_led) {
1011 if (_route->solo_safe()) {
1012 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1014 solo_safe_led->unset_active_state ();
1018 solo_button->set_active_state (solo_active_state (_route));
1020 /* some changes to solo status can affect mute display, so catch up
1023 update_mute_display ();
1027 RouteUI::solo_changed_so_update_mute ()
1029 update_mute_display ();
1033 RouteUI::mute_changed(void* /*src*/)
1035 update_mute_display ();
1039 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1041 if (r->is_monitor()) {
1042 return ActiveState(0);
1046 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1050 return Gtkmm2ext::ExplicitActive;
1051 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1052 /* master is NEVER muted by others */
1053 return Gtkmm2ext::ImplicitActive;
1055 /* no mute at all */
1056 return Gtkmm2ext::Off;
1063 return Gtkmm2ext::ExplicitActive;
1065 /* no mute at all */
1066 return Gtkmm2ext::Off;
1070 return ActiveState(0);
1074 RouteUI::update_mute_display ()
1080 mute_button->set_active_state (mute_active_state (_session, _route));
1084 RouteUI::route_rec_enable_changed ()
1086 update_rec_display ();
1087 update_monitoring_display ();
1091 RouteUI::session_rec_enable_changed ()
1093 update_rec_display ();
1094 update_monitoring_display ();
1098 RouteUI::update_rec_display ()
1100 if (!rec_enable_button || !_route) {
1104 if (_route->record_enabled()) {
1105 switch (_session->record_status ()) {
1106 case Session::Recording:
1107 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1110 case Session::Disabled:
1111 case Session::Enabled:
1112 rec_enable_button->set_active_state (Gtkmm2ext::ImplicitActive);
1117 if (step_edit_item) {
1118 step_edit_item->set_sensitive (false);
1122 rec_enable_button->unset_active_state ();
1124 if (step_edit_item) {
1125 step_edit_item->set_sensitive (true);
1130 check_rec_enable_sensitivity ();
1134 RouteUI::build_solo_menu (void)
1136 using namespace Menu_Helpers;
1138 solo_menu = new Menu;
1139 solo_menu->set_name ("ArdourContextMenu");
1140 MenuList& items = solo_menu->items();
1141 CheckMenuItem* check;
1143 check = new CheckMenuItem(_("Solo Isolate"));
1144 check->set_active (_route->solo_isolated());
1145 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1146 items.push_back (CheckMenuElem(*check));
1147 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1150 check = new CheckMenuItem(_("Solo Safe"));
1151 check->set_active (_route->solo_safe());
1152 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1153 items.push_back (CheckMenuElem(*check));
1154 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1157 //items.push_back (SeparatorElem());
1158 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1163 RouteUI::build_mute_menu(void)
1165 using namespace Menu_Helpers;
1167 mute_menu = new Menu;
1168 mute_menu->set_name ("ArdourContextMenu");
1170 MenuList& items = mute_menu->items();
1172 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1173 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1174 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1175 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1176 pre_fader_mute_check->show_all();
1178 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1179 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1180 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1181 items.push_back (CheckMenuElem(*post_fader_mute_check));
1182 post_fader_mute_check->show_all();
1184 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1185 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1186 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1187 items.push_back (CheckMenuElem(*listen_mute_check));
1188 listen_mute_check->show_all();
1190 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1191 init_mute_menu(MuteMaster::Main, main_mute_check);
1192 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1193 items.push_back (CheckMenuElem(*main_mute_check));
1194 main_mute_check->show_all();
1196 //items.push_back (SeparatorElem());
1197 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1199 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1203 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1205 check->set_active (_route->mute_points() & mp);
1209 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1211 if (check->get_active()) {
1212 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1214 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1219 RouteUI::muting_change ()
1221 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1224 MuteMaster::MutePoint current = _route->mute_points ();
1226 yn = (current & MuteMaster::PreFader);
1228 if (pre_fader_mute_check->get_active() != yn) {
1229 pre_fader_mute_check->set_active (yn);
1232 yn = (current & MuteMaster::PostFader);
1234 if (post_fader_mute_check->get_active() != yn) {
1235 post_fader_mute_check->set_active (yn);
1238 yn = (current & MuteMaster::Listen);
1240 if (listen_mute_check->get_active() != yn) {
1241 listen_mute_check->set_active (yn);
1244 yn = (current & MuteMaster::Main);
1246 if (main_mute_check->get_active() != yn) {
1247 main_mute_check->set_active (yn);
1252 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1254 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1258 bool view = solo_isolated_led->active_state();
1259 bool model = _route->solo_isolated();
1261 /* called BEFORE the view has changed */
1263 if (ev->button == 1) {
1264 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1267 /* disable isolate for all routes */
1268 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1272 if (model == view) {
1274 /* flip just this route */
1276 boost::shared_ptr<RouteList> rl (new RouteList);
1277 rl->push_back (_route);
1278 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1287 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1289 if (ev->button == 1) {
1290 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1297 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1299 bool view = check->get_active();
1300 bool model = _route->solo_isolated();
1302 /* called AFTER the view has changed */
1304 if (model != view) {
1305 _route->set_solo_isolated (view, this);
1310 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1312 _route->set_solo_safe (check->get_active(), this);
1315 /** Ask the user to choose a colour, and then set all selected tracks
1319 RouteUI::choose_color ()
1322 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1325 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1326 boost::bind (&RouteUI::set_color, _1, color)
1331 /** Set the route's own color. This may not be used for display if
1332 * the route is in a group which shares its color with its routes.
1335 RouteUI::set_color (const Gdk::Color & c)
1341 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1343 /* note: we use the route state ID here so that color is the same for both
1344 the time axis view and the mixer strip
1347 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1348 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1351 /** @return GUI state ID for things that are common to the route in all its representations */
1353 RouteUI::route_state_id () const
1355 return string_compose (X_("route %1"), _route->id().to_s());
1359 RouteUI::set_color_from_route ()
1361 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1369 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1372 _color.set_green (g);
1373 _color.set_blue (b);
1379 RouteUI::remove_this_route (bool apply_to_selection)
1381 if (apply_to_selection) {
1382 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1384 if ((route()->is_master() || route()->is_monitor()) &&
1385 !Config->get_allow_special_bus_removal()) {
1386 MessageDialog msg (_("That would be bad news ...."),
1390 msg.set_secondary_text (string_compose (_(
1391 "Removing the master or monitor bus is such a bad idea\n\
1392 that %1 is not going to allow it.\n\
1394 If you really want to do this sort of thing\n\
1395 edit your ardour.rc file to set the\n\
1396 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1403 vector<string> choices;
1407 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());
1409 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());
1412 choices.push_back (_("No, do nothing."));
1413 choices.push_back (_("Yes, remove it."));
1417 title = _("Remove track");
1419 title = _("Remove bus");
1422 Choice prompter (title, prompt, choices);
1424 if (prompter.run () == 1) {
1425 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1431 RouteUI::idle_remove_this_route (RouteUI *rui)
1433 rui->_session->remove_route (rui->route());
1437 /** @return true if this name should be used for the route, otherwise false */
1439 RouteUI::verify_new_route_name (const std::string& name)
1441 if (name.find (':') == string::npos) {
1445 MessageDialog colon_msg (
1446 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1447 false, MESSAGE_QUESTION, BUTTONS_NONE
1450 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1451 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1453 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1457 RouteUI::route_rename ()
1459 ArdourPrompter name_prompter (true);
1464 name_prompter.set_title (_("Rename Track"));
1466 name_prompter.set_title (_("Rename Bus"));
1468 name_prompter.set_prompt (_("New name:"));
1469 name_prompter.set_initial_text (_route->name());
1470 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1471 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1472 name_prompter.show_all ();
1475 switch (name_prompter.run ()) {
1476 case Gtk::RESPONSE_ACCEPT:
1477 name_prompter.get_result (result);
1478 name_prompter.hide ();
1479 if (result.length()) {
1480 if (verify_new_route_name (result)) {
1481 _route->set_name (result);
1484 /* back to name prompter */
1488 /* nothing entered, just get out of here */
1503 RouteUI::property_changed (const PropertyChange& what_changed)
1505 if (what_changed.contains (ARDOUR::Properties::name)) {
1506 name_label.set_text (_route->name());
1511 RouteUI::set_route_active (bool a, bool apply_to_selection)
1513 if (apply_to_selection) {
1514 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1516 _route->set_active (a, this);
1521 RouteUI::toggle_denormal_protection ()
1523 if (denormal_menu_item) {
1527 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1529 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1530 _route->set_denormal_protection (x);
1536 RouteUI::denormal_protection_changed ()
1538 if (denormal_menu_item) {
1539 denormal_menu_item->set_active (_route->denormal_protection());
1544 RouteUI::disconnect_input ()
1546 _route->input()->disconnect (this);
1550 RouteUI::disconnect_output ()
1552 _route->output()->disconnect (this);
1556 RouteUI::is_track () const
1558 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1561 boost::shared_ptr<Track>
1562 RouteUI::track() const
1564 return boost::dynamic_pointer_cast<Track>(_route);
1568 RouteUI::is_audio_track () const
1570 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1573 boost::shared_ptr<AudioTrack>
1574 RouteUI::audio_track() const
1576 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1580 RouteUI::is_midi_track () const
1582 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1585 boost::shared_ptr<MidiTrack>
1586 RouteUI::midi_track() const
1588 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1592 RouteUI::has_audio_outputs () const
1594 return (_route->n_outputs().n_audio() > 0);
1598 RouteUI::name() const
1600 return _route->name();
1604 RouteUI::map_frozen ()
1606 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1608 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1611 switch (at->freeze_state()) {
1612 case AudioTrack::Frozen:
1613 rec_enable_button->set_sensitive (false);
1616 rec_enable_button->set_sensitive (true);
1623 RouteUI::adjust_latency ()
1625 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1629 RouteUI::save_as_template ()
1632 std::string safe_name;
1635 path = ARDOUR::user_route_template_directory ();
1637 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1638 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1642 Prompter p (true); // modal
1644 p.set_title (_("Save As Template"));
1645 p.set_prompt (_("Template name:"));
1646 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1648 case RESPONSE_ACCEPT:
1655 p.get_result (name, true);
1657 safe_name = legalize_for_path (name);
1658 safe_name += template_suffix;
1660 path = Glib::build_filename (path, safe_name);
1662 _route->save_as_template (path, name);
1666 RouteUI::check_rec_enable_sensitivity ()
1668 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1669 rec_enable_button->set_sensitive (false);
1671 rec_enable_button->set_sensitive (true);
1674 update_monitoring_display ();
1678 RouteUI::parameter_changed (string const & p)
1680 /* this handles RC and per-session parameter changes */
1682 if (p == "disable-disarm-during-roll") {
1683 check_rec_enable_sensitivity ();
1684 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1685 set_button_names ();
1686 } else if (p == "auto-input") {
1687 update_monitoring_display ();
1692 RouteUI::step_gain_up ()
1694 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1698 RouteUI::page_gain_up ()
1700 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1704 RouteUI::step_gain_down ()
1706 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1710 RouteUI::page_gain_down ()
1712 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1716 RouteUI::open_remote_control_id_dialog ()
1718 ArdourDialog dialog (_("Remote Control ID"));
1719 SpinButton* spin = 0;
1721 dialog.get_vbox()->set_border_width (18);
1723 if (Config->get_remote_model() == UserOrdered) {
1724 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1726 HBox* hbox = manage (new HBox);
1727 hbox->set_spacing (6);
1728 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1729 spin = manage (new SpinButton);
1730 spin->set_digits (0);
1731 spin->set_increments (1, 10);
1732 spin->set_range (0, limit);
1733 spin->set_value (_route->remote_control_id());
1734 hbox->pack_start (*spin);
1735 dialog.get_vbox()->pack_start (*hbox);
1737 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1738 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1740 Label* l = manage (new Label());
1741 l->set_markup (string_compose (_("Remote Control IDs are currently determined by track/bus ordering in %1\n\n"
1742 "This %2 has remote control ID %3\n\n\n"
1743 "<span size=\"small\" style=\"italic\">Use the User Interaction tab of the Preferences window if you want to change this</span>"),
1744 (Config->get_remote_model() == MixerOrdered ? _("the mixer") : ("the editor")),
1745 (is_track() ? _("track") : _("bus")),
1746 _route->remote_control_id()));
1747 dialog.get_vbox()->pack_start (*l);
1748 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1752 int const r = dialog.run ();
1754 if (r == RESPONSE_ACCEPT && spin) {
1755 _route->set_remote_control_id (spin->get_value_as_int ());
1760 RouteUI::setup_invert_buttons ()
1762 /* remove old invert buttons */
1763 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1764 _invert_button_box.remove (**i);
1767 _invert_buttons.clear ();
1769 if (!_route || !_route->input()) {
1773 uint32_t const N = _route->input()->n_ports().n_audio ();
1775 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1777 for (uint32_t i = 0; i < to_add; ++i) {
1778 ArdourButton* b = manage (new ArdourButton);
1779 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1780 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
1782 b->set_name (X_("mixer strip button"));
1785 b->set_text (string_compose (X_("Ø (%1)"), N));
1787 b->set_text (X_("Ø"));
1790 b->set_text (string_compose (X_("Ø%1"), i + 1));
1793 if (N <= _max_invert_buttons) {
1794 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));
1796 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
1799 _invert_buttons.push_back (b);
1800 _invert_button_box.pack_start (*b);
1803 _invert_button_box.set_spacing (1);
1804 _invert_button_box.show_all ();
1808 RouteUI::set_invert_button_state ()
1810 ++_i_am_the_modifier;
1812 uint32_t const N = _route->input()->n_ports().n_audio();
1813 if (N > _max_invert_buttons) {
1815 /* One button for many channels; explicit active if all channels are inverted,
1816 implicit active if some are, off if none are.
1819 ArdourButton* b = _invert_buttons.front ();
1821 if (_route->phase_invert().count() == _route->phase_invert().size()) {
1822 b->set_active_state (Gtkmm2ext::ExplicitActive);
1823 } else if (_route->phase_invert().any()) {
1824 b->set_active_state (Gtkmm2ext::ImplicitActive);
1826 b->set_active_state (Gtkmm2ext::Off);
1831 /* One button per channel; just set active */
1834 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1835 (*i)->set_active (_route->phase_invert (j));
1840 --_i_am_the_modifier;
1844 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
1846 if (ev->button == 1 && i < _invert_buttons.size()) {
1847 uint32_t const N = _route->input()->n_ports().n_audio ();
1848 if (N <= _max_invert_buttons) {
1849 /* left-click inverts phase so long as we have a button per channel */
1850 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
1859 RouteUI::invert_press (GdkEventButton* ev)
1861 using namespace Menu_Helpers;
1863 uint32_t const N = _route->input()->n_ports().n_audio();
1864 if (N <= _max_invert_buttons && ev->button != 3) {
1865 /* If we have an invert button per channel, we only pop
1866 up a menu on right-click; left click is handled
1872 delete _invert_menu;
1873 _invert_menu = new Menu;
1874 _invert_menu->set_name ("ArdourContextMenu");
1875 MenuList& items = _invert_menu->items ();
1877 for (uint32_t i = 0; i < N; ++i) {
1878 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1879 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1880 ++_i_am_the_modifier;
1881 e->set_active (_route->phase_invert (i));
1882 --_i_am_the_modifier;
1885 _invert_menu->popup (0, ev->time);
1891 RouteUI::invert_menu_toggled (uint32_t c)
1893 if (_i_am_the_modifier) {
1897 _route->set_phase_invert (c, !_route->phase_invert (c));
1901 RouteUI::set_invert_sensitive (bool yn)
1903 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1904 (*b)->set_sensitive (yn);
1909 RouteUI::request_redraw ()
1912 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1916 /** The Route's gui_changed signal has been emitted */
1918 RouteUI::route_gui_changed (string what_changed)
1920 if (what_changed == "color") {
1921 if (set_color_from_route () == 0) {
1922 route_color_changed ();
1927 /** @return the color that this route should use; it maybe its own,
1928 or it maybe that of its route group.
1931 RouteUI::color () const
1933 RouteGroup* g = _route->route_group ();
1935 if (g && g->is_color()) {
1936 return GroupTabs::group_color (g);
1943 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
1945 _showing_sends_to = send_to;
1946 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
1950 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1952 if (_route == send_to) {
1953 show_sends_button->set_active (true);
1954 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
1956 show_sends_button->set_active (false);
1957 send_blink_connection.disconnect ();
1962 RouteUI::route_group() const
1964 return _route->route_group();