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"
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 ();
95 pre_fader_mute_check = 0;
96 post_fader_mute_check = 0;
97 listen_mute_check = 0;
100 solo_isolated_check = 0;
101 solo_isolated_led = 0;
105 denormal_menu_item = 0;
107 multiple_mute_change = false;
108 multiple_solo_change = false;
109 _i_am_the_modifier = 0;
111 setup_invert_buttons ();
113 mute_button = manage (new BindableToggleButton ());
114 // mute_button->set_self_managed (true);
115 mute_button->set_name ("MuteButton");
116 mute_button->add (mute_button_label);
117 mute_button_label.show ();
118 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
120 solo_button = manage (new BindableToggleButton ());
121 // solo_button->set_self_managed (true);
122 solo_button->set_name ("SoloButton");
123 solo_button->add (solo_button_label);
124 solo_button_label.show ();
125 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
126 solo_button->set_no_show_all (true);
128 rec_enable_button = manage (new BindableToggleButton ());
129 rec_enable_button->set_name ("RecordEnableButton");
130 // rec_enable_button->set_self_managed (true);
131 rec_enable_button->add (rec_enable_button_label);
132 rec_enable_button_label.show ();
133 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
135 show_sends_button = manage (new BindableToggleButton (""));
136 show_sends_button->set_name ("SendAlert");
137 // show_sends_button->set_self_managed (true);
138 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
140 monitor_input_button = manage (new BindableToggleButton ());
141 // monitor_input_button->set_self_managed (true);
142 monitor_input_button->set_name ("MonitorInputButton");
143 monitor_input_button->add (monitor_input_button_label);
144 monitor_input_button_label.show ();
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 BindableToggleButton ());
149 // monitor_disk_button->set_self_managed (true);
150 monitor_disk_button->set_name ("MonitorDiskButton");
151 monitor_disk_button->add (monitor_disk_button_label);
152 monitor_disk_button_label.show ();
153 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
154 monitor_disk_button->set_no_show_all (true);
156 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
157 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
158 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
160 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
162 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
163 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
165 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
166 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
168 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
169 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
170 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
171 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
173 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
174 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
176 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
177 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
183 route_connections.drop_connections ();
191 denormal_menu_item = 0;
195 RouteUI::self_delete ()
201 RouteUI::set_route (boost::shared_ptr<Route> rp)
207 if (set_color_from_route()) {
208 set_color (unique_random_color());
212 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
215 mute_button->set_controllable (_route->mute_control());
216 solo_button->set_controllable (_route->solo_control());
218 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
219 _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
221 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
222 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
223 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
224 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
226 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
227 _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
229 _route->io_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::setup_invert_buttons, this), gui_context ());
230 _route->gui_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
232 if (_session->writable() && is_track()) {
233 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
235 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
237 rec_enable_button->show();
238 rec_enable_button->set_controllable (t->rec_enable_control());
240 update_rec_display ();
242 if (is_midi_track()) {
243 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
244 ui_bind (&RouteUI::step_edit_changed, this, _1), gui_context());
250 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
251 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
253 update_monitoring_display ();
256 mute_button->unset_flags (Gtk::CAN_FOCUS);
257 solo_button->unset_flags (Gtk::CAN_FOCUS);
261 if (_route->is_monitor()) {
262 solo_button->hide ();
269 setup_invert_buttons ();
270 set_invert_button_state ();
274 RouteUI::polarity_changed ()
280 set_invert_button_state ();
284 RouteUI::mute_press (GdkEventButton* ev)
286 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
290 multiple_mute_change = false;
292 if (!_i_am_the_modifier) {
294 if (Keyboard::is_context_menu_event (ev)) {
300 mute_menu->popup(0,ev->time);
304 if (Keyboard::is_button2_event (ev)) {
305 // Primary-button2 click is the midi binding click
306 // button2-click is "momentary"
309 if (mute_button->on_button_press_event (ev)) {
313 _mute_release = new SoloMuteRelease (_route->muted ());
316 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
318 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
321 _mute_release->routes = _session->get_routes ();
324 _session->set_mute (_session->get_routes(), !_route->muted());
326 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
328 /* Primary-button1 applies change to the mix group even if it is not active
329 NOTE: Primary-button2 is MIDI learn.
332 if (ev->button == 1 && _route->route_group()) {
334 _mute_release->routes = _session->get_routes ();
337 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
342 /* plain click applies change to this route */
344 boost::shared_ptr<RouteList> rl (new RouteList);
345 rl->push_back (_route);
348 _mute_release->routes = rl;
351 _session->set_mute (rl, !_route->muted());
363 RouteUI::mute_release (GdkEventButton*)
365 if (!_i_am_the_modifier) {
367 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
368 delete _mute_release;
377 RouteUI::solo_press(GdkEventButton* ev)
379 /* ignore double/triple clicks */
381 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
385 multiple_solo_change = false;
387 if (!_i_am_the_modifier) {
389 if (Keyboard::is_context_menu_event (ev)) {
391 if (!solo_isolated_led) {
393 if (solo_menu == 0) {
397 solo_menu->popup (1, ev->time);
402 if (Keyboard::is_button2_event (ev)) {
404 // Primary-button2 click is the midi binding click
405 // button2-click is "momentary"
407 if (solo_button->on_button_press_event (ev)) {
411 _solo_release = new SoloMuteRelease (_route->self_soloed());
414 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
416 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
418 /* Primary-Tertiary-click applies change to all routes */
421 _solo_release->routes = _session->get_routes ();
424 if (Config->get_solo_control_is_listen_control()) {
425 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
427 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
430 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
432 // Primary-Secondary-click: exclusively solo this track
435 _solo_release->exclusive = true;
437 boost::shared_ptr<RouteList> routes = _session->get_routes();
439 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
440 if ((*i)->soloed ()) {
441 _solo_release->routes_on->push_back (*i);
443 _solo_release->routes_off->push_back (*i);
448 if (Config->get_solo_control_is_listen_control()) {
449 /* ??? we need a just_one_listen() method */
451 _session->set_just_one_solo (_route, true);
454 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
456 // shift-click: toggle solo isolated status
458 _route->set_solo_isolated (!_route->solo_isolated(), this);
459 delete _solo_release;
462 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
464 /* Primary-button1: solo mix group.
465 NOTE: Primary-button2 is MIDI learn.
468 if (ev->button == 1 && _route->route_group()) {
471 _solo_release->routes = _route->route_group()->route_list();
474 if (Config->get_solo_control_is_listen_control()) {
475 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
477 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
483 /* click: solo this route */
485 boost::shared_ptr<RouteList> rl (new RouteList);
486 rl->push_back (route());
489 _solo_release->routes = rl;
492 if (Config->get_solo_control_is_listen_control()) {
493 _session->set_listen (rl, !_route->listening_via_monitor());
495 _session->set_solo (rl, !_route->self_soloed());
506 RouteUI::solo_release (GdkEventButton*)
508 if (!_i_am_the_modifier) {
512 if (_solo_release->exclusive) {
515 if (Config->get_solo_control_is_listen_control()) {
516 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
518 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
522 delete _solo_release;
531 RouteUI::rec_enable_press(GdkEventButton* ev)
533 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
537 if (!_session->engine().connected()) {
538 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
543 if (is_midi_track()) {
545 /* cannot rec-enable while step-editing */
547 if (midi_track()->step_editing()) {
552 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
554 if (Keyboard::is_button2_event (ev)) {
556 // do nothing on midi sigc::bind event
557 return rec_enable_button->on_button_press_event (ev);
559 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
561 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->get_active());
563 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
565 /* Primary-button1 applies change to the route group (even if it is not active)
566 NOTE: Primary-button2 is MIDI learn.
568 if (ev->button == 1 && _route->route_group()) {
569 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->get_active(), Session::rt_cleanup, true);
572 } else if (Keyboard::is_context_menu_event (ev)) {
574 /* do this on release */
578 boost::shared_ptr<RouteList> rl (new RouteList);
579 rl->push_back (route());
580 _session->set_record_enabled (rl, !rec_enable_button->get_active());
588 RouteUI::monitoring_changed ()
590 update_monitoring_display ();
594 RouteUI::update_monitoring_display ()
596 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
602 MonitorChoice mc = t->monitoring();
604 if (mc & MonitorInput) {
605 monitor_input_button->set_visual_state (1);
607 monitor_input_button->set_visual_state (0);
610 if (mc & MonitorDisk) {
611 monitor_disk_button->set_visual_state (1);
613 monitor_disk_button->set_visual_state (0);
618 RouteUI::monitor_input_press(GdkEventButton* ev)
624 RouteUI::monitor_input_release(GdkEventButton* ev)
626 return monitor_release (ev, MonitorInput);
630 RouteUI::monitor_disk_press (GdkEventButton* ev)
636 RouteUI::monitor_disk_release (GdkEventButton* ev)
638 return monitor_release (ev, MonitorDisk);
642 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
644 if (ev->button != 1) {
648 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
655 boost::shared_ptr<RouteList> rl;
657 /* XXX for now, monitoring choices are orthogonal. cue monitoring
658 will follow in 3.X but requires mixing the input and playback (disk)
659 signal together, which requires yet more buffers.
662 if (t->monitoring() & monitor_choice) {
663 mc = MonitorChoice (t->monitoring() & ~monitor_choice);
665 /* this line will change when the options are non-orthogonal */
666 // mc = MonitorChoice (t->monitoring() | monitor_choice);
670 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
671 rl = _session->get_routes ();
674 rl.reset (new RouteList);
675 rl->push_back (route());
678 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
684 RouteUI::build_record_menu ()
690 /* no rec-button context menu for non-MIDI tracks
693 if (is_midi_track()) {
694 record_menu = new Menu;
695 record_menu->set_name ("ArdourContextMenu");
697 using namespace Menu_Helpers;
698 MenuList& items = record_menu->items();
700 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
701 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
703 if (_route->record_enabled()) {
704 step_edit_item->set_sensitive (false);
707 step_edit_item->set_active (midi_track()->step_editing());
712 RouteUI::toggle_step_edit ()
714 if (!is_midi_track() || _route->record_enabled()) {
718 midi_track()->set_step_editing (step_edit_item->get_active());
722 RouteUI::step_edit_changed (bool yn)
725 if (rec_enable_button) {
726 rec_enable_button->set_visual_state (3);
729 start_step_editing ();
731 if (step_edit_item) {
732 step_edit_item->set_active (true);
737 if (rec_enable_button) {
738 rec_enable_button->set_visual_state (0);
741 stop_step_editing ();
743 if (step_edit_item) {
744 step_edit_item->set_active (false);
750 RouteUI::rec_enable_release (GdkEventButton* ev)
752 if (Keyboard::is_context_menu_event (ev)) {
753 build_record_menu ();
755 record_menu->popup (1, ev->time);
764 RouteUI::build_sends_menu ()
766 using namespace Menu_Helpers;
768 sends_menu = new Menu;
769 sends_menu->set_name ("ArdourContextMenu");
770 MenuList& items = sends_menu->items();
773 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
777 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
781 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
785 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
789 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
793 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
796 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
800 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
803 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
804 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
805 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
810 RouteUI::create_sends (Placement p, bool include_buses)
812 _session->globally_add_internal_sends (_route, p, include_buses);
816 RouteUI::create_selected_sends (Placement p, bool include_buses)
818 boost::shared_ptr<RouteList> rlist (new RouteList);
819 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
821 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
822 RouteTimeAxisView* rtv;
824 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
825 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
826 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
827 rlist->push_back (rui->route());
833 _session->add_internal_sends (_route, p, rlist);
837 RouteUI::set_sends_gain_from_track ()
839 _session->globally_set_send_gains_from_track (_route);
843 RouteUI::set_sends_gain_to_zero ()
845 _session->globally_set_send_gains_to_zero (_route);
849 RouteUI::set_sends_gain_to_unity ()
851 _session->globally_set_send_gains_to_unity (_route);
855 RouteUI::show_sends_press(GdkEventButton* ev)
857 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
861 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
863 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
865 // do nothing on midi sigc::bind event
868 } else if (Keyboard::is_context_menu_event (ev)) {
870 if (sends_menu == 0) {
874 sends_menu->popup (0, ev->time);
878 /* change button state */
880 show_sends_button->set_active (!show_sends_button->get_active());
884 if (show_sends_button->get_active()) {
885 /* show sends to this bus */
886 MixerStrip::SwitchIO (_route);
887 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun(*this, &RouteUI::send_blink));
889 /* everybody back to normal */
890 send_blink_connection.disconnect ();
891 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
901 RouteUI::show_sends_release (GdkEventButton*)
907 RouteUI::send_blink (bool onoff)
909 if (!show_sends_button) {
914 show_sends_button->set_state (STATE_ACTIVE);
916 show_sends_button->set_state (STATE_NORMAL);
921 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
923 if (r->is_master() || r->is_monitor()) {
927 if (Config->get_solo_control_is_listen_control()) {
929 if (r->listening_via_monitor()) {
938 if (!r->self_soloed()) {
949 RouteUI::solo_visual_state_with_isolate (boost::shared_ptr<Route> r)
951 if (r->is_master() || r->is_monitor()) {
955 if (Config->get_solo_control_is_listen_control()) {
957 if (r->listening_via_monitor()) {
965 if (r->solo_isolated()) {
967 } else if (r->soloed()) {
968 if (!r->self_soloed()) {
979 RouteUI::solo_isolate_visual_state (boost::shared_ptr<Route> r)
981 if (r->is_master() || r->is_monitor()) {
985 if (r->solo_isolated()) {
993 RouteUI::solo_safe_visual_state (boost::shared_ptr<Route> r)
995 if (r->is_master() || r->is_monitor()) {
999 if (r->solo_safe()) {
1007 RouteUI::update_solo_display ()
1011 if (Config->get_solo_control_is_listen_control()) {
1013 if (solo_button->get_active() != (x = _route->listening_via_monitor())) {
1014 ++_i_am_the_modifier;
1015 solo_button->set_active(x);
1016 --_i_am_the_modifier;
1021 if (solo_button->get_active() != (x = _route->soloed())) {
1022 ++_i_am_the_modifier;
1023 solo_button->set_active (x);
1024 --_i_am_the_modifier;
1029 bool yn = _route->solo_safe ();
1031 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1032 solo_safe_check->set_active (yn);
1035 yn = _route->solo_isolated ();
1037 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1038 solo_isolated_check->set_active (yn);
1041 set_button_names ();
1043 if (solo_isolated_led) {
1044 solo_isolated_led->set_visual_state (_route->solo_isolated() ? 1 : 0);
1047 if (solo_safe_led) {
1048 solo_safe_led->set_visual_state (_route->solo_safe() ? 1 : 0);
1051 solo_button->set_visual_state (solo_visual_state (_route));
1053 /* some changes to solo status can affect mute display, so catch up
1056 update_mute_display ();
1060 RouteUI::solo_changed_so_update_mute ()
1062 update_mute_display ();
1066 RouteUI::mute_changed(void* /*src*/)
1068 update_mute_display ();
1072 RouteUI::mute_visual_state (Session* s, boost::shared_ptr<Route> r)
1074 if (r->is_master() || r->is_monitor()) {
1079 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1084 } else if (s->soloing() && !r->soloed() && !r->solo_isolated()) {
1087 /* no mute at all */
1097 /* no mute at all */
1106 RouteUI::update_mute_display ()
1112 bool model = _route->muted();
1113 bool view = mute_button->get_active();
1115 /* first make sure the button's "depressed" visual
1119 if (model != view) {
1120 ++_i_am_the_modifier;
1121 mute_button->set_active (model);
1122 --_i_am_the_modifier;
1125 mute_button->set_visual_state (mute_visual_state (_session, _route));
1129 RouteUI::route_rec_enable_changed ()
1131 update_rec_display ();
1135 RouteUI::session_rec_enable_changed ()
1137 update_rec_display ();
1141 RouteUI::update_rec_display ()
1143 if (!rec_enable_button || !_route) {
1147 bool model = _route->record_enabled();
1148 bool view = rec_enable_button->get_active();
1150 /* first make sure the button's "depressed" visual
1154 if (model != view) {
1155 ++_i_am_the_modifier;
1156 rec_enable_button->set_active (model);
1157 --_i_am_the_modifier;
1160 /* now make sure its color state is correct */
1163 switch (_session->record_status ()) {
1164 case Session::Recording:
1165 rec_enable_button->set_visual_state (1);
1168 case Session::Disabled:
1169 case Session::Enabled:
1170 rec_enable_button->set_visual_state (2);
1175 if (step_edit_item) {
1176 step_edit_item->set_sensitive (false);
1180 rec_enable_button->set_visual_state (0);
1182 if (step_edit_item) {
1183 step_edit_item->set_sensitive (true);
1188 check_rec_enable_sensitivity ();
1192 RouteUI::build_solo_menu (void)
1194 using namespace Menu_Helpers;
1196 solo_menu = new Menu;
1197 solo_menu->set_name ("ArdourContextMenu");
1198 MenuList& items = solo_menu->items();
1199 CheckMenuItem* check;
1201 check = new CheckMenuItem(_("Solo Isolate"));
1202 check->set_active (_route->solo_isolated());
1203 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1204 items.push_back (CheckMenuElem(*check));
1205 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1208 check = new CheckMenuItem(_("Solo Safe"));
1209 check->set_active (_route->solo_safe());
1210 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1211 items.push_back (CheckMenuElem(*check));
1212 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1215 //items.push_back (SeparatorElem());
1216 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1221 RouteUI::build_mute_menu(void)
1223 using namespace Menu_Helpers;
1225 mute_menu = new Menu;
1226 mute_menu->set_name ("ArdourContextMenu");
1228 MenuList& items = mute_menu->items();
1230 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1231 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1232 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1233 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1234 pre_fader_mute_check->show_all();
1236 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1237 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1238 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1239 items.push_back (CheckMenuElem(*post_fader_mute_check));
1240 post_fader_mute_check->show_all();
1242 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1243 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1244 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1245 items.push_back (CheckMenuElem(*listen_mute_check));
1246 listen_mute_check->show_all();
1248 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1249 init_mute_menu(MuteMaster::Main, main_mute_check);
1250 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1251 items.push_back (CheckMenuElem(*main_mute_check));
1252 main_mute_check->show_all();
1254 //items.push_back (SeparatorElem());
1255 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1257 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1261 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1263 check->set_active (_route->mute_points() & mp);
1267 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1269 if (check->get_active()) {
1270 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1272 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1277 RouteUI::muting_change ()
1279 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1282 MuteMaster::MutePoint current = _route->mute_points ();
1284 yn = (current & MuteMaster::PreFader);
1286 if (pre_fader_mute_check->get_active() != yn) {
1287 pre_fader_mute_check->set_active (yn);
1290 yn = (current & MuteMaster::PostFader);
1292 if (post_fader_mute_check->get_active() != yn) {
1293 post_fader_mute_check->set_active (yn);
1296 yn = (current & MuteMaster::Listen);
1298 if (listen_mute_check->get_active() != yn) {
1299 listen_mute_check->set_active (yn);
1302 yn = (current & MuteMaster::Main);
1304 if (main_mute_check->get_active() != yn) {
1305 main_mute_check->set_active (yn);
1310 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1312 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1316 bool view = (solo_isolated_led->visual_state() != 0);
1317 bool model = _route->solo_isolated();
1319 /* called BEFORE the view has changed */
1321 if (ev->button == 1) {
1322 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1325 /* disable isolate for all routes */
1326 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1330 if (model == view) {
1332 /* flip just this route */
1334 boost::shared_ptr<RouteList> rl (new RouteList);
1335 rl->push_back (_route);
1336 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1345 RouteUI::solo_safe_button_release (GdkEventButton*)
1347 _route->set_solo_safe (!(solo_safe_led->visual_state() > 0), this);
1352 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1354 bool view = check->get_active();
1355 bool model = _route->solo_isolated();
1357 /* called AFTER the view has changed */
1359 if (model != view) {
1360 _route->set_solo_isolated (view, this);
1365 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1367 _route->set_solo_safe (check->get_active(), this);
1370 /** Ask the user to choose a colour, and then set all selected tracks
1374 RouteUI::choose_color ()
1377 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1380 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1381 boost::bind (&RouteUI::set_color, _1, color)
1386 /** Set the route's own color. This may not be used for display if
1387 * the route is in a group which shares its color with its routes.
1390 RouteUI::set_color (const Gdk::Color & c)
1396 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1398 /* note: we use the route state ID here so that color is the same for both
1399 the time axis view and the mixer strip
1402 gui_object_state().set<string> (route_state_id(), X_("color"), buf);
1403 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1406 /** @return GUI state ID for things that are common to the route in all its representations */
1408 RouteUI::route_state_id () const
1410 return string_compose (X_("route %1"), _route->id().to_s());
1414 RouteUI::set_color_from_route ()
1416 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1424 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1427 _color.set_green (g);
1428 _color.set_blue (b);
1434 RouteUI::remove_this_route (bool apply_to_selection)
1436 if (apply_to_selection) {
1437 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1439 if ((route()->is_master() || route()->is_monitor()) &&
1440 !Config->get_allow_special_bus_removal()) {
1441 MessageDialog msg (_("That would be bad news ...."),
1445 msg.set_secondary_text (string_compose (_(
1446 "Removing the master or monitor bus is such a bad idea\n\
1447 that %1 is not going to allow it.\n\
1449 If you really want to do this sort of thing\n\
1450 edit your ardour.rc file to set the\n\
1451 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1458 vector<string> choices;
1462 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());
1464 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());
1467 choices.push_back (_("No, do nothing."));
1468 choices.push_back (_("Yes, remove it."));
1472 title = _("Remove track");
1474 title = _("Remove bus");
1477 Choice prompter (title, prompt, choices);
1479 if (prompter.run () == 1) {
1480 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1486 RouteUI::idle_remove_this_route (RouteUI *rui)
1488 rui->_session->remove_route (rui->route());
1492 /** @return true if this name should be used for the route, otherwise false */
1494 RouteUI::verify_new_route_name (const std::string& name)
1496 if (name.find (':') == string::npos) {
1500 MessageDialog colon_msg (
1501 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1502 false, MESSAGE_QUESTION, BUTTONS_NONE
1505 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1506 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1508 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1512 RouteUI::route_rename ()
1514 ArdourPrompter name_prompter (true);
1519 name_prompter.set_title (_("Rename Track"));
1521 name_prompter.set_title (_("Rename Bus"));
1523 name_prompter.set_prompt (_("New name:"));
1524 name_prompter.set_initial_text (_route->name());
1525 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1526 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1527 name_prompter.show_all ();
1530 switch (name_prompter.run ()) {
1531 case Gtk::RESPONSE_ACCEPT:
1532 name_prompter.get_result (result);
1533 name_prompter.hide ();
1534 if (result.length()) {
1535 if (verify_new_route_name (result)) {
1536 _route->set_name (result);
1539 /* back to name prompter */
1543 /* nothing entered, just get out of here */
1555 RouteUI::property_changed (const PropertyChange& what_changed)
1557 if (what_changed.contains (ARDOUR::Properties::name)) {
1558 name_label.set_text (_route->name());
1563 RouteUI::set_route_active (bool a, bool apply_to_selection)
1565 if (apply_to_selection) {
1566 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1568 _route->set_active (a, this);
1573 RouteUI::toggle_denormal_protection ()
1575 if (denormal_menu_item) {
1579 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1581 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1582 _route->set_denormal_protection (x);
1588 RouteUI::denormal_protection_changed ()
1590 if (denormal_menu_item) {
1591 denormal_menu_item->set_active (_route->denormal_protection());
1596 RouteUI::disconnect_input ()
1598 _route->input()->disconnect (this);
1602 RouteUI::disconnect_output ()
1604 _route->output()->disconnect (this);
1608 RouteUI::is_track () const
1610 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1613 boost::shared_ptr<Track>
1614 RouteUI::track() const
1616 return boost::dynamic_pointer_cast<Track>(_route);
1620 RouteUI::is_audio_track () const
1622 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1625 boost::shared_ptr<AudioTrack>
1626 RouteUI::audio_track() const
1628 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1632 RouteUI::is_midi_track () const
1634 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1637 boost::shared_ptr<MidiTrack>
1638 RouteUI::midi_track() const
1640 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1644 RouteUI::has_audio_outputs () const
1646 return (_route->n_outputs().n_audio() > 0);
1650 RouteUI::name() const
1652 return _route->name();
1656 RouteUI::map_frozen ()
1658 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1660 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1663 switch (at->freeze_state()) {
1664 case AudioTrack::Frozen:
1665 rec_enable_button->set_sensitive (false);
1668 rec_enable_button->set_sensitive (true);
1675 RouteUI::adjust_latency ()
1677 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1681 RouteUI::save_as_template ()
1684 std::string safe_name;
1687 path = ARDOUR::user_route_template_directory ();
1689 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1690 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1694 Prompter p (true); // modal
1696 p.set_title (_("Save As Template"));
1697 p.set_prompt (_("Template name:"));
1698 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1700 case RESPONSE_ACCEPT:
1707 p.get_result (name, true);
1709 safe_name = legalize_for_path (name);
1710 safe_name += template_suffix;
1714 _route->save_as_template (path.to_string(), name);
1718 RouteUI::check_rec_enable_sensitivity ()
1720 if (_session->transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1721 rec_enable_button->set_sensitive (false);
1723 rec_enable_button->set_sensitive (true);
1728 RouteUI::parameter_changed (string const & p)
1730 if (p == "disable-disarm-during-roll") {
1731 check_rec_enable_sensitivity ();
1732 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1733 set_button_names ();
1738 RouteUI::step_gain_up ()
1740 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1744 RouteUI::page_gain_up ()
1746 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1750 RouteUI::step_gain_down ()
1752 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1756 RouteUI::page_gain_down ()
1758 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1762 RouteUI::open_remote_control_id_dialog ()
1764 ArdourDialog dialog (_("Remote Control ID"));
1766 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1768 HBox* hbox = manage (new HBox);
1769 hbox->set_spacing (6);
1770 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1771 SpinButton* spin = manage (new SpinButton);
1772 spin->set_digits (0);
1773 spin->set_increments (1, 10);
1774 spin->set_range (0, limit);
1775 spin->set_value (_route->remote_control_id());
1776 hbox->pack_start (*spin);
1777 dialog.get_vbox()->pack_start (*hbox);
1779 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1780 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1783 int const r = dialog.run ();
1785 if (r == RESPONSE_ACCEPT) {
1786 _route->set_remote_control_id (spin->get_value_as_int ());
1791 RouteUI::setup_invert_buttons ()
1793 /* remove old invert buttons */
1794 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1795 _invert_button_box.remove (**i);
1798 _invert_buttons.clear ();
1800 if (!_route || !_route->input()) {
1804 uint32_t const N = _route->input()->n_ports().n_audio ();
1806 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1808 for (uint32_t i = 0; i < to_add; ++i) {
1809 BindableToggleButton* b = manage (new BindableToggleButton);
1810 b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_toggled), i, b));
1811 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1813 b->set_name (X_("MixerInvertButton"));
1815 b->add (*manage (new Label (X_("Ø"))));
1817 b->add (*manage (new Label (string_compose (X_("Ø%1"), i + 1))));
1821 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));
1823 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));
1826 _invert_buttons.push_back (b);
1827 _invert_button_box.pack_start (*b);
1830 _invert_button_box.show_all ();
1834 RouteUI::set_invert_button_state ()
1836 ++_i_am_the_modifier;
1838 uint32_t const N = _route->input()->n_ports().n_audio();
1839 if (N > _max_invert_buttons) {
1840 _invert_buttons.front()->set_active (_route->phase_invert().any());
1841 --_i_am_the_modifier;
1846 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1847 (*i)->set_active (_route->phase_invert (j));
1850 --_i_am_the_modifier;
1854 RouteUI::invert_toggled (uint32_t i, BindableToggleButton* b)
1856 if (_i_am_the_modifier) {
1860 uint32_t const N = _route->input()->n_ports().n_audio();
1861 if (N <= _max_invert_buttons) {
1862 _route->set_phase_invert (i, b->get_active ());
1864 boost::dynamic_bitset<> p (N);
1865 if (b->get_active ()) {
1868 _route->set_phase_invert (p);
1873 RouteUI::invert_press (GdkEventButton* ev)
1875 using namespace Menu_Helpers;
1877 if (ev->button != 3) {
1881 delete _invert_menu;
1882 _invert_menu = new Menu;
1883 _invert_menu->set_name ("ArdourContextMenu");
1884 MenuList& items = _invert_menu->items ();
1886 uint32_t const N = _route->input()->n_ports().n_audio();
1887 for (uint32_t i = 0; i < N; ++i) {
1888 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1889 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1890 ++_i_am_the_modifier;
1891 e->set_active (_route->phase_invert (i));
1892 --_i_am_the_modifier;
1895 _invert_menu->popup (0, ev->time);
1901 RouteUI::invert_menu_toggled (uint32_t c)
1903 if (_i_am_the_modifier) {
1907 _route->set_phase_invert (c, !_route->phase_invert (c));
1911 RouteUI::set_invert_sensitive (bool yn)
1913 for (list<BindableToggleButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1914 (*b)->set_sensitive (yn);
1919 RouteUI::request_redraw ()
1922 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1926 /** The Route's gui_changed signal has been emitted */
1928 RouteUI::route_gui_changed (string what_changed)
1930 if (what_changed == "color") {
1931 if (set_color_from_route () == 0) {
1932 route_color_changed ();
1937 /** @return the color that this route should use; it maybe its own,
1938 or it maybe that of its route group.
1941 RouteUI::color () const
1943 RouteGroup* g = _route->route_group ();
1945 if (g && g->is_color()) {
1946 return GroupTabs::group_color (g);