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 _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
161 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
163 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
164 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
166 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
167 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
169 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
170 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
171 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
172 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
174 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
175 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
177 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
178 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
184 route_connections.drop_connections ();
192 denormal_menu_item = 0;
196 RouteUI::self_delete ()
202 RouteUI::set_route (boost::shared_ptr<Route> rp)
208 if (set_color_from_route()) {
209 set_color (unique_random_color());
213 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
216 mute_button->set_controllable (_route->mute_control());
217 solo_button->set_controllable (_route->solo_control());
219 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
220 _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
222 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
223 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
224 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
225 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
227 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
228 _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
230 _route->io_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::setup_invert_buttons, this), gui_context ());
231 _route->gui_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
233 if (_session->writable() && is_track()) {
234 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
236 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
238 rec_enable_button->show();
239 rec_enable_button->set_controllable (t->rec_enable_control());
241 update_rec_display ();
243 if (is_midi_track()) {
244 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
245 ui_bind (&RouteUI::step_edit_changed, this, _1), gui_context());
251 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
252 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
254 update_monitoring_display ();
257 mute_button->unset_flags (Gtk::CAN_FOCUS);
258 solo_button->unset_flags (Gtk::CAN_FOCUS);
262 if (_route->is_monitor()) {
263 solo_button->hide ();
270 setup_invert_buttons ();
271 set_invert_button_state ();
275 RouteUI::polarity_changed ()
281 set_invert_button_state ();
285 RouteUI::mute_press (GdkEventButton* ev)
287 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
291 multiple_mute_change = false;
293 if (!_i_am_the_modifier) {
295 if (Keyboard::is_context_menu_event (ev)) {
301 mute_menu->popup(0,ev->time);
305 if (Keyboard::is_button2_event (ev)) {
306 // Primary-button2 click is the midi binding click
307 // button2-click is "momentary"
310 if (mute_button->on_button_press_event (ev)) {
314 _mute_release = new SoloMuteRelease (_route->muted ());
317 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
319 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
322 _mute_release->routes = _session->get_routes ();
325 _session->set_mute (_session->get_routes(), !_route->muted());
327 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
329 /* Primary-button1 applies change to the mix group even if it is not active
330 NOTE: Primary-button2 is MIDI learn.
333 if (ev->button == 1 && _route->route_group()) {
335 _mute_release->routes = _session->get_routes ();
338 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
343 /* plain click applies change to this route */
345 boost::shared_ptr<RouteList> rl (new RouteList);
346 rl->push_back (_route);
349 _mute_release->routes = rl;
352 _session->set_mute (rl, !_route->muted());
364 RouteUI::mute_release (GdkEventButton*)
366 if (!_i_am_the_modifier) {
368 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
369 delete _mute_release;
378 RouteUI::solo_press(GdkEventButton* ev)
380 /* ignore double/triple clicks */
382 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
386 multiple_solo_change = false;
388 if (!_i_am_the_modifier) {
390 if (Keyboard::is_context_menu_event (ev)) {
392 if (!solo_isolated_led) {
394 if (solo_menu == 0) {
398 solo_menu->popup (1, ev->time);
403 if (Keyboard::is_button2_event (ev)) {
405 // Primary-button2 click is the midi binding click
406 // button2-click is "momentary"
408 if (solo_button->on_button_press_event (ev)) {
412 _solo_release = new SoloMuteRelease (_route->self_soloed());
415 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
417 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
419 /* Primary-Tertiary-click applies change to all routes */
422 _solo_release->routes = _session->get_routes ();
425 if (Config->get_solo_control_is_listen_control()) {
426 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
428 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
431 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
433 // Primary-Secondary-click: exclusively solo this track
436 _solo_release->exclusive = true;
438 boost::shared_ptr<RouteList> routes = _session->get_routes();
440 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
441 if ((*i)->soloed ()) {
442 _solo_release->routes_on->push_back (*i);
444 _solo_release->routes_off->push_back (*i);
449 if (Config->get_solo_control_is_listen_control()) {
450 /* ??? we need a just_one_listen() method */
452 _session->set_just_one_solo (_route, true);
455 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
457 // shift-click: toggle solo isolated status
459 _route->set_solo_isolated (!_route->solo_isolated(), this);
460 delete _solo_release;
463 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
465 /* Primary-button1: solo mix group.
466 NOTE: Primary-button2 is MIDI learn.
469 if (ev->button == 1 && _route->route_group()) {
472 _solo_release->routes = _route->route_group()->route_list();
475 if (Config->get_solo_control_is_listen_control()) {
476 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
478 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
484 /* click: solo this route */
486 boost::shared_ptr<RouteList> rl (new RouteList);
487 rl->push_back (route());
490 _solo_release->routes = rl;
493 if (Config->get_solo_control_is_listen_control()) {
494 _session->set_listen (rl, !_route->listening_via_monitor());
496 _session->set_solo (rl, !_route->self_soloed());
507 RouteUI::solo_release (GdkEventButton*)
509 if (!_i_am_the_modifier) {
513 if (_solo_release->exclusive) {
516 if (Config->get_solo_control_is_listen_control()) {
517 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
519 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
523 delete _solo_release;
532 RouteUI::rec_enable_press(GdkEventButton* ev)
534 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
538 if (!_session->engine().connected()) {
539 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
544 if (is_midi_track()) {
546 /* cannot rec-enable while step-editing */
548 if (midi_track()->step_editing()) {
553 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
555 if (Keyboard::is_button2_event (ev)) {
557 // do nothing on midi sigc::bind event
558 return rec_enable_button->on_button_press_event (ev);
560 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
562 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->get_active());
564 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
566 /* Primary-button1 applies change to the route group (even if it is not active)
567 NOTE: Primary-button2 is MIDI learn.
569 if (ev->button == 1 && _route->route_group()) {
570 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->get_active(), Session::rt_cleanup, true);
573 } else if (Keyboard::is_context_menu_event (ev)) {
575 /* do this on release */
579 boost::shared_ptr<RouteList> rl (new RouteList);
580 rl->push_back (route());
581 _session->set_record_enabled (rl, !rec_enable_button->get_active());
589 RouteUI::monitoring_changed ()
591 update_monitoring_display ();
595 RouteUI::update_monitoring_display ()
601 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
607 MonitorState ms = t->monitoring_state();
609 if (ms & MonitoringInput) {
610 if (t->monitoring_choice() & MonitorInput) {
611 monitor_input_button->set_visual_state (1);
613 monitor_input_button->set_visual_state (2);
616 monitor_input_button->set_visual_state (0);
619 if (ms & MonitoringDisk) {
620 if (t->monitoring_choice() & MonitorDisk) {
621 monitor_disk_button->set_visual_state (1);
623 monitor_disk_button->set_visual_state (2);
626 monitor_disk_button->set_visual_state (0);
631 RouteUI::monitor_input_press(GdkEventButton* ev)
637 RouteUI::monitor_input_release(GdkEventButton* ev)
639 return monitor_release (ev, MonitorInput);
643 RouteUI::monitor_disk_press (GdkEventButton* ev)
649 RouteUI::monitor_disk_release (GdkEventButton* ev)
651 return monitor_release (ev, MonitorDisk);
655 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
657 if (ev->button != 1) {
661 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
668 boost::shared_ptr<RouteList> rl;
670 /* XXX for now, monitoring choices are orthogonal. cue monitoring
671 will follow in 3.X but requires mixing the input and playback (disk)
672 signal together, which requires yet more buffers.
675 if (t->monitoring_choice() & monitor_choice) {
676 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
678 /* this line will change when the options are non-orthogonal */
679 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
683 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
684 rl = _session->get_routes ();
686 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
687 if (_route->route_group() && _route->route_group()->is_monitoring()) {
688 rl = _route->route_group()->route_list();
690 rl.reset (new RouteList);
691 rl->push_back (route());
694 rl.reset (new RouteList);
695 rl->push_back (route());
698 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
704 RouteUI::build_record_menu ()
710 /* no rec-button context menu for non-MIDI tracks
713 if (is_midi_track()) {
714 record_menu = new Menu;
715 record_menu->set_name ("ArdourContextMenu");
717 using namespace Menu_Helpers;
718 MenuList& items = record_menu->items();
720 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
721 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
723 if (_route->record_enabled()) {
724 step_edit_item->set_sensitive (false);
727 step_edit_item->set_active (midi_track()->step_editing());
732 RouteUI::toggle_step_edit ()
734 if (!is_midi_track() || _route->record_enabled()) {
738 midi_track()->set_step_editing (step_edit_item->get_active());
742 RouteUI::step_edit_changed (bool yn)
745 if (rec_enable_button) {
746 rec_enable_button->set_visual_state (3);
749 start_step_editing ();
751 if (step_edit_item) {
752 step_edit_item->set_active (true);
757 if (rec_enable_button) {
758 rec_enable_button->set_visual_state (0);
761 stop_step_editing ();
763 if (step_edit_item) {
764 step_edit_item->set_active (false);
770 RouteUI::rec_enable_release (GdkEventButton* ev)
772 if (Keyboard::is_context_menu_event (ev)) {
773 build_record_menu ();
775 record_menu->popup (1, ev->time);
784 RouteUI::build_sends_menu ()
786 using namespace Menu_Helpers;
788 sends_menu = new Menu;
789 sends_menu->set_name ("ArdourContextMenu");
790 MenuList& items = sends_menu->items();
793 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
797 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
801 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
805 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
809 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
813 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
816 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
820 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
823 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
824 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
825 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
830 RouteUI::create_sends (Placement p, bool include_buses)
832 _session->globally_add_internal_sends (_route, p, include_buses);
836 RouteUI::create_selected_sends (Placement p, bool include_buses)
838 boost::shared_ptr<RouteList> rlist (new RouteList);
839 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
841 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
842 RouteTimeAxisView* rtv;
844 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
845 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
846 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
847 rlist->push_back (rui->route());
853 _session->add_internal_sends (_route, p, rlist);
857 RouteUI::set_sends_gain_from_track ()
859 _session->globally_set_send_gains_from_track (_route);
863 RouteUI::set_sends_gain_to_zero ()
865 _session->globally_set_send_gains_to_zero (_route);
869 RouteUI::set_sends_gain_to_unity ()
871 _session->globally_set_send_gains_to_unity (_route);
875 RouteUI::show_sends_press(GdkEventButton* ev)
877 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
881 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
883 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
885 // do nothing on midi sigc::bind event
888 } else if (Keyboard::is_context_menu_event (ev)) {
890 if (sends_menu == 0) {
894 sends_menu->popup (0, ev->time);
898 /* change button state */
900 show_sends_button->set_active (!show_sends_button->get_active());
904 if (show_sends_button->get_active()) {
905 /* show sends to this bus */
906 MixerStrip::SwitchIO (_route);
907 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun(*this, &RouteUI::send_blink));
909 /* everybody back to normal */
910 send_blink_connection.disconnect ();
911 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
921 RouteUI::show_sends_release (GdkEventButton*)
927 RouteUI::send_blink (bool onoff)
929 if (!show_sends_button) {
934 show_sends_button->set_state (STATE_ACTIVE);
936 show_sends_button->set_state (STATE_NORMAL);
941 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
943 if (r->is_master() || r->is_monitor()) {
947 if (Config->get_solo_control_is_listen_control()) {
949 if (r->listening_via_monitor()) {
958 if (!r->self_soloed()) {
969 RouteUI::solo_visual_state_with_isolate (boost::shared_ptr<Route> r)
971 if (r->is_master() || r->is_monitor()) {
975 if (Config->get_solo_control_is_listen_control()) {
977 if (r->listening_via_monitor()) {
985 if (r->solo_isolated()) {
987 } else if (r->soloed()) {
988 if (!r->self_soloed()) {
999 RouteUI::solo_isolate_visual_state (boost::shared_ptr<Route> r)
1001 if (r->is_master() || r->is_monitor()) {
1005 if (r->solo_isolated()) {
1013 RouteUI::solo_safe_visual_state (boost::shared_ptr<Route> r)
1015 if (r->is_master() || r->is_monitor()) {
1019 if (r->solo_safe()) {
1027 RouteUI::update_solo_display ()
1031 if (Config->get_solo_control_is_listen_control()) {
1033 if (solo_button->get_active() != (x = _route->listening_via_monitor())) {
1034 ++_i_am_the_modifier;
1035 solo_button->set_active(x);
1036 --_i_am_the_modifier;
1041 if (solo_button->get_active() != (x = _route->soloed())) {
1042 ++_i_am_the_modifier;
1043 solo_button->set_active (x);
1044 --_i_am_the_modifier;
1049 bool yn = _route->solo_safe ();
1051 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1052 solo_safe_check->set_active (yn);
1055 yn = _route->solo_isolated ();
1057 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1058 solo_isolated_check->set_active (yn);
1061 set_button_names ();
1063 if (solo_isolated_led) {
1064 solo_isolated_led->set_visual_state (_route->solo_isolated() ? 1 : 0);
1067 if (solo_safe_led) {
1068 solo_safe_led->set_visual_state (_route->solo_safe() ? 1 : 0);
1071 solo_button->set_visual_state (solo_visual_state (_route));
1073 /* some changes to solo status can affect mute display, so catch up
1076 update_mute_display ();
1080 RouteUI::solo_changed_so_update_mute ()
1082 update_mute_display ();
1086 RouteUI::mute_changed(void* /*src*/)
1088 update_mute_display ();
1092 RouteUI::mute_visual_state (Session* s, boost::shared_ptr<Route> r)
1094 if (r->is_master() || r->is_monitor()) {
1099 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1104 } else if (s->soloing() && !r->soloed() && !r->solo_isolated()) {
1107 /* no mute at all */
1117 /* no mute at all */
1126 RouteUI::update_mute_display ()
1132 bool model = _route->muted();
1133 bool view = mute_button->get_active();
1135 /* first make sure the button's "depressed" visual
1139 if (model != view) {
1140 ++_i_am_the_modifier;
1141 mute_button->set_active (model);
1142 --_i_am_the_modifier;
1145 mute_button->set_visual_state (mute_visual_state (_session, _route));
1149 RouteUI::route_rec_enable_changed ()
1151 update_rec_display ();
1152 update_monitoring_display ();
1156 RouteUI::session_rec_enable_changed ()
1158 update_rec_display ();
1159 update_monitoring_display ();
1163 RouteUI::update_rec_display ()
1165 if (!rec_enable_button || !_route) {
1169 bool model = _route->record_enabled();
1170 bool view = rec_enable_button->get_active();
1172 /* first make sure the button's "depressed" visual
1176 if (model != view) {
1177 ++_i_am_the_modifier;
1178 rec_enable_button->set_active (model);
1179 --_i_am_the_modifier;
1182 /* now make sure its color state is correct */
1185 switch (_session->record_status ()) {
1186 case Session::Recording:
1187 rec_enable_button->set_visual_state (1);
1190 case Session::Disabled:
1191 case Session::Enabled:
1192 rec_enable_button->set_visual_state (2);
1197 if (step_edit_item) {
1198 step_edit_item->set_sensitive (false);
1202 rec_enable_button->set_visual_state (0);
1204 if (step_edit_item) {
1205 step_edit_item->set_sensitive (true);
1210 check_rec_enable_sensitivity ();
1214 RouteUI::build_solo_menu (void)
1216 using namespace Menu_Helpers;
1218 solo_menu = new Menu;
1219 solo_menu->set_name ("ArdourContextMenu");
1220 MenuList& items = solo_menu->items();
1221 CheckMenuItem* check;
1223 check = new CheckMenuItem(_("Solo Isolate"));
1224 check->set_active (_route->solo_isolated());
1225 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1226 items.push_back (CheckMenuElem(*check));
1227 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1230 check = new CheckMenuItem(_("Solo Safe"));
1231 check->set_active (_route->solo_safe());
1232 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1233 items.push_back (CheckMenuElem(*check));
1234 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1237 //items.push_back (SeparatorElem());
1238 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1243 RouteUI::build_mute_menu(void)
1245 using namespace Menu_Helpers;
1247 mute_menu = new Menu;
1248 mute_menu->set_name ("ArdourContextMenu");
1250 MenuList& items = mute_menu->items();
1252 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1253 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1254 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1255 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1256 pre_fader_mute_check->show_all();
1258 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1259 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1260 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1261 items.push_back (CheckMenuElem(*post_fader_mute_check));
1262 post_fader_mute_check->show_all();
1264 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1265 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1266 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1267 items.push_back (CheckMenuElem(*listen_mute_check));
1268 listen_mute_check->show_all();
1270 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1271 init_mute_menu(MuteMaster::Main, main_mute_check);
1272 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1273 items.push_back (CheckMenuElem(*main_mute_check));
1274 main_mute_check->show_all();
1276 //items.push_back (SeparatorElem());
1277 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1279 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1283 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1285 check->set_active (_route->mute_points() & mp);
1289 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1291 if (check->get_active()) {
1292 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1294 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1299 RouteUI::muting_change ()
1301 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1304 MuteMaster::MutePoint current = _route->mute_points ();
1306 yn = (current & MuteMaster::PreFader);
1308 if (pre_fader_mute_check->get_active() != yn) {
1309 pre_fader_mute_check->set_active (yn);
1312 yn = (current & MuteMaster::PostFader);
1314 if (post_fader_mute_check->get_active() != yn) {
1315 post_fader_mute_check->set_active (yn);
1318 yn = (current & MuteMaster::Listen);
1320 if (listen_mute_check->get_active() != yn) {
1321 listen_mute_check->set_active (yn);
1324 yn = (current & MuteMaster::Main);
1326 if (main_mute_check->get_active() != yn) {
1327 main_mute_check->set_active (yn);
1332 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1334 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1338 bool view = (solo_isolated_led->visual_state() != 0);
1339 bool model = _route->solo_isolated();
1341 /* called BEFORE the view has changed */
1343 if (ev->button == 1) {
1344 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1347 /* disable isolate for all routes */
1348 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1352 if (model == view) {
1354 /* flip just this route */
1356 boost::shared_ptr<RouteList> rl (new RouteList);
1357 rl->push_back (_route);
1358 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1367 RouteUI::solo_safe_button_release (GdkEventButton*)
1369 _route->set_solo_safe (!(solo_safe_led->visual_state() > 0), this);
1374 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1376 bool view = check->get_active();
1377 bool model = _route->solo_isolated();
1379 /* called AFTER the view has changed */
1381 if (model != view) {
1382 _route->set_solo_isolated (view, this);
1387 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1389 _route->set_solo_safe (check->get_active(), this);
1392 /** Ask the user to choose a colour, and then set all selected tracks
1396 RouteUI::choose_color ()
1399 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1402 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1403 boost::bind (&RouteUI::set_color, _1, color)
1408 /** Set the route's own color. This may not be used for display if
1409 * the route is in a group which shares its color with its routes.
1412 RouteUI::set_color (const Gdk::Color & c)
1418 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1420 /* note: we use the route state ID here so that color is the same for both
1421 the time axis view and the mixer strip
1424 gui_object_state().set<string> (route_state_id(), X_("color"), buf);
1425 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1428 /** @return GUI state ID for things that are common to the route in all its representations */
1430 RouteUI::route_state_id () const
1432 return string_compose (X_("route %1"), _route->id().to_s());
1436 RouteUI::set_color_from_route ()
1438 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1446 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1449 _color.set_green (g);
1450 _color.set_blue (b);
1456 RouteUI::remove_this_route (bool apply_to_selection)
1458 if (apply_to_selection) {
1459 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1461 if ((route()->is_master() || route()->is_monitor()) &&
1462 !Config->get_allow_special_bus_removal()) {
1463 MessageDialog msg (_("That would be bad news ...."),
1467 msg.set_secondary_text (string_compose (_(
1468 "Removing the master or monitor bus is such a bad idea\n\
1469 that %1 is not going to allow it.\n\
1471 If you really want to do this sort of thing\n\
1472 edit your ardour.rc file to set the\n\
1473 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1480 vector<string> choices;
1484 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());
1486 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());
1489 choices.push_back (_("No, do nothing."));
1490 choices.push_back (_("Yes, remove it."));
1494 title = _("Remove track");
1496 title = _("Remove bus");
1499 Choice prompter (title, prompt, choices);
1501 if (prompter.run () == 1) {
1502 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1508 RouteUI::idle_remove_this_route (RouteUI *rui)
1510 rui->_session->remove_route (rui->route());
1514 /** @return true if this name should be used for the route, otherwise false */
1516 RouteUI::verify_new_route_name (const std::string& name)
1518 if (name.find (':') == string::npos) {
1522 MessageDialog colon_msg (
1523 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1524 false, MESSAGE_QUESTION, BUTTONS_NONE
1527 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1528 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1530 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1534 RouteUI::route_rename ()
1536 ArdourPrompter name_prompter (true);
1541 name_prompter.set_title (_("Rename Track"));
1543 name_prompter.set_title (_("Rename Bus"));
1545 name_prompter.set_prompt (_("New name:"));
1546 name_prompter.set_initial_text (_route->name());
1547 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1548 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1549 name_prompter.show_all ();
1552 switch (name_prompter.run ()) {
1553 case Gtk::RESPONSE_ACCEPT:
1554 name_prompter.get_result (result);
1555 name_prompter.hide ();
1556 if (result.length()) {
1557 if (verify_new_route_name (result)) {
1558 _route->set_name (result);
1561 /* back to name prompter */
1565 /* nothing entered, just get out of here */
1577 RouteUI::property_changed (const PropertyChange& what_changed)
1579 if (what_changed.contains (ARDOUR::Properties::name)) {
1580 name_label.set_text (_route->name());
1585 RouteUI::set_route_active (bool a, bool apply_to_selection)
1587 if (apply_to_selection) {
1588 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1590 _route->set_active (a, this);
1595 RouteUI::toggle_denormal_protection ()
1597 if (denormal_menu_item) {
1601 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1603 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1604 _route->set_denormal_protection (x);
1610 RouteUI::denormal_protection_changed ()
1612 if (denormal_menu_item) {
1613 denormal_menu_item->set_active (_route->denormal_protection());
1618 RouteUI::disconnect_input ()
1620 _route->input()->disconnect (this);
1624 RouteUI::disconnect_output ()
1626 _route->output()->disconnect (this);
1630 RouteUI::is_track () const
1632 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1635 boost::shared_ptr<Track>
1636 RouteUI::track() const
1638 return boost::dynamic_pointer_cast<Track>(_route);
1642 RouteUI::is_audio_track () const
1644 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1647 boost::shared_ptr<AudioTrack>
1648 RouteUI::audio_track() const
1650 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1654 RouteUI::is_midi_track () const
1656 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1659 boost::shared_ptr<MidiTrack>
1660 RouteUI::midi_track() const
1662 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1666 RouteUI::has_audio_outputs () const
1668 return (_route->n_outputs().n_audio() > 0);
1672 RouteUI::name() const
1674 return _route->name();
1678 RouteUI::map_frozen ()
1680 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1682 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1685 switch (at->freeze_state()) {
1686 case AudioTrack::Frozen:
1687 rec_enable_button->set_sensitive (false);
1690 rec_enable_button->set_sensitive (true);
1697 RouteUI::adjust_latency ()
1699 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1703 RouteUI::save_as_template ()
1706 std::string safe_name;
1709 path = ARDOUR::user_route_template_directory ();
1711 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1712 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1716 Prompter p (true); // modal
1718 p.set_title (_("Save As Template"));
1719 p.set_prompt (_("Template name:"));
1720 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1722 case RESPONSE_ACCEPT:
1729 p.get_result (name, true);
1731 safe_name = legalize_for_path (name);
1732 safe_name += template_suffix;
1736 _route->save_as_template (path.to_string(), name);
1740 RouteUI::check_rec_enable_sensitivity ()
1742 if (_session->transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1743 rec_enable_button->set_sensitive (false);
1745 rec_enable_button->set_sensitive (true);
1748 update_monitoring_display ();
1752 RouteUI::parameter_changed (string const & p)
1754 /* this handles RC and per-session parameter changes */
1756 if (p == "disable-disarm-during-roll") {
1757 check_rec_enable_sensitivity ();
1758 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1759 set_button_names ();
1760 } else if (p == "auto-input") {
1761 update_monitoring_display ();
1766 RouteUI::step_gain_up ()
1768 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1772 RouteUI::page_gain_up ()
1774 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1778 RouteUI::step_gain_down ()
1780 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1784 RouteUI::page_gain_down ()
1786 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1790 RouteUI::open_remote_control_id_dialog ()
1792 ArdourDialog dialog (_("Remote Control ID"));
1794 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1796 HBox* hbox = manage (new HBox);
1797 hbox->set_spacing (6);
1798 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1799 SpinButton* spin = manage (new SpinButton);
1800 spin->set_digits (0);
1801 spin->set_increments (1, 10);
1802 spin->set_range (0, limit);
1803 spin->set_value (_route->remote_control_id());
1804 hbox->pack_start (*spin);
1805 dialog.get_vbox()->pack_start (*hbox);
1807 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1808 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1811 int const r = dialog.run ();
1813 if (r == RESPONSE_ACCEPT) {
1814 _route->set_remote_control_id (spin->get_value_as_int ());
1819 RouteUI::setup_invert_buttons ()
1821 /* remove old invert buttons */
1822 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1823 _invert_button_box.remove (**i);
1826 _invert_buttons.clear ();
1828 if (!_route || !_route->input()) {
1832 uint32_t const N = _route->input()->n_ports().n_audio ();
1834 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1836 for (uint32_t i = 0; i < to_add; ++i) {
1837 BindableToggleButton* b = manage (new BindableToggleButton);
1838 b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_toggled), i, b));
1839 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1841 b->set_name (X_("MixerInvertButton"));
1843 b->add (*manage (new Label (X_("Ø"))));
1845 b->add (*manage (new Label (string_compose (X_("Ø%1"), i + 1))));
1849 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));
1851 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));
1854 _invert_buttons.push_back (b);
1855 _invert_button_box.pack_start (*b);
1858 _invert_button_box.show_all ();
1862 RouteUI::set_invert_button_state ()
1864 ++_i_am_the_modifier;
1866 uint32_t const N = _route->input()->n_ports().n_audio();
1867 if (N > _max_invert_buttons) {
1868 _invert_buttons.front()->set_active (_route->phase_invert().any());
1869 --_i_am_the_modifier;
1874 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1875 (*i)->set_active (_route->phase_invert (j));
1878 --_i_am_the_modifier;
1882 RouteUI::invert_toggled (uint32_t i, BindableToggleButton* b)
1884 if (_i_am_the_modifier) {
1888 uint32_t const N = _route->input()->n_ports().n_audio();
1889 if (N <= _max_invert_buttons) {
1890 _route->set_phase_invert (i, b->get_active ());
1892 boost::dynamic_bitset<> p (N);
1893 if (b->get_active ()) {
1896 _route->set_phase_invert (p);
1901 RouteUI::invert_press (GdkEventButton* ev)
1903 using namespace Menu_Helpers;
1905 if (ev->button != 3) {
1909 delete _invert_menu;
1910 _invert_menu = new Menu;
1911 _invert_menu->set_name ("ArdourContextMenu");
1912 MenuList& items = _invert_menu->items ();
1914 uint32_t const N = _route->input()->n_ports().n_audio();
1915 for (uint32_t i = 0; i < N; ++i) {
1916 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1917 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1918 ++_i_am_the_modifier;
1919 e->set_active (_route->phase_invert (i));
1920 --_i_am_the_modifier;
1923 _invert_menu->popup (0, ev->time);
1929 RouteUI::invert_menu_toggled (uint32_t c)
1931 if (_i_am_the_modifier) {
1935 _route->set_phase_invert (c, !_route->phase_invert (c));
1939 RouteUI::set_invert_sensitive (bool yn)
1941 for (list<BindableToggleButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1942 (*b)->set_sensitive (yn);
1947 RouteUI::request_redraw ()
1950 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1954 /** The Route's gui_changed signal has been emitted */
1956 RouteUI::route_gui_changed (string what_changed)
1958 if (what_changed == "color") {
1959 if (set_color_from_route () == 0) {
1960 route_color_changed ();
1965 /** @return the color that this route should use; it maybe its own,
1966 or it maybe that of its route group.
1969 RouteUI::color () const
1971 RouteGroup* g = _route->route_group ();
1973 if (g && g->is_color()) {
1974 return GroupTabs::group_color (g);