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 ArdourButton);
116 // mute_button->set_self_managed (true);
117 mute_button->set_name ("mute button");
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 ("solo button");
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 ("record enable button");
130 rec_enable_button->add (rec_enable_button_label);
131 rec_enable_button_label.show ();
132 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
134 show_sends_button = manage (new ArdourButton);
135 show_sends_button->set_name ("send alert button");
136 // show_sends_button->set_self_managed (true);
137 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
139 monitor_input_button = manage (new ArdourButton (ArdourButton::led_default_elements));
140 monitor_input_button->set_name ("monitor");
141 monitor_input_button->set_text (_("In"));
142 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
143 monitor_input_button->set_no_show_all (true);
145 monitor_disk_button = manage (new ArdourButton (ArdourButton::led_default_elements));
146 monitor_disk_button->set_name ("monitor");
147 monitor_disk_button->set_text (_("Disk"));
148 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
149 monitor_disk_button->set_no_show_all (true);
151 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
152 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
153 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
155 _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
156 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
158 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
159 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
161 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
162 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
164 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
165 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
166 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
167 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
169 monitor_input_button->set_distinct_led_click (false);
170 monitor_disk_button->set_distinct_led_click (false);
172 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
173 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
175 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
176 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
182 route_connections.drop_connections ();
190 denormal_menu_item = 0;
194 RouteUI::self_delete ()
200 RouteUI::set_route (boost::shared_ptr<Route> rp)
206 if (set_color_from_route()) {
207 set_color (unique_random_color());
211 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
214 mute_button->set_controllable (_route->mute_control());
215 solo_button->set_controllable (_route->solo_control());
217 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
218 _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
220 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
221 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
222 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
223 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
225 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
226 _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
228 _route->io_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::setup_invert_buttons, this), gui_context ());
229 _route->gui_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
231 if (_session->writable() && is_track()) {
232 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
234 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
236 rec_enable_button->show();
237 rec_enable_button->set_controllable (t->rec_enable_control());
239 update_rec_display ();
241 if (is_midi_track()) {
242 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
243 ui_bind (&RouteUI::step_edit_changed, this, _1), gui_context());
249 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
250 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
252 update_monitoring_display ();
255 mute_button->unset_flags (Gtk::CAN_FOCUS);
256 solo_button->unset_flags (Gtk::CAN_FOCUS);
260 if (_route->is_monitor()) {
261 solo_button->hide ();
268 setup_invert_buttons ();
269 set_invert_button_state ();
273 RouteUI::polarity_changed ()
279 set_invert_button_state ();
283 RouteUI::mute_press (GdkEventButton* ev)
285 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
289 multiple_mute_change = false;
291 if (!_i_am_the_modifier) {
293 if (Keyboard::is_context_menu_event (ev)) {
299 mute_menu->popup(0,ev->time);
303 if (Keyboard::is_button2_event (ev)) {
304 // Primary-button2 click is the midi binding click
305 // button2-click is "momentary"
308 if (mute_button->on_button_press_event (ev)) {
312 _mute_release = new SoloMuteRelease (_route->muted ());
315 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
317 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
320 _mute_release->routes = _session->get_routes ();
323 _session->set_mute (_session->get_routes(), !_route->muted());
325 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
327 /* Primary-button1 applies change to the mix group even if it is not active
328 NOTE: Primary-button2 is MIDI learn.
331 if (ev->button == 1 && _route->route_group()) {
333 _mute_release->routes = _session->get_routes ();
336 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
341 /* plain click applies change to this route */
343 boost::shared_ptr<RouteList> rl (new RouteList);
344 rl->push_back (_route);
347 _mute_release->routes = rl;
350 _session->set_mute (rl, !_route->muted());
362 RouteUI::mute_release (GdkEventButton*)
364 if (!_i_am_the_modifier) {
366 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
367 delete _mute_release;
376 RouteUI::solo_press(GdkEventButton* ev)
378 /* ignore double/triple clicks */
380 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
384 multiple_solo_change = false;
386 if (!_i_am_the_modifier) {
388 if (Keyboard::is_context_menu_event (ev)) {
390 if (!solo_isolated_led) {
392 if (solo_menu == 0) {
396 solo_menu->popup (1, ev->time);
401 if (Keyboard::is_button2_event (ev)) {
403 // Primary-button2 click is the midi binding click
404 // button2-click is "momentary"
406 if (solo_button->on_button_press_event (ev)) {
410 _solo_release = new SoloMuteRelease (_route->self_soloed());
413 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
415 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
417 /* Primary-Tertiary-click applies change to all routes */
420 _solo_release->routes = _session->get_routes ();
423 if (Config->get_solo_control_is_listen_control()) {
424 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
426 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
429 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
431 // Primary-Secondary-click: exclusively solo this track
434 _solo_release->exclusive = true;
436 boost::shared_ptr<RouteList> routes = _session->get_routes();
438 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
439 if ((*i)->soloed ()) {
440 _solo_release->routes_on->push_back (*i);
442 _solo_release->routes_off->push_back (*i);
447 if (Config->get_solo_control_is_listen_control()) {
448 /* ??? we need a just_one_listen() method */
450 _session->set_just_one_solo (_route, true);
453 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
455 // shift-click: toggle solo isolated status
457 _route->set_solo_isolated (!_route->solo_isolated(), this);
458 delete _solo_release;
461 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
463 /* Primary-button1: solo mix group.
464 NOTE: Primary-button2 is MIDI learn.
467 if (ev->button == 1 && _route->route_group()) {
470 _solo_release->routes = _route->route_group()->route_list();
473 if (Config->get_solo_control_is_listen_control()) {
474 _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
476 _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
482 /* click: solo this route */
484 boost::shared_ptr<RouteList> rl (new RouteList);
485 rl->push_back (route());
488 _solo_release->routes = rl;
491 if (Config->get_solo_control_is_listen_control()) {
492 _session->set_listen (rl, !_route->listening_via_monitor());
494 _session->set_solo (rl, !_route->self_soloed());
505 RouteUI::solo_release (GdkEventButton*)
507 if (!_i_am_the_modifier) {
511 if (_solo_release->exclusive) {
514 if (Config->get_solo_control_is_listen_control()) {
515 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
517 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
521 delete _solo_release;
530 RouteUI::rec_enable_press(GdkEventButton* ev)
532 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
536 if (!_session->engine().connected()) {
537 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
542 if (is_midi_track()) {
544 /* cannot rec-enable while step-editing */
546 if (midi_track()->step_editing()) {
551 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
553 if (Keyboard::is_button2_event (ev)) {
555 // do nothing on midi sigc::bind event
556 return rec_enable_button->on_button_press_event (ev);
558 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
560 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->get_active());
562 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
564 /* Primary-button1 applies change to the route group (even if it is not active)
565 NOTE: Primary-button2 is MIDI learn.
567 if (ev->button == 1 && _route->route_group()) {
568 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->get_active(), Session::rt_cleanup, true);
571 } else if (Keyboard::is_context_menu_event (ev)) {
573 /* do this on release */
577 boost::shared_ptr<RouteList> rl (new RouteList);
578 rl->push_back (route());
579 _session->set_record_enabled (rl, !rec_enable_button->get_active());
587 RouteUI::monitoring_changed ()
589 update_monitoring_display ();
593 RouteUI::update_monitoring_display ()
599 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
605 MonitorState ms = t->monitoring_state();
607 if (t->monitoring_choice() & MonitorInput) {
608 monitor_input_button->set_active_state (Gtkmm2ext::Active);
610 if (ms & MonitoringInput) {
611 monitor_input_button->set_active_state (Gtkmm2ext::Mid);
613 monitor_input_button->unset_active_state ();
617 if (t->monitoring_choice() & MonitorDisk) {
618 monitor_disk_button->set_active_state (Gtkmm2ext::Active);
620 if (ms & MonitoringDisk) {
621 monitor_disk_button->set_active_state (Gtkmm2ext::Mid);
623 monitor_disk_button->unset_active_state ();
629 RouteUI::monitor_input_press(GdkEventButton* ev)
635 RouteUI::monitor_input_release(GdkEventButton* ev)
637 return monitor_release (ev, MonitorInput);
641 RouteUI::monitor_disk_press (GdkEventButton* ev)
647 RouteUI::monitor_disk_release (GdkEventButton* ev)
649 return monitor_release (ev, MonitorDisk);
653 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
655 if (ev->button != 1) {
659 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
666 boost::shared_ptr<RouteList> rl;
668 /* XXX for now, monitoring choices are orthogonal. cue monitoring
669 will follow in 3.X but requires mixing the input and playback (disk)
670 signal together, which requires yet more buffers.
673 if (t->monitoring_choice() & monitor_choice) {
674 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
676 /* this line will change when the options are non-orthogonal */
677 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
681 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
682 rl = _session->get_routes ();
684 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
685 if (_route->route_group() && _route->route_group()->is_monitoring()) {
686 rl = _route->route_group()->route_list();
688 rl.reset (new RouteList);
689 rl->push_back (route());
692 rl.reset (new RouteList);
693 rl->push_back (route());
696 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
702 RouteUI::build_record_menu ()
708 /* no rec-button context menu for non-MIDI tracks
711 if (is_midi_track()) {
712 record_menu = new Menu;
713 record_menu->set_name ("ArdourContextMenu");
715 using namespace Menu_Helpers;
716 MenuList& items = record_menu->items();
718 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
719 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
721 if (_route->record_enabled()) {
722 step_edit_item->set_sensitive (false);
725 step_edit_item->set_active (midi_track()->step_editing());
730 RouteUI::toggle_step_edit ()
732 if (!is_midi_track() || _route->record_enabled()) {
736 midi_track()->set_step_editing (step_edit_item->get_active());
740 RouteUI::step_edit_changed (bool yn)
743 if (rec_enable_button) {
744 rec_enable_button->set_visual_state (3);
747 start_step_editing ();
749 if (step_edit_item) {
750 step_edit_item->set_active (true);
755 if (rec_enable_button) {
756 rec_enable_button->set_visual_state (0);
759 stop_step_editing ();
761 if (step_edit_item) {
762 step_edit_item->set_active (false);
768 RouteUI::rec_enable_release (GdkEventButton* ev)
770 if (Keyboard::is_context_menu_event (ev)) {
771 build_record_menu ();
773 record_menu->popup (1, ev->time);
782 RouteUI::build_sends_menu ()
784 using namespace Menu_Helpers;
786 sends_menu = new Menu;
787 sends_menu->set_name ("ArdourContextMenu");
788 MenuList& items = sends_menu->items();
791 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
795 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
799 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
803 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
807 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
811 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
814 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
818 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
821 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
822 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
823 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
828 RouteUI::create_sends (Placement p, bool include_buses)
830 _session->globally_add_internal_sends (_route, p, include_buses);
834 RouteUI::create_selected_sends (Placement p, bool include_buses)
836 boost::shared_ptr<RouteList> rlist (new RouteList);
837 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
839 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
840 RouteTimeAxisView* rtv;
842 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
843 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
844 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
845 rlist->push_back (rui->route());
851 _session->add_internal_sends (_route, p, rlist);
855 RouteUI::set_sends_gain_from_track ()
857 _session->globally_set_send_gains_from_track (_route);
861 RouteUI::set_sends_gain_to_zero ()
863 _session->globally_set_send_gains_to_zero (_route);
867 RouteUI::set_sends_gain_to_unity ()
869 _session->globally_set_send_gains_to_unity (_route);
873 RouteUI::show_sends_press(GdkEventButton* ev)
875 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
879 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
881 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
883 // do nothing on midi sigc::bind event
886 } else if (Keyboard::is_context_menu_event (ev)) {
888 if (sends_menu == 0) {
892 sends_menu->popup (0, ev->time);
896 /* change button state */
898 show_sends_button->set_active_state (Active);
902 if (show_sends_button->active_state()) {
903 /* show sends to this bus */
904 MixerStrip::SwitchIO (_route);
905 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun(*this, &RouteUI::send_blink));
907 /* everybody back to normal */
908 send_blink_connection.disconnect ();
909 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
919 RouteUI::show_sends_release (GdkEventButton*)
925 RouteUI::send_blink (bool onoff)
927 if (!show_sends_button) {
932 show_sends_button->set_state (STATE_ACTIVE);
934 show_sends_button->set_state (STATE_NORMAL);
939 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
941 if (r->is_master() || r->is_monitor()) {
945 if (Config->get_solo_control_is_listen_control()) {
947 if (r->listening_via_monitor()) {
956 if (!r->self_soloed()) {
967 RouteUI::solo_visual_state_with_isolate (boost::shared_ptr<Route> r)
969 if (r->is_master() || r->is_monitor()) {
973 if (Config->get_solo_control_is_listen_control()) {
975 if (r->listening_via_monitor()) {
983 if (r->solo_isolated()) {
985 } else if (r->soloed()) {
986 if (!r->self_soloed()) {
997 RouteUI::solo_isolate_visual_state (boost::shared_ptr<Route> r)
999 if (r->is_master() || r->is_monitor()) {
1003 if (r->solo_isolated()) {
1011 RouteUI::solo_safe_visual_state (boost::shared_ptr<Route> r)
1013 if (r->is_master() || r->is_monitor()) {
1017 if (r->solo_safe()) {
1025 RouteUI::update_solo_display ()
1029 if (Config->get_solo_control_is_listen_control()) {
1031 if (solo_button->get_active() != (x = _route->listening_via_monitor())) {
1032 ++_i_am_the_modifier;
1033 solo_button->set_active(x);
1034 --_i_am_the_modifier;
1039 if (solo_button->get_active() != (x = _route->soloed())) {
1040 ++_i_am_the_modifier;
1041 solo_button->set_active (x);
1042 --_i_am_the_modifier;
1047 bool yn = _route->solo_safe ();
1049 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1050 solo_safe_check->set_active (yn);
1053 yn = _route->solo_isolated ();
1055 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1056 solo_isolated_check->set_active (yn);
1059 set_button_names ();
1061 if (solo_isolated_led) {
1062 if (_route->solo_isolated()) {
1063 solo_isolated_led->set_active_state (Gtkmm2ext::Active);
1065 solo_isolated_led->unset_active_state ();
1069 if (solo_safe_led) {
1070 if (_route->solo_safe()) {
1071 solo_safe_led->set_active_state (Gtkmm2ext::Active);
1073 solo_safe_led->unset_active_state ();
1077 solo_button->set_visual_state (solo_visual_state (_route));
1079 /* some changes to solo status can affect mute display, so catch up
1082 update_mute_display ();
1086 RouteUI::solo_changed_so_update_mute ()
1088 update_mute_display ();
1092 RouteUI::mute_changed(void* /*src*/)
1094 update_mute_display ();
1098 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1100 if (r->is_master() || r->is_monitor()) {
1101 return ActiveState(0);
1105 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1110 } else if (s->soloing() && !r->soloed() && !r->solo_isolated()) {
1113 /* no mute at all */
1114 return ActiveState(0);
1123 /* no mute at all */
1124 return ActiveState(0);
1128 return ActiveState(0);
1132 RouteUI::update_mute_display ()
1138 mute_button->set_active_state (mute_active_state (_session, _route));
1142 RouteUI::route_rec_enable_changed ()
1144 update_rec_display ();
1145 update_monitoring_display ();
1149 RouteUI::session_rec_enable_changed ()
1151 update_rec_display ();
1152 update_monitoring_display ();
1156 RouteUI::update_rec_display ()
1158 if (!rec_enable_button || !_route) {
1162 bool model = _route->record_enabled();
1163 bool view = rec_enable_button->get_active();
1165 /* first make sure the button's "depressed" visual
1169 if (model != view) {
1170 ++_i_am_the_modifier;
1171 rec_enable_button->set_active (model);
1172 --_i_am_the_modifier;
1175 /* now make sure its color state is correct */
1178 switch (_session->record_status ()) {
1179 case Session::Recording:
1180 rec_enable_button->set_visual_state (1);
1183 case Session::Disabled:
1184 case Session::Enabled:
1185 rec_enable_button->set_visual_state (2);
1190 if (step_edit_item) {
1191 step_edit_item->set_sensitive (false);
1195 rec_enable_button->set_visual_state (0);
1197 if (step_edit_item) {
1198 step_edit_item->set_sensitive (true);
1203 check_rec_enable_sensitivity ();
1207 RouteUI::build_solo_menu (void)
1209 using namespace Menu_Helpers;
1211 solo_menu = new Menu;
1212 solo_menu->set_name ("ArdourContextMenu");
1213 MenuList& items = solo_menu->items();
1214 CheckMenuItem* check;
1216 check = new CheckMenuItem(_("Solo Isolate"));
1217 check->set_active (_route->solo_isolated());
1218 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1219 items.push_back (CheckMenuElem(*check));
1220 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1223 check = new CheckMenuItem(_("Solo Safe"));
1224 check->set_active (_route->solo_safe());
1225 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1226 items.push_back (CheckMenuElem(*check));
1227 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1230 //items.push_back (SeparatorElem());
1231 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1236 RouteUI::build_mute_menu(void)
1238 using namespace Menu_Helpers;
1240 mute_menu = new Menu;
1241 mute_menu->set_name ("ArdourContextMenu");
1243 MenuList& items = mute_menu->items();
1245 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1246 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1247 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1248 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1249 pre_fader_mute_check->show_all();
1251 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1252 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1253 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1254 items.push_back (CheckMenuElem(*post_fader_mute_check));
1255 post_fader_mute_check->show_all();
1257 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1258 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1259 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1260 items.push_back (CheckMenuElem(*listen_mute_check));
1261 listen_mute_check->show_all();
1263 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1264 init_mute_menu(MuteMaster::Main, main_mute_check);
1265 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1266 items.push_back (CheckMenuElem(*main_mute_check));
1267 main_mute_check->show_all();
1269 //items.push_back (SeparatorElem());
1270 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1272 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1276 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1278 check->set_active (_route->mute_points() & mp);
1282 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1284 if (check->get_active()) {
1285 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1287 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1292 RouteUI::muting_change ()
1294 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1297 MuteMaster::MutePoint current = _route->mute_points ();
1299 yn = (current & MuteMaster::PreFader);
1301 if (pre_fader_mute_check->get_active() != yn) {
1302 pre_fader_mute_check->set_active (yn);
1305 yn = (current & MuteMaster::PostFader);
1307 if (post_fader_mute_check->get_active() != yn) {
1308 post_fader_mute_check->set_active (yn);
1311 yn = (current & MuteMaster::Listen);
1313 if (listen_mute_check->get_active() != yn) {
1314 listen_mute_check->set_active (yn);
1317 yn = (current & MuteMaster::Main);
1319 if (main_mute_check->get_active() != yn) {
1320 main_mute_check->set_active (yn);
1325 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1327 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1331 bool view = solo_isolated_led->active_state();
1332 bool model = _route->solo_isolated();
1334 /* called BEFORE the view has changed */
1336 if (ev->button == 1) {
1337 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1340 /* disable isolate for all routes */
1341 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1345 if (model == view) {
1347 /* flip just this route */
1349 boost::shared_ptr<RouteList> rl (new RouteList);
1350 rl->push_back (_route);
1351 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1360 RouteUI::solo_safe_button_release (GdkEventButton*)
1362 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1367 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1369 bool view = check->get_active();
1370 bool model = _route->solo_isolated();
1372 /* called AFTER the view has changed */
1374 if (model != view) {
1375 _route->set_solo_isolated (view, this);
1380 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1382 _route->set_solo_safe (check->get_active(), this);
1385 /** Ask the user to choose a colour, and then set all selected tracks
1389 RouteUI::choose_color ()
1392 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1395 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1396 boost::bind (&RouteUI::set_color, _1, color)
1401 /** Set the route's own color. This may not be used for display if
1402 * the route is in a group which shares its color with its routes.
1405 RouteUI::set_color (const Gdk::Color & c)
1411 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1413 /* note: we use the route state ID here so that color is the same for both
1414 the time axis view and the mixer strip
1417 gui_object_state().set<string> (route_state_id(), X_("color"), buf);
1418 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1421 /** @return GUI state ID for things that are common to the route in all its representations */
1423 RouteUI::route_state_id () const
1425 return string_compose (X_("route %1"), _route->id().to_s());
1429 RouteUI::set_color_from_route ()
1431 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1439 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1442 _color.set_green (g);
1443 _color.set_blue (b);
1449 RouteUI::remove_this_route (bool apply_to_selection)
1451 if (apply_to_selection) {
1452 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1454 if ((route()->is_master() || route()->is_monitor()) &&
1455 !Config->get_allow_special_bus_removal()) {
1456 MessageDialog msg (_("That would be bad news ...."),
1460 msg.set_secondary_text (string_compose (_(
1461 "Removing the master or monitor bus is such a bad idea\n\
1462 that %1 is not going to allow it.\n\
1464 If you really want to do this sort of thing\n\
1465 edit your ardour.rc file to set the\n\
1466 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1473 vector<string> choices;
1477 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());
1479 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());
1482 choices.push_back (_("No, do nothing."));
1483 choices.push_back (_("Yes, remove it."));
1487 title = _("Remove track");
1489 title = _("Remove bus");
1492 Choice prompter (title, prompt, choices);
1494 if (prompter.run () == 1) {
1495 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1501 RouteUI::idle_remove_this_route (RouteUI *rui)
1503 rui->_session->remove_route (rui->route());
1507 /** @return true if this name should be used for the route, otherwise false */
1509 RouteUI::verify_new_route_name (const std::string& name)
1511 if (name.find (':') == string::npos) {
1515 MessageDialog colon_msg (
1516 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1517 false, MESSAGE_QUESTION, BUTTONS_NONE
1520 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1521 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1523 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1527 RouteUI::route_rename ()
1529 ArdourPrompter name_prompter (true);
1534 name_prompter.set_title (_("Rename Track"));
1536 name_prompter.set_title (_("Rename Bus"));
1538 name_prompter.set_prompt (_("New name:"));
1539 name_prompter.set_initial_text (_route->name());
1540 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1541 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1542 name_prompter.show_all ();
1545 switch (name_prompter.run ()) {
1546 case Gtk::RESPONSE_ACCEPT:
1547 name_prompter.get_result (result);
1548 name_prompter.hide ();
1549 if (result.length()) {
1550 if (verify_new_route_name (result)) {
1551 _route->set_name (result);
1554 /* back to name prompter */
1558 /* nothing entered, just get out of here */
1570 RouteUI::property_changed (const PropertyChange& what_changed)
1572 if (what_changed.contains (ARDOUR::Properties::name)) {
1573 name_label.set_text (_route->name());
1578 RouteUI::set_route_active (bool a, bool apply_to_selection)
1580 if (apply_to_selection) {
1581 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1583 _route->set_active (a, this);
1588 RouteUI::toggle_denormal_protection ()
1590 if (denormal_menu_item) {
1594 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1596 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1597 _route->set_denormal_protection (x);
1603 RouteUI::denormal_protection_changed ()
1605 if (denormal_menu_item) {
1606 denormal_menu_item->set_active (_route->denormal_protection());
1611 RouteUI::disconnect_input ()
1613 _route->input()->disconnect (this);
1617 RouteUI::disconnect_output ()
1619 _route->output()->disconnect (this);
1623 RouteUI::is_track () const
1625 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1628 boost::shared_ptr<Track>
1629 RouteUI::track() const
1631 return boost::dynamic_pointer_cast<Track>(_route);
1635 RouteUI::is_audio_track () const
1637 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1640 boost::shared_ptr<AudioTrack>
1641 RouteUI::audio_track() const
1643 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1647 RouteUI::is_midi_track () const
1649 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1652 boost::shared_ptr<MidiTrack>
1653 RouteUI::midi_track() const
1655 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1659 RouteUI::has_audio_outputs () const
1661 return (_route->n_outputs().n_audio() > 0);
1665 RouteUI::name() const
1667 return _route->name();
1671 RouteUI::map_frozen ()
1673 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1675 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1678 switch (at->freeze_state()) {
1679 case AudioTrack::Frozen:
1680 rec_enable_button->set_sensitive (false);
1683 rec_enable_button->set_sensitive (true);
1690 RouteUI::adjust_latency ()
1692 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1696 RouteUI::save_as_template ()
1699 std::string safe_name;
1702 path = ARDOUR::user_route_template_directory ();
1704 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1705 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1709 Prompter p (true); // modal
1711 p.set_title (_("Save As Template"));
1712 p.set_prompt (_("Template name:"));
1713 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1715 case RESPONSE_ACCEPT:
1722 p.get_result (name, true);
1724 safe_name = legalize_for_path (name);
1725 safe_name += template_suffix;
1729 _route->save_as_template (path.to_string(), name);
1733 RouteUI::check_rec_enable_sensitivity ()
1735 if (_session->transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1736 rec_enable_button->set_sensitive (false);
1738 rec_enable_button->set_sensitive (true);
1741 update_monitoring_display ();
1745 RouteUI::parameter_changed (string const & p)
1747 /* this handles RC and per-session parameter changes */
1749 if (p == "disable-disarm-during-roll") {
1750 check_rec_enable_sensitivity ();
1751 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1752 set_button_names ();
1753 } else if (p == "auto-input") {
1754 update_monitoring_display ();
1759 RouteUI::step_gain_up ()
1761 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1765 RouteUI::page_gain_up ()
1767 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1771 RouteUI::step_gain_down ()
1773 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1777 RouteUI::page_gain_down ()
1779 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1783 RouteUI::open_remote_control_id_dialog ()
1785 ArdourDialog dialog (_("Remote Control ID"));
1787 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1789 HBox* hbox = manage (new HBox);
1790 hbox->set_spacing (6);
1791 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1792 SpinButton* spin = manage (new SpinButton);
1793 spin->set_digits (0);
1794 spin->set_increments (1, 10);
1795 spin->set_range (0, limit);
1796 spin->set_value (_route->remote_control_id());
1797 hbox->pack_start (*spin);
1798 dialog.get_vbox()->pack_start (*hbox);
1800 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1801 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1804 int const r = dialog.run ();
1806 if (r == RESPONSE_ACCEPT) {
1807 _route->set_remote_control_id (spin->get_value_as_int ());
1812 RouteUI::setup_invert_buttons ()
1814 /* remove old invert buttons */
1815 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1816 _invert_button_box.remove (**i);
1819 _invert_buttons.clear ();
1821 if (!_route || !_route->input()) {
1825 uint32_t const N = _route->input()->n_ports().n_audio ();
1827 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1829 for (uint32_t i = 0; i < to_add; ++i) {
1830 BindableToggleButton* b = manage (new BindableToggleButton);
1831 b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_toggled), i, b));
1832 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1834 b->set_name (X_("MixerInvertButton"));
1836 b->add (*manage (new Label (X_("Ø"))));
1838 b->add (*manage (new Label (string_compose (X_("Ø%1"), i + 1))));
1842 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));
1844 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));
1847 _invert_buttons.push_back (b);
1848 _invert_button_box.pack_start (*b);
1851 _invert_button_box.show_all ();
1855 RouteUI::set_invert_button_state ()
1857 ++_i_am_the_modifier;
1859 uint32_t const N = _route->input()->n_ports().n_audio();
1860 if (N > _max_invert_buttons) {
1861 _invert_buttons.front()->set_active (_route->phase_invert().any());
1862 --_i_am_the_modifier;
1867 for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1868 (*i)->set_active (_route->phase_invert (j));
1871 --_i_am_the_modifier;
1875 RouteUI::invert_toggled (uint32_t i, BindableToggleButton* b)
1877 if (_i_am_the_modifier) {
1881 uint32_t const N = _route->input()->n_ports().n_audio();
1882 if (N <= _max_invert_buttons) {
1883 _route->set_phase_invert (i, b->get_active ());
1885 boost::dynamic_bitset<> p (N);
1886 if (b->get_active ()) {
1889 _route->set_phase_invert (p);
1894 RouteUI::invert_press (GdkEventButton* ev)
1896 using namespace Menu_Helpers;
1898 if (ev->button != 3) {
1902 delete _invert_menu;
1903 _invert_menu = new Menu;
1904 _invert_menu->set_name ("ArdourContextMenu");
1905 MenuList& items = _invert_menu->items ();
1907 uint32_t const N = _route->input()->n_ports().n_audio();
1908 for (uint32_t i = 0; i < N; ++i) {
1909 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1910 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1911 ++_i_am_the_modifier;
1912 e->set_active (_route->phase_invert (i));
1913 --_i_am_the_modifier;
1916 _invert_menu->popup (0, ev->time);
1922 RouteUI::invert_menu_toggled (uint32_t c)
1924 if (_i_am_the_modifier) {
1928 _route->set_phase_invert (c, !_route->phase_invert (c));
1932 RouteUI::set_invert_sensitive (bool yn)
1934 for (list<BindableToggleButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1935 (*b)->set_sensitive (yn);
1940 RouteUI::request_redraw ()
1943 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1947 /** The Route's gui_changed signal has been emitted */
1949 RouteUI::route_gui_changed (string what_changed)
1951 if (what_changed == "color") {
1952 if (set_color_from_route () == 0) {
1953 route_color_changed ();
1958 /** @return the color that this route should use; it maybe its own,
1959 or it maybe that of its route group.
1962 RouteUI::color () const
1964 RouteGroup* g = _route->route_group ();
1966 if (g && g->is_color()) {
1967 return GroupTabs::group_color (g);