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;
67 sigc::signal<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
68 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
70 RouteUI::RouteUI (ARDOUR::Session* sess)
78 _route.reset (); /* drop reference to route, so that it can be cleaned up */
79 route_connections.drop_connections ();
97 pre_fader_mute_check = 0;
98 post_fader_mute_check = 0;
99 listen_mute_check = 0;
102 solo_isolated_check = 0;
103 solo_isolated_led = 0;
107 denormal_menu_item = 0;
109 multiple_mute_change = false;
110 multiple_solo_change = false;
111 _i_am_the_modifier = 0;
113 setup_invert_buttons ();
115 mute_button = manage (new ArdourButton);
116 mute_button->set_name ("mute button");
117 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
119 solo_button = manage (new ArdourButton);
120 solo_button->set_name ("solo button");
121 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
122 solo_button->set_no_show_all (true);
124 rec_enable_button = manage (new ArdourButton);
125 rec_enable_button->set_name ("record enable button");
126 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
128 show_sends_button = manage (new ArdourButton);
129 show_sends_button->set_name ("send alert button");
130 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
132 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
133 monitor_input_button->set_name ("monitor button");
134 monitor_input_button->set_text (_("In"));
135 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
136 monitor_input_button->set_no_show_all (true);
138 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
139 monitor_disk_button->set_name ("monitor button");
140 monitor_disk_button->set_text (_("Disk"));
141 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
142 monitor_disk_button->set_no_show_all (true);
144 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
145 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
146 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
148 _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
149 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
151 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
152 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
154 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
155 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
157 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
158 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
159 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
160 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
162 monitor_input_button->set_distinct_led_click (false);
163 monitor_disk_button->set_distinct_led_click (false);
165 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
166 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
168 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
169 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
171 BusSendDisplayChanged.connect (sigc::mem_fun (*this, &RouteUI::bus_send_display_changed));
177 route_connections.drop_connections ();
185 denormal_menu_item = 0;
189 RouteUI::self_delete ()
195 RouteUI::set_route (boost::shared_ptr<Route> rp)
201 if (set_color_from_route()) {
202 set_color (unique_random_color());
206 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
209 mute_button->set_controllable (_route->mute_control());
210 solo_button->set_controllable (_route->solo_control());
212 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
213 _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
215 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
216 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
217 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
218 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
220 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
221 _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
223 _route->io_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::setup_invert_buttons, this), gui_context ());
224 _route->gui_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
226 if (_session->writable() && is_track()) {
227 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
229 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
231 rec_enable_button->show();
232 rec_enable_button->set_controllable (t->rec_enable_control());
234 update_rec_display ();
236 if (is_midi_track()) {
237 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
238 ui_bind (&RouteUI::step_edit_changed, this, _1), gui_context());
244 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
245 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
247 update_monitoring_display ();
250 mute_button->unset_flags (Gtk::CAN_FOCUS);
251 solo_button->unset_flags (Gtk::CAN_FOCUS);
255 if (_route->is_monitor()) {
256 solo_button->hide ();
263 setup_invert_buttons ();
264 set_invert_button_state ();
266 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
267 bus_send_display_changed (s);
269 update_mute_display ();
270 update_solo_display ();
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 && solo_isolated_led->is_visible()) ||
392 ! (solo_safe_led && solo_safe_led->is_visible())) {
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 /* rec-enable button exits from step editing */
548 if (midi_track()->step_editing()) {
549 midi_track()->set_step_editing (false);
554 if (!_i_am_the_modifier && is_track() && rec_enable_button) {
556 if (Keyboard::is_button2_event (ev)) {
558 // do nothing on midi sigc::bind event
559 return rec_enable_button->on_button_press_event (ev);
561 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
563 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
565 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
567 /* Primary-button1 applies change to the route group (even if it is not active)
568 NOTE: Primary-button2 is MIDI learn.
570 if (ev->button == 1 && _route->route_group()) {
571 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->active_state(), Session::rt_cleanup, true);
574 } else if (Keyboard::is_context_menu_event (ev)) {
576 /* do this on release */
580 boost::shared_ptr<RouteList> rl (new RouteList);
581 rl->push_back (route());
582 _session->set_record_enabled (rl, !rec_enable_button->active_state());
590 RouteUI::monitoring_changed ()
592 update_monitoring_display ();
596 RouteUI::update_monitoring_display ()
602 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
608 MonitorState ms = t->monitoring_state();
610 if (t->monitoring_choice() & MonitorInput) {
611 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
613 if (ms & MonitoringInput) {
614 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
616 monitor_input_button->unset_active_state ();
620 if (t->monitoring_choice() & MonitorDisk) {
621 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
623 if (ms & MonitoringDisk) {
624 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
626 monitor_disk_button->unset_active_state ();
632 RouteUI::monitor_input_press(GdkEventButton* ev)
638 RouteUI::monitor_input_release(GdkEventButton* ev)
640 return monitor_release (ev, MonitorInput);
644 RouteUI::monitor_disk_press (GdkEventButton* ev)
650 RouteUI::monitor_disk_release (GdkEventButton* ev)
652 return monitor_release (ev, MonitorDisk);
656 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
658 if (ev->button != 1) {
662 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
669 boost::shared_ptr<RouteList> rl;
671 /* XXX for now, monitoring choices are orthogonal. cue monitoring
672 will follow in 3.X but requires mixing the input and playback (disk)
673 signal together, which requires yet more buffers.
676 if (t->monitoring_choice() & monitor_choice) {
677 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
679 /* this line will change when the options are non-orthogonal */
680 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
684 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
685 rl = _session->get_routes ();
687 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
688 if (_route->route_group() && _route->route_group()->is_monitoring()) {
689 rl = _route->route_group()->route_list();
691 rl.reset (new RouteList);
692 rl->push_back (route());
695 rl.reset (new RouteList);
696 rl->push_back (route());
699 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
705 RouteUI::build_record_menu ()
711 /* no rec-button context menu for non-MIDI tracks
714 if (is_midi_track()) {
715 record_menu = new Menu;
716 record_menu->set_name ("ArdourContextMenu");
718 using namespace Menu_Helpers;
719 MenuList& items = record_menu->items();
721 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
722 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
724 if (_route->record_enabled()) {
725 step_edit_item->set_sensitive (false);
728 step_edit_item->set_active (midi_track()->step_editing());
733 RouteUI::toggle_step_edit ()
735 if (!is_midi_track() || _route->record_enabled()) {
739 midi_track()->set_step_editing (step_edit_item->get_active());
743 RouteUI::step_edit_changed (bool yn)
746 if (rec_enable_button) {
747 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
750 start_step_editing ();
752 if (step_edit_item) {
753 step_edit_item->set_active (true);
758 if (rec_enable_button) {
759 rec_enable_button->unset_active_state ();
762 stop_step_editing ();
764 if (step_edit_item) {
765 step_edit_item->set_active (false);
771 RouteUI::rec_enable_release (GdkEventButton* ev)
773 if (Keyboard::is_context_menu_event (ev)) {
774 build_record_menu ();
776 record_menu->popup (1, ev->time);
785 RouteUI::build_sends_menu ()
787 using namespace Menu_Helpers;
789 sends_menu = new Menu;
790 sends_menu->set_name ("ArdourContextMenu");
791 MenuList& items = sends_menu->items();
794 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
798 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
802 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
806 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
810 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
814 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
817 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
821 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
824 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
825 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
826 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
831 RouteUI::create_sends (Placement p, bool include_buses)
833 _session->globally_add_internal_sends (_route, p, include_buses);
837 RouteUI::create_selected_sends (Placement p, bool include_buses)
839 boost::shared_ptr<RouteList> rlist (new RouteList);
840 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
842 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
843 RouteTimeAxisView* rtv;
845 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
846 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
847 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
848 rlist->push_back (rui->route());
854 _session->add_internal_sends (_route, p, rlist);
858 RouteUI::set_sends_gain_from_track ()
860 _session->globally_set_send_gains_from_track (_route);
864 RouteUI::set_sends_gain_to_zero ()
866 _session->globally_set_send_gains_to_zero (_route);
870 RouteUI::set_sends_gain_to_unity ()
872 _session->globally_set_send_gains_to_unity (_route);
876 RouteUI::show_sends_press(GdkEventButton* ev)
878 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
882 if (!_i_am_the_modifier && !is_track() && show_sends_button) {
884 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
886 // do nothing on midi sigc::bind event
889 } else if (Keyboard::is_context_menu_event (ev)) {
891 if (sends_menu == 0) {
895 sends_menu->popup (0, ev->time);
899 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
902 set_showing_sends_to (boost::shared_ptr<Route> ());
904 set_showing_sends_to (_route);
913 RouteUI::show_sends_release (GdkEventButton*)
919 RouteUI::send_blink (bool onoff)
921 if (!show_sends_button) {
926 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
928 show_sends_button->unset_active_state ();
932 Gtkmm2ext::ActiveState
933 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
935 if (r->is_master() || r->is_monitor()) {
936 return Gtkmm2ext::Off;
939 if (Config->get_solo_control_is_listen_control()) {
941 if (r->listening_via_monitor()) {
942 return Gtkmm2ext::ExplicitActive;
944 return Gtkmm2ext::Off;
950 if (!r->self_soloed()) {
951 return Gtkmm2ext::ImplicitActive;
953 return Gtkmm2ext::ExplicitActive;
956 return Gtkmm2ext::Off;
960 Gtkmm2ext::ActiveState
961 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
963 if (r->is_master() || r->is_monitor()) {
964 return Gtkmm2ext::Off;
967 if (r->solo_isolated()) {
968 return Gtkmm2ext::ExplicitActive;
970 return Gtkmm2ext::Off;
974 Gtkmm2ext::ActiveState
975 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
977 if (r->is_master() || r->is_monitor()) {
978 return Gtkmm2ext::Off;
981 if (r->solo_safe()) {
982 return Gtkmm2ext::ExplicitActive;
984 return Gtkmm2ext::Off;
989 RouteUI::update_solo_display ()
991 bool yn = _route->solo_safe ();
993 if (solo_safe_check && solo_safe_check->get_active() != yn) {
994 solo_safe_check->set_active (yn);
997 yn = _route->solo_isolated ();
999 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1000 solo_isolated_check->set_active (yn);
1003 set_button_names ();
1005 if (solo_isolated_led) {
1006 if (_route->solo_isolated()) {
1007 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1009 solo_isolated_led->unset_active_state ();
1013 if (solo_safe_led) {
1014 if (_route->solo_safe()) {
1015 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1017 solo_safe_led->unset_active_state ();
1021 solo_button->set_active_state (solo_active_state (_route));
1023 /* some changes to solo status can affect mute display, so catch up
1026 update_mute_display ();
1030 RouteUI::solo_changed_so_update_mute ()
1032 update_mute_display ();
1036 RouteUI::mute_changed(void* /*src*/)
1038 update_mute_display ();
1042 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1044 if (r->is_monitor()) {
1045 return ActiveState(0);
1049 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1053 return Gtkmm2ext::ExplicitActive;
1054 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1055 /* master is NEVER muted by others */
1056 return Gtkmm2ext::ImplicitActive;
1058 /* no mute at all */
1059 return Gtkmm2ext::Off;
1066 return Gtkmm2ext::ExplicitActive;
1068 /* no mute at all */
1069 return Gtkmm2ext::Off;
1073 return ActiveState(0);
1077 RouteUI::update_mute_display ()
1083 mute_button->set_active_state (mute_active_state (_session, _route));
1087 RouteUI::route_rec_enable_changed ()
1089 update_rec_display ();
1090 update_monitoring_display ();
1094 RouteUI::session_rec_enable_changed ()
1096 update_rec_display ();
1097 update_monitoring_display ();
1101 RouteUI::update_rec_display ()
1103 if (!rec_enable_button || !_route) {
1107 if (_route->record_enabled()) {
1108 switch (_session->record_status ()) {
1109 case Session::Recording:
1110 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1113 case Session::Disabled:
1114 case Session::Enabled:
1115 rec_enable_button->set_active_state (Gtkmm2ext::ImplicitActive);
1120 if (step_edit_item) {
1121 step_edit_item->set_sensitive (false);
1125 rec_enable_button->unset_active_state ();
1127 if (step_edit_item) {
1128 step_edit_item->set_sensitive (true);
1133 check_rec_enable_sensitivity ();
1137 RouteUI::build_solo_menu (void)
1139 using namespace Menu_Helpers;
1141 solo_menu = new Menu;
1142 solo_menu->set_name ("ArdourContextMenu");
1143 MenuList& items = solo_menu->items();
1144 CheckMenuItem* check;
1146 check = new CheckMenuItem(_("Solo Isolate"));
1147 check->set_active (_route->solo_isolated());
1148 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1149 items.push_back (CheckMenuElem(*check));
1150 solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1153 check = new CheckMenuItem(_("Solo Safe"));
1154 check->set_active (_route->solo_safe());
1155 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1156 items.push_back (CheckMenuElem(*check));
1157 solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1160 //items.push_back (SeparatorElem());
1161 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1166 RouteUI::build_mute_menu(void)
1168 using namespace Menu_Helpers;
1170 mute_menu = new Menu;
1171 mute_menu->set_name ("ArdourContextMenu");
1173 MenuList& items = mute_menu->items();
1175 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1176 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1177 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1178 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1179 pre_fader_mute_check->show_all();
1181 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1182 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1183 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1184 items.push_back (CheckMenuElem(*post_fader_mute_check));
1185 post_fader_mute_check->show_all();
1187 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1188 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1189 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1190 items.push_back (CheckMenuElem(*listen_mute_check));
1191 listen_mute_check->show_all();
1193 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1194 init_mute_menu(MuteMaster::Main, main_mute_check);
1195 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1196 items.push_back (CheckMenuElem(*main_mute_check));
1197 main_mute_check->show_all();
1199 //items.push_back (SeparatorElem());
1200 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1202 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1206 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1208 check->set_active (_route->mute_points() & mp);
1212 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1214 if (check->get_active()) {
1215 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1217 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1222 RouteUI::muting_change ()
1224 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1227 MuteMaster::MutePoint current = _route->mute_points ();
1229 yn = (current & MuteMaster::PreFader);
1231 if (pre_fader_mute_check->get_active() != yn) {
1232 pre_fader_mute_check->set_active (yn);
1235 yn = (current & MuteMaster::PostFader);
1237 if (post_fader_mute_check->get_active() != yn) {
1238 post_fader_mute_check->set_active (yn);
1241 yn = (current & MuteMaster::Listen);
1243 if (listen_mute_check->get_active() != yn) {
1244 listen_mute_check->set_active (yn);
1247 yn = (current & MuteMaster::Main);
1249 if (main_mute_check->get_active() != yn) {
1250 main_mute_check->set_active (yn);
1255 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1257 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1261 bool view = solo_isolated_led->active_state();
1262 bool model = _route->solo_isolated();
1264 /* called BEFORE the view has changed */
1266 if (ev->button == 1) {
1267 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1270 /* disable isolate for all routes */
1271 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1275 if (model == view) {
1277 /* flip just this route */
1279 boost::shared_ptr<RouteList> rl (new RouteList);
1280 rl->push_back (_route);
1281 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1290 RouteUI::solo_safe_button_release (GdkEventButton*)
1292 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1297 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1299 bool view = check->get_active();
1300 bool model = _route->solo_isolated();
1302 /* called AFTER the view has changed */
1304 if (model != view) {
1305 _route->set_solo_isolated (view, this);
1310 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1312 _route->set_solo_safe (check->get_active(), this);
1315 /** Ask the user to choose a colour, and then set all selected tracks
1319 RouteUI::choose_color ()
1322 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1325 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1326 boost::bind (&RouteUI::set_color, _1, color)
1331 /** Set the route's own color. This may not be used for display if
1332 * the route is in a group which shares its color with its routes.
1335 RouteUI::set_color (const Gdk::Color & c)
1341 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1343 /* note: we use the route state ID here so that color is the same for both
1344 the time axis view and the mixer strip
1347 gui_object_state().set<string> (route_state_id(), X_("color"), buf);
1348 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1351 /** @return GUI state ID for things that are common to the route in all its representations */
1353 RouteUI::route_state_id () const
1355 return string_compose (X_("route %1"), _route->id().to_s());
1359 RouteUI::set_color_from_route ()
1361 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1369 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1372 _color.set_green (g);
1373 _color.set_blue (b);
1379 RouteUI::remove_this_route (bool apply_to_selection)
1381 if (apply_to_selection) {
1382 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1384 if ((route()->is_master() || route()->is_monitor()) &&
1385 !Config->get_allow_special_bus_removal()) {
1386 MessageDialog msg (_("That would be bad news ...."),
1390 msg.set_secondary_text (string_compose (_(
1391 "Removing the master or monitor bus is such a bad idea\n\
1392 that %1 is not going to allow it.\n\
1394 If you really want to do this sort of thing\n\
1395 edit your ardour.rc file to set the\n\
1396 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1403 vector<string> choices;
1407 prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1409 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1412 choices.push_back (_("No, do nothing."));
1413 choices.push_back (_("Yes, remove it."));
1417 title = _("Remove track");
1419 title = _("Remove bus");
1422 Choice prompter (title, prompt, choices);
1424 if (prompter.run () == 1) {
1425 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1431 RouteUI::idle_remove_this_route (RouteUI *rui)
1433 rui->_session->remove_route (rui->route());
1437 /** @return true if this name should be used for the route, otherwise false */
1439 RouteUI::verify_new_route_name (const std::string& name)
1441 if (name.find (':') == string::npos) {
1445 MessageDialog colon_msg (
1446 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1447 false, MESSAGE_QUESTION, BUTTONS_NONE
1450 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1451 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1453 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1457 RouteUI::route_rename ()
1459 ArdourPrompter name_prompter (true);
1464 name_prompter.set_title (_("Rename Track"));
1466 name_prompter.set_title (_("Rename Bus"));
1468 name_prompter.set_prompt (_("New name:"));
1469 name_prompter.set_initial_text (_route->name());
1470 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1471 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1472 name_prompter.show_all ();
1475 switch (name_prompter.run ()) {
1476 case Gtk::RESPONSE_ACCEPT:
1477 name_prompter.get_result (result);
1478 name_prompter.hide ();
1479 if (result.length()) {
1480 if (verify_new_route_name (result)) {
1481 _route->set_name (result);
1484 /* back to name prompter */
1488 /* nothing entered, just get out of here */
1503 RouteUI::property_changed (const PropertyChange& what_changed)
1505 if (what_changed.contains (ARDOUR::Properties::name)) {
1506 name_label.set_text (_route->name());
1511 RouteUI::set_route_active (bool a, bool apply_to_selection)
1513 if (apply_to_selection) {
1514 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1516 _route->set_active (a, this);
1521 RouteUI::toggle_denormal_protection ()
1523 if (denormal_menu_item) {
1527 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1529 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1530 _route->set_denormal_protection (x);
1536 RouteUI::denormal_protection_changed ()
1538 if (denormal_menu_item) {
1539 denormal_menu_item->set_active (_route->denormal_protection());
1544 RouteUI::disconnect_input ()
1546 _route->input()->disconnect (this);
1550 RouteUI::disconnect_output ()
1552 _route->output()->disconnect (this);
1556 RouteUI::is_track () const
1558 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1561 boost::shared_ptr<Track>
1562 RouteUI::track() const
1564 return boost::dynamic_pointer_cast<Track>(_route);
1568 RouteUI::is_audio_track () const
1570 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1573 boost::shared_ptr<AudioTrack>
1574 RouteUI::audio_track() const
1576 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1580 RouteUI::is_midi_track () const
1582 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1585 boost::shared_ptr<MidiTrack>
1586 RouteUI::midi_track() const
1588 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1592 RouteUI::has_audio_outputs () const
1594 return (_route->n_outputs().n_audio() > 0);
1598 RouteUI::name() const
1600 return _route->name();
1604 RouteUI::map_frozen ()
1606 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1608 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1611 switch (at->freeze_state()) {
1612 case AudioTrack::Frozen:
1613 rec_enable_button->set_sensitive (false);
1616 rec_enable_button->set_sensitive (true);
1623 RouteUI::adjust_latency ()
1625 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1629 RouteUI::save_as_template ()
1632 std::string safe_name;
1635 path = ARDOUR::user_route_template_directory ();
1637 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1638 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1642 Prompter p (true); // modal
1644 p.set_title (_("Save As Template"));
1645 p.set_prompt (_("Template name:"));
1646 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1648 case RESPONSE_ACCEPT:
1655 p.get_result (name, true);
1657 safe_name = legalize_for_path (name);
1658 safe_name += template_suffix;
1662 _route->save_as_template (path.to_string(), name);
1666 RouteUI::check_rec_enable_sensitivity ()
1668 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1669 rec_enable_button->set_sensitive (false);
1671 rec_enable_button->set_sensitive (true);
1674 update_monitoring_display ();
1678 RouteUI::parameter_changed (string const & p)
1680 /* this handles RC and per-session parameter changes */
1682 if (p == "disable-disarm-during-roll") {
1683 check_rec_enable_sensitivity ();
1684 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1685 set_button_names ();
1686 } else if (p == "auto-input") {
1687 update_monitoring_display ();
1692 RouteUI::step_gain_up ()
1694 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1698 RouteUI::page_gain_up ()
1700 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1704 RouteUI::step_gain_down ()
1706 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1710 RouteUI::page_gain_down ()
1712 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1716 RouteUI::open_remote_control_id_dialog ()
1718 ArdourDialog dialog (_("Remote Control ID"));
1720 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1722 HBox* hbox = manage (new HBox);
1723 hbox->set_spacing (6);
1724 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1725 SpinButton* spin = manage (new SpinButton);
1726 spin->set_digits (0);
1727 spin->set_increments (1, 10);
1728 spin->set_range (0, limit);
1729 spin->set_value (_route->remote_control_id());
1730 hbox->pack_start (*spin);
1731 dialog.get_vbox()->pack_start (*hbox);
1733 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1734 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1737 int const r = dialog.run ();
1739 if (r == RESPONSE_ACCEPT) {
1740 _route->set_remote_control_id (spin->get_value_as_int ());
1745 RouteUI::setup_invert_buttons ()
1747 /* remove old invert buttons */
1748 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1749 _invert_button_box.remove (**i);
1752 _invert_buttons.clear ();
1754 if (!_route || !_route->input()) {
1758 uint32_t const N = _route->input()->n_ports().n_audio ();
1760 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1762 for (uint32_t i = 0; i < to_add; ++i) {
1763 ArdourButton* b = manage (new ArdourButton);
1764 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1765 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
1767 b->set_name (X_("mixer strip button"));
1770 b->set_text (string_compose (X_("Ø (%1)"), N));
1772 b->set_text (X_("Ø"));
1775 b->set_text (string_compose (X_("Ø%1"), i + 1));
1778 if (N <= _max_invert_buttons) {
1779 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));
1781 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
1784 _invert_buttons.push_back (b);
1785 _invert_button_box.pack_start (*b);
1788 _invert_button_box.set_spacing (1);
1789 _invert_button_box.show_all ();
1793 RouteUI::set_invert_button_state ()
1795 ++_i_am_the_modifier;
1797 uint32_t const N = _route->input()->n_ports().n_audio();
1798 if (N > _max_invert_buttons) {
1800 /* One button for many channels; explicit active if all channels are inverted,
1801 implicit active if some are, off if none are.
1804 ArdourButton* b = _invert_buttons.front ();
1806 if (_route->phase_invert().count() == _route->phase_invert().size()) {
1807 b->set_active_state (Gtkmm2ext::ExplicitActive);
1808 } else if (_route->phase_invert().any()) {
1809 b->set_active_state (Gtkmm2ext::ImplicitActive);
1811 b->set_active_state (Gtkmm2ext::Off);
1816 /* One button per channel; just set active */
1819 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1820 (*i)->set_active (_route->phase_invert (j));
1825 --_i_am_the_modifier;
1829 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
1831 if (ev->button == 1 && i < _invert_buttons.size()) {
1832 uint32_t const N = _route->input()->n_ports().n_audio ();
1833 if (N <= _max_invert_buttons) {
1834 /* left-click inverts phase so long as we have a button per channel */
1835 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
1844 RouteUI::invert_press (GdkEventButton* ev)
1846 using namespace Menu_Helpers;
1848 uint32_t const N = _route->input()->n_ports().n_audio();
1849 if (N <= _max_invert_buttons && ev->button != 3) {
1850 /* If we have an invert button per channel, we only pop
1851 up a menu on right-click; left click is handled
1857 delete _invert_menu;
1858 _invert_menu = new Menu;
1859 _invert_menu->set_name ("ArdourContextMenu");
1860 MenuList& items = _invert_menu->items ();
1862 for (uint32_t i = 0; i < N; ++i) {
1863 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1864 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1865 ++_i_am_the_modifier;
1866 e->set_active (_route->phase_invert (i));
1867 --_i_am_the_modifier;
1870 _invert_menu->popup (0, ev->time);
1876 RouteUI::invert_menu_toggled (uint32_t c)
1878 if (_i_am_the_modifier) {
1882 _route->set_phase_invert (c, !_route->phase_invert (c));
1886 RouteUI::set_invert_sensitive (bool yn)
1888 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1889 (*b)->set_sensitive (yn);
1894 RouteUI::request_redraw ()
1897 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1901 /** The Route's gui_changed signal has been emitted */
1903 RouteUI::route_gui_changed (string what_changed)
1905 if (what_changed == "color") {
1906 if (set_color_from_route () == 0) {
1907 route_color_changed ();
1912 /** @return the color that this route should use; it maybe its own,
1913 or it maybe that of its route group.
1916 RouteUI::color () const
1918 RouteGroup* g = _route->route_group ();
1920 if (g && g->is_color()) {
1921 return GroupTabs::group_color (g);
1928 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
1930 _showing_sends_to = send_to;
1931 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
1935 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1937 if (_route == send_to) {
1938 show_sends_button->set_active (true);
1939 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
1941 show_sends_button->set_active (false);
1942 send_blink_connection.disconnect ();
1947 RouteUI::route_group() const
1949 return _route->route_group();