2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/choice.h>
22 #include <gtkmm2ext/doi.h>
23 #include <gtkmm2ext/bindable_button.h>
24 #include <gtkmm2ext/barcontroller.h>
25 #include <gtkmm2ext/gtk_ui.h>
27 #include "ardour/route_group.h"
28 #include "ardour/dB.h"
29 #include "pbd/memento_command.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/controllable.h"
32 #include "pbd/enumwriter.h"
34 #include "ardour_ui.h"
37 #include "ardour_button.h"
41 #include "gui_thread.h"
42 #include "ardour_dialog.h"
43 #include "latency_gui.h"
44 #include "mixer_strip.h"
45 #include "automation_time_axis.h"
46 #include "route_time_axis.h"
47 #include "group_tabs.h"
49 #include "ardour/route.h"
50 #include "ardour/event_type_map.h"
51 #include "ardour/session.h"
52 #include "ardour/audioengine.h"
53 #include "ardour/audio_track.h"
54 #include "ardour/midi_track.h"
55 #include "ardour/template_utils.h"
56 #include "ardour/filename_extensions.h"
57 #include "ardour/directory_names.h"
58 #include "ardour/profile.h"
62 using namespace Gtkmm2ext;
63 using namespace ARDOUR;
66 uint32_t RouteUI::_max_invert_buttons = 3;
68 RouteUI::RouteUI (ARDOUR::Session* sess)
76 _route.reset (); /* drop reference to route, so that it can be cleaned up */
77 route_connections.drop_connections ();
84 delete solo_safe_image;
96 pre_fader_mute_check = 0;
97 post_fader_mute_check = 0;
98 listen_mute_check = 0;
101 solo_isolated_check = 0;
102 solo_isolated_led = 0;
106 denormal_menu_item = 0;
108 multiple_mute_change = false;
109 multiple_solo_change = false;
110 _i_am_the_modifier = 0;
113 setup_invert_buttons ();
115 mute_button = manage (new BindableToggleButton ());
116 // mute_button->set_self_managed (true);
117 mute_button->set_name ("MuteButton");
118 mute_button->add (mute_button_label);
119 mute_button_label.show ();
120 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
122 solo_button = manage (new BindableToggleButton ());
123 // solo_button->set_self_managed (true);
124 solo_button->set_name ("SoloButton");
125 solo_button->add (solo_button_label);
126 solo_button_label.show ();
127 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
128 solo_button->set_no_show_all (true);
130 rec_enable_button = manage (new BindableToggleButton ());
131 rec_enable_button->set_name ("RecordEnableButton");
132 // rec_enable_button->set_self_managed (true);
133 rec_enable_button->add (rec_enable_button_label);
134 rec_enable_button_label.show ();
135 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
137 show_sends_button = manage (new BindableToggleButton (""));
138 show_sends_button->set_name ("SendAlert");
139 // show_sends_button->set_self_managed (true);
140 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
142 monitor_input_button = manage (new ArdourButton (ArdourButton::led_default_elements));
143 monitor_input_button->set_name ("monitor");
144 monitor_input_button->set_text (_("In"));
145 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
146 monitor_input_button->set_no_show_all (true);
148 monitor_disk_button = manage (new ArdourButton (ArdourButton::led_default_elements));
149 monitor_disk_button->set_name ("monitor");
150 monitor_disk_button->set_text (_("Disk"));
151 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
152 monitor_disk_button->set_no_show_all (true);
154 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
155 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
156 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
158 _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
159 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
161 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
162 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
164 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
165 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
167 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
168 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
169 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
170 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
172 monitor_input_button->set_distinct_led_click (false);
173 monitor_disk_button->set_distinct_led_click (false);
175 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
176 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
178 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
179 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
185 route_connections.drop_connections ();
193 denormal_menu_item = 0;
197 RouteUI::self_delete ()
203 RouteUI::set_route (boost::shared_ptr<Route> rp)
209 if (set_color_from_route()) {
210 set_color (unique_random_color());
214 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
217 mute_button->set_controllable (_route->mute_control());
218 solo_button->set_controllable (_route->solo_control());
220 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
221 _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
223 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
224 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
225 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
226 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
228 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
229 _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
231 _route->io_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::setup_invert_buttons, this), gui_context ());
232 _route->gui_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
234 if (_session->writable() && is_track()) {
235 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
237 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
239 rec_enable_button->show();
240 rec_enable_button->set_controllable (t->rec_enable_control());
242 update_rec_display ();
244 if (is_midi_track()) {
245 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
246 ui_bind (&RouteUI::step_edit_changed, this, _1), gui_context());
252 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
253 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
255 update_monitoring_display ();
258 mute_button->unset_flags (Gtk::CAN_FOCUS);
259 solo_button->unset_flags (Gtk::CAN_FOCUS);
263 if (_route->is_monitor()) {
264 solo_button->hide ();
271 setup_invert_buttons ();
272 set_invert_button_state ();
276 RouteUI::polarity_changed ()
282 set_invert_button_state ();
286 RouteUI::mute_press (GdkEventButton* ev)
288 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
292 multiple_mute_change = false;
294 if (!_i_am_the_modifier) {
296 if (Keyboard::is_context_menu_event (ev)) {
302 mute_menu->popup(0,ev->time);
306 if (Keyboard::is_button2_event (ev)) {
307 // Primary-button2 click is the midi binding click
308 // button2-click is "momentary"
311 if (mute_button->on_button_press_event (ev)) {
315 _mute_release = new SoloMuteRelease (_route->muted ());
318 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
320 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
323 _mute_release->routes = _session->get_routes ();
326 _session->set_mute (_session->get_routes(), !_route->muted());
328 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
330 /* Primary-button1 applies change to the mix group even if it is not active
331 NOTE: Primary-button2 is MIDI learn.
334 if (ev->button == 1 && _route->route_group()) {
336 _mute_release->routes = _session->get_routes ();
339 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
344 /* plain click applies change to this route */
346 boost::shared_ptr<RouteList> rl (new RouteList);
347 rl->push_back (_route);
350 _mute_release->routes = rl;
353 _session->set_mute (rl, !_route->muted());
365 RouteUI::mute_release (GdkEventButton*)
367 if (!_i_am_the_modifier) {
369 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
370 delete _mute_release;
379 RouteUI::solo_press(GdkEventButton* ev)
381 /* ignore double/triple clicks */
383 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
387 multiple_solo_change = false;
389 if (!_i_am_the_modifier) {
391 if (Keyboard::is_context_menu_event (ev)) {
393 if (!solo_isolated_led) {
395 if (solo_menu == 0) {
399 solo_menu->popup (1, ev->time);
404 if (Keyboard::is_button2_event (ev)) {
406 // Primary-button2 click is the midi binding click
407 // button2-click is "momentary"
409 if (solo_button->on_button_press_event (ev)) {
413 _solo_release = new SoloMuteRelease (_route->self_soloed());
416 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
418 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
420 /* Primary-Tertiary-click applies change to all routes */
423 _solo_release->routes = _session->get_routes ();
426 if (Config->get_solo_control_is_listen_control()) {
427 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
429 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
432 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
434 // Primary-Secondary-click: exclusively solo this track
437 _solo_release->exclusive = true;
439 boost::shared_ptr<RouteList> routes = _session->get_routes();
441 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
442 if ((*i)->soloed ()) {
443 _solo_release->routes_on->push_back (*i);
445 _solo_release->routes_off->push_back (*i);
450 if (Config->get_solo_control_is_listen_control()) {
451 /* ??? we need a just_one_listen() method */
453 _session->set_just_one_solo (_route, true);
456 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
458 // shift-click: toggle solo isolated status
460 _route->set_solo_isolated (!_route->solo_isolated(), this);
461 delete _solo_release;
464 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
466 /* Primary-button1: solo mix group.
467 NOTE: Primary-button2 is MIDI learn.
470 if (ev->button == 1 && _route->route_group()) {
473 _solo_release->routes = _route->route_group()->route_list();
476 if (Config->get_solo_control_is_listen_control()) {
477 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
479 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
485 /* click: solo this route */
487 boost::shared_ptr<RouteList> rl (new RouteList);
488 rl->push_back (route());
491 _solo_release->routes = rl;
494 if (Config->get_solo_control_is_listen_control()) {
495 _session->set_listen (rl, !_route->listening_via_monitor());
497 _session->set_solo (rl, !_route->self_soloed());
508 RouteUI::solo_release (GdkEventButton*)
510 if (!_i_am_the_modifier) {
514 if (_solo_release->exclusive) {
517 if (Config->get_solo_control_is_listen_control()) {
518 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
520 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
524 delete _solo_release;
533 RouteUI::rec_enable_press(GdkEventButton* ev)
535 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
539 if (!_session->engine().connected()) {
540 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
545 if (is_midi_track()) {
547 /* cannot rec-enable while step-editing */
549 if (midi_track()->step_editing()) {
554 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
556 if (Keyboard::is_button2_event (ev)) {
558 // do nothing on midi sigc::bind event
559 return rec_enable_button->on_button_press_event (ev);
561 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
563 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->get_active());
565 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
567 /* Primary-button1 applies change to the route group (even if it is not active)
568 NOTE: Primary-button2 is MIDI learn.
570 if (ev->button == 1 && _route->route_group()) {
571 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->get_active(), Session::rt_cleanup, true);
574 } else if (Keyboard::is_context_menu_event (ev)) {
576 /* do this on release */
580 boost::shared_ptr<RouteList> rl (new RouteList);
581 rl->push_back (route());
582 _session->set_record_enabled (rl, !rec_enable_button->get_active());
590 RouteUI::monitoring_changed ()
592 update_monitoring_display ();
596 RouteUI::update_monitoring_display ()
602 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
608 MonitorState ms = t->monitoring_state();
610 if (t->monitoring_choice() & MonitorInput) {
611 monitor_input_button->set_active_state (CairoWidget::Active);
613 if (ms & MonitoringInput) {
614 monitor_input_button->set_active_state (CairoWidget::Mid);
616 monitor_input_button->unset_active_state ();
620 if (t->monitoring_choice() & MonitorDisk) {
621 monitor_disk_button->set_active_state (CairoWidget::Active);
623 if (ms & MonitoringDisk) {
624 monitor_disk_button->set_active_state (CairoWidget::Mid);
626 monitor_disk_button->unset_active_state ();
632 RouteUI::monitor_input_press(GdkEventButton* ev)
638 RouteUI::monitor_input_release(GdkEventButton* ev)
640 return monitor_release (ev, MonitorInput);
644 RouteUI::monitor_disk_press (GdkEventButton* ev)
650 RouteUI::monitor_disk_release (GdkEventButton* ev)
652 return monitor_release (ev, MonitorDisk);
656 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
658 if (ev->button != 1) {
662 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
669 boost::shared_ptr<RouteList> rl;
671 /* XXX for now, monitoring choices are orthogonal. cue monitoring
672 will follow in 3.X but requires mixing the input and playback (disk)
673 signal together, which requires yet more buffers.
676 if (t->monitoring_choice() & monitor_choice) {
677 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
679 /* this line will change when the options are non-orthogonal */
680 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
684 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
685 rl = _session->get_routes ();
687 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
688 if (_route->route_group() && _route->route_group()->is_monitoring()) {
689 rl = _route->route_group()->route_list();
691 rl.reset (new RouteList);
692 rl->push_back (route());
695 rl.reset (new RouteList);
696 rl->push_back (route());
699 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
705 RouteUI::build_record_menu ()
711 /* no rec-button context menu for non-MIDI tracks
714 if (is_midi_track()) {
715 record_menu = new Menu;
716 record_menu->set_name ("ArdourContextMenu");
718 using namespace Menu_Helpers;
719 MenuList& items = record_menu->items();
721 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
722 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
724 if (_route->record_enabled()) {
725 step_edit_item->set_sensitive (false);
728 step_edit_item->set_active (midi_track()->step_editing());
733 RouteUI::toggle_step_edit ()
735 if (!is_midi_track() || _route->record_enabled()) {
739 midi_track()->set_step_editing (step_edit_item->get_active());
743 RouteUI::step_edit_changed (bool yn)
746 if (rec_enable_button) {
747 rec_enable_button->set_visual_state (3);
750 start_step_editing ();
752 if (step_edit_item) {
753 step_edit_item->set_active (true);
758 if (rec_enable_button) {
759 rec_enable_button->set_visual_state (0);
762 stop_step_editing ();
764 if (step_edit_item) {
765 step_edit_item->set_active (false);
771 RouteUI::rec_enable_release (GdkEventButton* ev)
773 if (Keyboard::is_context_menu_event (ev)) {
774 build_record_menu ();
776 record_menu->popup (1, ev->time);
785 RouteUI::build_sends_menu ()
787 using namespace Menu_Helpers;
789 sends_menu = new Menu;
790 sends_menu->set_name ("ArdourContextMenu");
791 MenuList& items = sends_menu->items();
794 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
798 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
802 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
806 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
810 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
814 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
817 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
821 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
824 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
825 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
826 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
831 RouteUI::create_sends (Placement p, bool include_buses)
833 _session->globally_add_internal_sends (_route, p, include_buses);
837 RouteUI::create_selected_sends (Placement p, bool include_buses)
839 boost::shared_ptr<RouteList> rlist (new RouteList);
840 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
842 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
843 RouteTimeAxisView* rtv;
845 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
846 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
847 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
848 rlist->push_back (rui->route());
854 _session->add_internal_sends (_route, p, rlist);
858 RouteUI::set_sends_gain_from_track ()
860 _session->globally_set_send_gains_from_track (_route);
864 RouteUI::set_sends_gain_to_zero ()
866 _session->globally_set_send_gains_to_zero (_route);
870 RouteUI::set_sends_gain_to_unity ()
872 _session->globally_set_send_gains_to_unity (_route);
876 RouteUI::show_sends_press(GdkEventButton* ev)
878 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
882 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
884 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
886 // do nothing on midi sigc::bind event
889 } else if (Keyboard::is_context_menu_event (ev)) {
891 if (sends_menu == 0) {
895 sends_menu->popup (0, ev->time);
899 /* change button state */
901 show_sends_button->set_active (!show_sends_button->get_active());
905 if (show_sends_button->get_active()) {
906 /* show sends to this bus */
907 MixerStrip::SwitchIO (_route);
908 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun(*this, &RouteUI::send_blink));
910 /* everybody back to normal */
911 send_blink_connection.disconnect ();
912 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
922 RouteUI::show_sends_release (GdkEventButton*)
928 RouteUI::send_blink (bool onoff)
930 if (!show_sends_button) {
935 show_sends_button->set_state (STATE_ACTIVE);
937 show_sends_button->set_state (STATE_NORMAL);
942 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
944 if (r->is_master() || r->is_monitor()) {
948 if (Config->get_solo_control_is_listen_control()) {
950 if (r->listening_via_monitor()) {
959 if (!r->self_soloed()) {
970 RouteUI::solo_visual_state_with_isolate (boost::shared_ptr<Route> r)
972 if (r->is_master() || r->is_monitor()) {
976 if (Config->get_solo_control_is_listen_control()) {
978 if (r->listening_via_monitor()) {
986 if (r->solo_isolated()) {
988 } else if (r->soloed()) {
989 if (!r->self_soloed()) {
1000 RouteUI::solo_isolate_visual_state (boost::shared_ptr<Route> r)
1002 if (r->is_master() || r->is_monitor()) {
1006 if (r->solo_isolated()) {
1014 RouteUI::solo_safe_visual_state (boost::shared_ptr<Route> r)
1016 if (r->is_master() || r->is_monitor()) {
1020 if (r->solo_safe()) {
1028 RouteUI::update_solo_display ()
1032 if (Config->get_solo_control_is_listen_control()) {
1034 if (solo_button->get_active() != (x = _route->listening_via_monitor())) {
1035 ++_i_am_the_modifier;
1036 solo_button->set_active(x);
1037 --_i_am_the_modifier;
1042 if (solo_button->get_active() != (x = _route->soloed())) {
1043 ++_i_am_the_modifier;
1044 solo_button->set_active (x);
1045 --_i_am_the_modifier;
1050 bool yn = _route->solo_safe ();
1052 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1053 solo_safe_check->set_active (yn);
1056 yn = _route->solo_isolated ();
1058 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1059 solo_isolated_check->set_active (yn);
1062 set_button_names ();
1064 if (solo_isolated_led) {
1065 if (_route->solo_isolated()) {
1066 solo_isolated_led->set_active_state (CairoWidget::Active);
1068 solo_isolated_led->unset_active_state ();
1072 if (solo_safe_led) {
1073 if (_route->solo_safe()) {
1074 solo_safe_led->set_active_state (CairoWidget::Active);
1076 solo_safe_led->unset_active_state ();
1080 solo_button->set_visual_state (solo_visual_state (_route));
1082 /* some changes to solo status can affect mute display, so catch up
1085 update_mute_display ();
1089 RouteUI::solo_changed_so_update_mute ()
1091 update_mute_display ();
1095 RouteUI::mute_changed(void* /*src*/)
1097 update_mute_display ();
1101 RouteUI::mute_visual_state (Session* s, boost::shared_ptr<Route> r)
1103 if (r->is_master() || r->is_monitor()) {
1108 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1113 } else if (s->soloing() && !r->soloed() && !r->solo_isolated()) {
1116 /* no mute at all */
1126 /* no mute at all */
1135 RouteUI::update_mute_display ()
1141 bool model = _route->muted();
1142 bool view = mute_button->get_active();
1144 /* first make sure the button's "depressed" visual
1148 if (model != view) {
1149 ++_i_am_the_modifier;
1150 mute_button->set_active (model);
1151 --_i_am_the_modifier;
1154 mute_button->set_visual_state (mute_visual_state (_session, _route));
1158 RouteUI::route_rec_enable_changed ()
1160 update_rec_display ();
1161 update_monitoring_display ();
1165 RouteUI::session_rec_enable_changed ()
1167 update_rec_display ();
1168 update_monitoring_display ();
1172 RouteUI::update_rec_display ()
1174 if (!rec_enable_button || !_route) {
1178 bool model = _route->record_enabled();
1179 bool view = rec_enable_button->get_active();
1181 /* first make sure the button's "depressed" visual
1185 if (model != view) {
1186 ++_i_am_the_modifier;
1187 rec_enable_button->set_active (model);
1188 --_i_am_the_modifier;
1191 /* now make sure its color state is correct */
1194 switch (_session->record_status ()) {
1195 case Session::Recording:
1196 rec_enable_button->set_visual_state (1);
1199 case Session::Disabled:
1200 case Session::Enabled:
1201 rec_enable_button->set_visual_state (2);
1206 if (step_edit_item) {
1207 step_edit_item->set_sensitive (false);
1211 rec_enable_button->set_visual_state (0);
1213 if (step_edit_item) {
1214 step_edit_item->set_sensitive (true);
1219 check_rec_enable_sensitivity ();
1223 RouteUI::build_solo_menu (void)
1225 using namespace Menu_Helpers;
1227 solo_menu = new Menu;
1228 solo_menu->set_name ("ArdourContextMenu");
1229 MenuList& items = solo_menu->items();
1230 CheckMenuItem* check;
1232 check = new CheckMenuItem(_("Solo Isolate"));
1233 check->set_active (_route->solo_isolated());
1234 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1235 items.push_back (CheckMenuElem(*check));
1236 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1239 check = new CheckMenuItem(_("Solo Safe"));
1240 check->set_active (_route->solo_safe());
1241 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1242 items.push_back (CheckMenuElem(*check));
1243 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1246 //items.push_back (SeparatorElem());
1247 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1252 RouteUI::build_mute_menu(void)
1254 using namespace Menu_Helpers;
1256 mute_menu = new Menu;
1257 mute_menu->set_name ("ArdourContextMenu");
1259 MenuList& items = mute_menu->items();
1261 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1262 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1263 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1264 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1265 pre_fader_mute_check->show_all();
1267 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1268 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1269 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1270 items.push_back (CheckMenuElem(*post_fader_mute_check));
1271 post_fader_mute_check->show_all();
1273 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1274 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1275 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1276 items.push_back (CheckMenuElem(*listen_mute_check));
1277 listen_mute_check->show_all();
1279 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1280 init_mute_menu(MuteMaster::Main, main_mute_check);
1281 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1282 items.push_back (CheckMenuElem(*main_mute_check));
1283 main_mute_check->show_all();
1285 //items.push_back (SeparatorElem());
1286 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1288 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1292 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1294 check->set_active (_route->mute_points() & mp);
1298 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1300 if (check->get_active()) {
1301 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1303 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1308 RouteUI::muting_change ()
1310 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1313 MuteMaster::MutePoint current = _route->mute_points ();
1315 yn = (current & MuteMaster::PreFader);
1317 if (pre_fader_mute_check->get_active() != yn) {
1318 pre_fader_mute_check->set_active (yn);
1321 yn = (current & MuteMaster::PostFader);
1323 if (post_fader_mute_check->get_active() != yn) {
1324 post_fader_mute_check->set_active (yn);
1327 yn = (current & MuteMaster::Listen);
1329 if (listen_mute_check->get_active() != yn) {
1330 listen_mute_check->set_active (yn);
1333 yn = (current & MuteMaster::Main);
1335 if (main_mute_check->get_active() != yn) {
1336 main_mute_check->set_active (yn);
1341 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1343 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1347 bool view = solo_isolated_led->active_state();
1348 bool model = _route->solo_isolated();
1350 /* called BEFORE the view has changed */
1352 if (ev->button == 1) {
1353 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1356 /* disable isolate for all routes */
1357 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1361 if (model == view) {
1363 /* flip just this route */
1365 boost::shared_ptr<RouteList> rl (new RouteList);
1366 rl->push_back (_route);
1367 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1376 RouteUI::solo_safe_button_release (GdkEventButton*)
1378 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1383 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1385 bool view = check->get_active();
1386 bool model = _route->solo_isolated();
1388 /* called AFTER the view has changed */
1390 if (model != view) {
1391 _route->set_solo_isolated (view, this);
1396 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1398 _route->set_solo_safe (check->get_active(), this);
1401 /** Ask the user to choose a colour, and then set all selected tracks
1405 RouteUI::choose_color ()
1408 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1411 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1412 boost::bind (&RouteUI::set_color, _1, color)
1417 /** Set the route's own color. This may not be used for display if
1418 * the route is in a group which shares its color with its routes.
1421 RouteUI::set_color (const Gdk::Color & c)
1427 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1429 /* note: we use the route state ID here so that color is the same for both
1430 the time axis view and the mixer strip
1433 gui_object_state().set<string> (route_state_id(), X_("color"), buf);
1434 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1437 /** @return GUI state ID for things that are common to the route in all its representations */
1439 RouteUI::route_state_id () const
1441 return string_compose (X_("route %1"), _route->id().to_s());
1445 RouteUI::set_color_from_route ()
1447 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1455 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1458 _color.set_green (g);
1459 _color.set_blue (b);
1465 RouteUI::remove_this_route (bool apply_to_selection)
1467 if (apply_to_selection) {
1468 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1470 if ((route()->is_master() || route()->is_monitor()) &&
1471 !Config->get_allow_special_bus_removal()) {
1472 MessageDialog msg (_("That would be bad news ...."),
1476 msg.set_secondary_text (string_compose (_(
1477 "Removing the master or monitor bus is such a bad idea\n\
1478 that %1 is not going to allow it.\n\
1480 If you really want to do this sort of thing\n\
1481 edit your ardour.rc file to set the\n\
1482 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1489 vector<string> choices;
1493 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());
1495 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());
1498 choices.push_back (_("No, do nothing."));
1499 choices.push_back (_("Yes, remove it."));
1503 title = _("Remove track");
1505 title = _("Remove bus");
1508 Choice prompter (title, prompt, choices);
1510 if (prompter.run () == 1) {
1511 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1517 RouteUI::idle_remove_this_route (RouteUI *rui)
1519 rui->_session->remove_route (rui->route());
1523 /** @return true if this name should be used for the route, otherwise false */
1525 RouteUI::verify_new_route_name (const std::string& name)
1527 if (name.find (':') == string::npos) {
1531 MessageDialog colon_msg (
1532 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1533 false, MESSAGE_QUESTION, BUTTONS_NONE
1536 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1537 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1539 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1543 RouteUI::route_rename ()
1545 ArdourPrompter name_prompter (true);
1550 name_prompter.set_title (_("Rename Track"));
1552 name_prompter.set_title (_("Rename Bus"));
1554 name_prompter.set_prompt (_("New name:"));
1555 name_prompter.set_initial_text (_route->name());
1556 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1557 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1558 name_prompter.show_all ();
1561 switch (name_prompter.run ()) {
1562 case Gtk::RESPONSE_ACCEPT:
1563 name_prompter.get_result (result);
1564 name_prompter.hide ();
1565 if (result.length()) {
1566 if (verify_new_route_name (result)) {
1567 _route->set_name (result);
1570 /* back to name prompter */
1574 /* nothing entered, just get out of here */
1586 RouteUI::property_changed (const PropertyChange& what_changed)
1588 if (what_changed.contains (ARDOUR::Properties::name)) {
1589 name_label.set_text (_route->name());
1594 RouteUI::set_route_active (bool a, bool apply_to_selection)
1596 if (apply_to_selection) {
1597 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1599 _route->set_active (a, this);
1604 RouteUI::toggle_denormal_protection ()
1606 if (denormal_menu_item) {
1610 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1612 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1613 _route->set_denormal_protection (x);
1619 RouteUI::denormal_protection_changed ()
1621 if (denormal_menu_item) {
1622 denormal_menu_item->set_active (_route->denormal_protection());
1627 RouteUI::disconnect_input ()
1629 _route->input()->disconnect (this);
1633 RouteUI::disconnect_output ()
1635 _route->output()->disconnect (this);
1639 RouteUI::is_track () const
1641 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1644 boost::shared_ptr<Track>
1645 RouteUI::track() const
1647 return boost::dynamic_pointer_cast<Track>(_route);
1651 RouteUI::is_audio_track () const
1653 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1656 boost::shared_ptr<AudioTrack>
1657 RouteUI::audio_track() const
1659 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1663 RouteUI::is_midi_track () const
1665 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1668 boost::shared_ptr<MidiTrack>
1669 RouteUI::midi_track() const
1671 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1675 RouteUI::has_audio_outputs () const
1677 return (_route->n_outputs().n_audio() > 0);
1681 RouteUI::name() const
1683 return _route->name();
1687 RouteUI::map_frozen ()
1689 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1691 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1694 switch (at->freeze_state()) {
1695 case AudioTrack::Frozen:
1696 rec_enable_button->set_sensitive (false);
1699 rec_enable_button->set_sensitive (true);
1706 RouteUI::adjust_latency ()
1708 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1712 RouteUI::save_as_template ()
1715 std::string safe_name;
1718 path = ARDOUR::user_route_template_directory ();
1720 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1721 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1725 Prompter p (true); // modal
1727 p.set_title (_("Save As Template"));
1728 p.set_prompt (_("Template name:"));
1729 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1731 case RESPONSE_ACCEPT:
1738 p.get_result (name, true);
1740 safe_name = legalize_for_path (name);
1741 safe_name += template_suffix;
1745 _route->save_as_template (path.to_string(), name);
1749 RouteUI::check_rec_enable_sensitivity ()
1751 if (_session->transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1752 rec_enable_button->set_sensitive (false);
1754 rec_enable_button->set_sensitive (true);
1757 update_monitoring_display ();
1761 RouteUI::parameter_changed (string const & p)
1763 /* this handles RC and per-session parameter changes */
1765 if (p == "disable-disarm-during-roll") {
1766 check_rec_enable_sensitivity ();
1767 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1768 set_button_names ();
1769 } else if (p == "auto-input") {
1770 update_monitoring_display ();
1775 RouteUI::step_gain_up ()
1777 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1781 RouteUI::page_gain_up ()
1783 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1787 RouteUI::step_gain_down ()
1789 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1793 RouteUI::page_gain_down ()
1795 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1799 RouteUI::open_remote_control_id_dialog ()
1801 ArdourDialog dialog (_("Remote Control ID"));
1803 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1805 HBox* hbox = manage (new HBox);
1806 hbox->set_spacing (6);
1807 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1808 SpinButton* spin = manage (new SpinButton);
1809 spin->set_digits (0);
1810 spin->set_increments (1, 10);
1811 spin->set_range (0, limit);
1812 spin->set_value (_route->remote_control_id());
1813 hbox->pack_start (*spin);
1814 dialog.get_vbox()->pack_start (*hbox);
1816 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1817 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1820 int const r = dialog.run ();
1822 if (r == RESPONSE_ACCEPT) {
1823 _route->set_remote_control_id (spin->get_value_as_int ());
1828 RouteUI::setup_invert_buttons ()
1830 /* remove old invert buttons */
1831 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1832 _invert_button_box.remove (**i);
1835 _invert_buttons.clear ();
1837 if (!_route || !_route->input()) {
1841 uint32_t const N = _route->input()->n_ports().n_audio ();
1843 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1845 for (uint32_t i = 0; i < to_add; ++i) {
1846 BindableToggleButton* b = manage (new BindableToggleButton);
1847 b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_toggled), i, b));
1848 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1850 b->set_name (X_("MixerInvertButton"));
1852 b->add (*manage (new Label (X_("Ø"))));
1854 b->add (*manage (new Label (string_compose (X_("Ø%1"), i + 1))));
1858 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));
1860 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) all channels of this track. Right-click to show menu."), i + 1));
1863 _invert_buttons.push_back (b);
1864 _invert_button_box.pack_start (*b);
1867 _invert_button_box.show_all ();
1871 RouteUI::set_invert_button_state ()
1873 ++_i_am_the_modifier;
1875 uint32_t const N = _route->input()->n_ports().n_audio();
1876 if (N > _max_invert_buttons) {
1877 _invert_buttons.front()->set_active (_route->phase_invert().any());
1878 --_i_am_the_modifier;
1883 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1884 (*i)->set_active (_route->phase_invert (j));
1887 --_i_am_the_modifier;
1891 RouteUI::invert_toggled (uint32_t i, BindableToggleButton* b)
1893 if (_i_am_the_modifier) {
1897 uint32_t const N = _route->input()->n_ports().n_audio();
1898 if (N <= _max_invert_buttons) {
1899 _route->set_phase_invert (i, b->get_active ());
1901 boost::dynamic_bitset<> p (N);
1902 if (b->get_active ()) {
1905 _route->set_phase_invert (p);
1910 RouteUI::invert_press (GdkEventButton* ev)
1912 using namespace Menu_Helpers;
1914 if (ev->button != 3) {
1918 delete _invert_menu;
1919 _invert_menu = new Menu;
1920 _invert_menu->set_name ("ArdourContextMenu");
1921 MenuList& items = _invert_menu->items ();
1923 uint32_t const N = _route->input()->n_ports().n_audio();
1924 for (uint32_t i = 0; i < N; ++i) {
1925 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1926 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1927 ++_i_am_the_modifier;
1928 e->set_active (_route->phase_invert (i));
1929 --_i_am_the_modifier;
1932 _invert_menu->popup (0, ev->time);
1938 RouteUI::invert_menu_toggled (uint32_t c)
1940 if (_i_am_the_modifier) {
1944 _route->set_phase_invert (c, !_route->phase_invert (c));
1948 RouteUI::set_invert_sensitive (bool yn)
1950 for (list<BindableToggleButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1951 (*b)->set_sensitive (yn);
1956 RouteUI::request_redraw ()
1959 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1963 /** The Route's gui_changed signal has been emitted */
1965 RouteUI::route_gui_changed (string what_changed)
1967 if (what_changed == "color") {
1968 if (set_color_from_route () == 0) {
1969 route_color_changed ();
1974 /** @return the color that this route should use; it maybe its own,
1975 or it maybe that of its route group.
1978 RouteUI::color () const
1980 RouteGroup* g = _route->route_group ();
1982 if (g && g->is_color()) {
1983 return GroupTabs::group_color (g);