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/audio_track.h"
50 #include "ardour/audioengine.h"
51 #include "ardour/filename_extensions.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/route.h"
54 #include "ardour/session.h"
55 #include "ardour/template_utils.h"
59 using namespace Gtkmm2ext;
60 using namespace ARDOUR;
61 using namespace ARDOUR_UI_UTILS;
64 uint32_t RouteUI::_max_invert_buttons = 3;
65 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
66 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
68 RouteUI::RouteUI (ARDOUR::Session* sess)
82 _route.reset (); /* drop reference to route, so that it can be cleaned up */
83 route_connections.drop_connections ();
90 delete comment_window;
102 pre_fader_mute_check = 0;
103 post_fader_mute_check = 0;
104 listen_mute_check = 0;
107 solo_isolated_check = 0;
108 solo_isolated_led = 0;
112 denormal_menu_item = 0;
114 multiple_mute_change = false;
115 multiple_solo_change = false;
116 _i_am_the_modifier = 0;
118 setup_invert_buttons ();
120 mute_button = manage (new ArdourButton);
121 mute_button->set_name ("mute button");
122 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
124 solo_button = manage (new ArdourButton);
125 solo_button->set_name ("solo button");
126 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
127 solo_button->set_no_show_all (true);
129 rec_enable_button = manage (new ArdourButton);
130 rec_enable_button->set_name ("record enable button");
131 // rec_enable_button->set_tweaks (ArdourButton::ImplicitUsesSolidColor);
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 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
138 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
139 monitor_input_button->set_name ("monitor button");
140 monitor_input_button->set_text (_("In"));
141 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
142 monitor_input_button->set_no_show_all (true);
144 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
145 monitor_disk_button->set_name ("monitor button");
146 monitor_disk_button->set_text (_("Disk"));
147 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
148 monitor_disk_button->set_no_show_all (true);
150 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
151 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
152 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
154 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
155 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
157 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
158 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
160 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
161 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
163 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
164 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
165 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
166 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
168 monitor_input_button->set_distinct_led_click (false);
169 monitor_disk_button->set_distinct_led_click (false);
171 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
172 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
174 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
175 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
177 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
183 route_connections.drop_connections ();
191 denormal_menu_item = 0;
195 RouteUI::self_delete ()
201 RouteUI::set_route (boost::shared_ptr<Route> rp)
207 if (set_color_from_route()) {
208 set_color (unique_random_color());
212 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
215 mute_button->set_controllable (_route->mute_control());
216 solo_button->set_controllable (_route->solo_control());
218 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
219 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::mute_changed, this, _1), gui_context());
221 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this, _1), gui_context());
223 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
224 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
225 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
226 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
228 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
229 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
231 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
232 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
234 if (_session->writable() && is_track()) {
235 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
237 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
239 rec_enable_button->show();
240 rec_enable_button->set_controllable (t->rec_enable_control());
242 if (is_midi_track()) {
243 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
244 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
249 /* this will work for busses and tracks, and needs to be called to
250 set up the name entry/name label display.
253 update_rec_display ();
256 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
257 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
259 update_monitoring_display ();
262 mute_button->unset_flags (Gtk::CAN_FOCUS);
263 solo_button->unset_flags (Gtk::CAN_FOCUS);
267 if (_route->is_monitor() || _route->is_master()) {
268 solo_button->hide ();
275 setup_invert_buttons ();
276 set_invert_button_state ();
278 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
279 bus_send_display_changed (s);
281 update_mute_display ();
282 update_solo_display ();
286 RouteUI::polarity_changed ()
292 set_invert_button_state ();
296 RouteUI::mute_press (GdkEventButton* ev)
298 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
302 multiple_mute_change = false;
304 if (Keyboard::is_context_menu_event (ev)) {
310 mute_menu->popup(0,ev->time);
314 if (Keyboard::is_button2_event (ev)) {
315 // Primary-button2 click is the midi binding click
316 // button2-click is "momentary"
319 if (mute_button->on_button_press_event (ev)) {
323 _mute_release = new SoloMuteRelease (_route->muted ());
326 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
328 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
330 /* toggle mute on everything (but
331 * exclude the master and monitor)
333 * because we are going to erase
334 * elements of the list we need to work
338 boost::shared_ptr<RouteList> copy (new RouteList);
340 *copy = *_session->get_routes ();
342 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
343 if ((*i)->is_master() || (*i)->is_monitor()) {
351 _mute_release->routes = copy;
355 _session->set_mute (copy, !_route->muted());
357 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
359 /* Primary-button1 applies change to the mix group even if it is not active
360 NOTE: Primary-button2 is MIDI learn.
363 boost::shared_ptr<RouteList> rl;
365 if (ev->button == 1) {
367 if (_route->route_group()) {
369 rl = _route->route_group()->route_list();
372 _mute_release->routes = rl;
375 rl.reset (new RouteList);
376 rl->push_back (_route);
380 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, true);
385 /* plain click applies change to this route */
387 boost::shared_ptr<RouteList> rl (new RouteList);
388 rl->push_back (_route);
391 _mute_release->routes = rl;
394 _session->set_mute (rl, !_route->muted());
404 RouteUI::mute_release (GdkEventButton*)
408 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
409 delete _mute_release;
417 RouteUI::solo_press(GdkEventButton* ev)
419 /* ignore double/triple clicks */
421 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
425 multiple_solo_change = false;
427 if (Keyboard::is_context_menu_event (ev)) {
429 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
430 ! (solo_safe_led && solo_safe_led->is_visible())) {
432 if (solo_menu == 0) {
436 solo_menu->popup (1, ev->time);
441 if (Keyboard::is_button2_event (ev)) {
443 // Primary-button2 click is the midi binding click
444 // button2-click is "momentary"
446 if (solo_button->on_button_press_event (ev)) {
450 _solo_release = new SoloMuteRelease (_route->self_soloed());
453 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
455 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
457 /* Primary-Tertiary-click applies change to all routes */
460 _solo_release->routes = _session->get_routes ();
464 if (Config->get_solo_control_is_listen_control()) {
465 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
467 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
470 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
472 // Primary-Secondary-click: exclusively solo this track
475 _solo_release->exclusive = true;
477 boost::shared_ptr<RouteList> routes = _session->get_routes();
479 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
480 if ((*i)->soloed ()) {
481 _solo_release->routes_on->push_back (*i);
483 _solo_release->routes_off->push_back (*i);
488 if (Config->get_solo_control_is_listen_control()) {
489 /* ??? we need a just_one_listen() method */
492 _session->set_just_one_solo (_route, true);
495 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
497 // shift-click: toggle solo isolated status
499 _route->set_solo_isolated (!_route->solo_isolated(), this);
500 delete _solo_release;
503 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
505 /* Primary-button1: solo mix group.
506 NOTE: Primary-button2 is MIDI learn.
509 /* Primary-button1 applies change to the mix group even if it is not active
510 NOTE: Primary-button2 is MIDI learn.
513 boost::shared_ptr<RouteList> rl;
515 if (ev->button == 1) {
517 if (_route->route_group()) {
519 rl = _route->route_group()->route_list();
522 _solo_release->routes = rl;
525 rl.reset (new RouteList);
526 rl->push_back (_route);
530 if (Config->get_solo_control_is_listen_control()) {
531 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, true);
533 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, true);
539 /* click: solo this route */
541 boost::shared_ptr<RouteList> rl (new RouteList);
542 rl->push_back (route());
545 _solo_release->routes = rl;
549 if (Config->get_solo_control_is_listen_control()) {
550 _session->set_listen (rl, !_route->listening_via_monitor());
552 _session->set_solo (rl, !_route->self_soloed());
562 RouteUI::solo_release (GdkEventButton*)
566 if (_solo_release->exclusive) {
570 if (Config->get_solo_control_is_listen_control()) {
571 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
573 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
577 delete _solo_release;
585 RouteUI::rec_enable_press(GdkEventButton* ev)
587 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
591 if (!_session->engine().connected()) {
592 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
597 if (is_midi_track()) {
599 /* rec-enable button exits from step editing */
601 if (midi_track()->step_editing()) {
602 midi_track()->set_step_editing (false);
607 if (is_track() && rec_enable_button) {
609 if (Keyboard::is_button2_event (ev)) {
611 // do nothing on midi sigc::bind event
612 return rec_enable_button->on_button_press_event (ev);
614 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
617 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
619 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
621 /* Primary-button1 applies change to the route group (even if it is not active)
622 NOTE: Primary-button2 is MIDI learn.
625 if (ev->button == 1) {
627 boost::shared_ptr<RouteList> rl;
629 if (_route->route_group()) {
631 rl = _route->route_group()->route_list();
634 rl.reset (new RouteList);
635 rl->push_back (_route);
639 _session->set_record_enabled (rl, !rec_enable_button->active_state(), Session::rt_cleanup, true);
642 } else if (Keyboard::is_context_menu_event (ev)) {
644 /* do this on release */
648 boost::shared_ptr<RouteList> rl (new RouteList);
649 rl->push_back (route());
651 _session->set_record_enabled (rl, !rec_enable_button->active_state());
659 RouteUI::monitoring_changed ()
661 update_monitoring_display ();
665 RouteUI::update_monitoring_display ()
671 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
677 MonitorState ms = t->monitoring_state();
679 if (t->monitoring_choice() & MonitorInput) {
680 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
682 if (ms & MonitoringInput) {
683 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
685 monitor_input_button->unset_active_state ();
689 if (t->monitoring_choice() & MonitorDisk) {
690 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
692 if (ms & MonitoringDisk) {
693 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
695 monitor_disk_button->unset_active_state ();
701 RouteUI::monitor_input_press(GdkEventButton*)
707 RouteUI::monitor_input_release(GdkEventButton* ev)
709 return monitor_release (ev, MonitorInput);
713 RouteUI::monitor_disk_press (GdkEventButton*)
719 RouteUI::monitor_disk_release (GdkEventButton* ev)
721 return monitor_release (ev, MonitorDisk);
725 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
727 if (ev->button != 1) {
731 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
738 boost::shared_ptr<RouteList> rl;
740 /* XXX for now, monitoring choices are orthogonal. cue monitoring
741 will follow in 3.X but requires mixing the input and playback (disk)
742 signal together, which requires yet more buffers.
745 if (t->monitoring_choice() & monitor_choice) {
746 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
748 /* this line will change when the options are non-orthogonal */
749 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
753 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
754 rl = _session->get_routes ();
756 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
757 if (_route->route_group() && _route->route_group()->is_monitoring()) {
758 rl = _route->route_group()->route_list();
760 rl.reset (new RouteList);
761 rl->push_back (route());
764 rl.reset (new RouteList);
765 rl->push_back (route());
769 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
775 RouteUI::build_record_menu ()
781 /* no rec-button context menu for non-MIDI tracks
784 if (is_midi_track()) {
785 record_menu = new Menu;
786 record_menu->set_name ("ArdourContextMenu");
788 using namespace Menu_Helpers;
789 MenuList& items = record_menu->items();
791 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
792 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
794 if (_route->record_enabled()) {
795 step_edit_item->set_sensitive (false);
798 step_edit_item->set_active (midi_track()->step_editing());
803 RouteUI::toggle_step_edit ()
805 if (!is_midi_track() || _route->record_enabled()) {
809 midi_track()->set_step_editing (step_edit_item->get_active());
813 RouteUI::step_edit_changed (bool yn)
816 if (rec_enable_button) {
817 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
820 start_step_editing ();
822 if (step_edit_item) {
823 step_edit_item->set_active (true);
828 if (rec_enable_button) {
829 rec_enable_button->unset_active_state ();
832 stop_step_editing ();
834 if (step_edit_item) {
835 step_edit_item->set_active (false);
841 RouteUI::rec_enable_release (GdkEventButton* ev)
843 if (Keyboard::is_context_menu_event (ev)) {
844 build_record_menu ();
846 record_menu->popup (1, ev->time);
855 RouteUI::build_sends_menu ()
857 using namespace Menu_Helpers;
859 sends_menu = new Menu;
860 sends_menu->set_name ("ArdourContextMenu");
861 MenuList& items = sends_menu->items();
864 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
868 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
872 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
876 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
880 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
884 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
887 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
891 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
894 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
895 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
896 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
901 RouteUI::create_sends (Placement p, bool include_buses)
903 _session->globally_add_internal_sends (_route, p, include_buses);
907 RouteUI::create_selected_sends (Placement p, bool include_buses)
909 boost::shared_ptr<RouteList> rlist (new RouteList);
910 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
912 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
913 RouteTimeAxisView* rtv;
915 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
916 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
917 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
918 rlist->push_back (rui->route());
924 _session->add_internal_sends (_route, p, rlist);
928 RouteUI::set_sends_gain_from_track ()
930 _session->globally_set_send_gains_from_track (_route);
934 RouteUI::set_sends_gain_to_zero ()
936 _session->globally_set_send_gains_to_zero (_route);
940 RouteUI::set_sends_gain_to_unity ()
942 _session->globally_set_send_gains_to_unity (_route);
946 RouteUI::show_sends_press(GdkEventButton* ev)
948 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
952 if (!is_track() && show_sends_button) {
954 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
956 // do nothing on midi sigc::bind event
959 } else if (Keyboard::is_context_menu_event (ev)) {
961 if (sends_menu == 0) {
965 sends_menu->popup (0, ev->time);
969 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
972 set_showing_sends_to (boost::shared_ptr<Route> ());
974 set_showing_sends_to (_route);
983 RouteUI::show_sends_release (GdkEventButton*)
989 RouteUI::send_blink (bool onoff)
991 if (!show_sends_button) {
996 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
998 show_sends_button->unset_active_state ();
1002 Gtkmm2ext::ActiveState
1003 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1005 if (r->is_master() || r->is_monitor()) {
1006 return Gtkmm2ext::Off;
1009 if (Config->get_solo_control_is_listen_control()) {
1011 if (r->listening_via_monitor()) {
1012 return Gtkmm2ext::ExplicitActive;
1014 return Gtkmm2ext::Off;
1020 if (!r->self_soloed()) {
1021 return Gtkmm2ext::ImplicitActive;
1023 return Gtkmm2ext::ExplicitActive;
1026 return Gtkmm2ext::Off;
1030 Gtkmm2ext::ActiveState
1031 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1033 if (r->is_master() || r->is_monitor()) {
1034 return Gtkmm2ext::Off;
1037 if (r->solo_isolated()) {
1038 return Gtkmm2ext::ExplicitActive;
1040 return Gtkmm2ext::Off;
1044 Gtkmm2ext::ActiveState
1045 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1047 if (r->is_master() || r->is_monitor()) {
1048 return Gtkmm2ext::Off;
1051 if (r->solo_safe()) {
1052 return Gtkmm2ext::ExplicitActive;
1054 return Gtkmm2ext::Off;
1059 RouteUI::update_solo_display ()
1061 bool yn = _route->solo_safe ();
1063 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1064 solo_safe_check->set_active (yn);
1067 yn = _route->solo_isolated ();
1069 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1070 solo_isolated_check->set_active (yn);
1073 set_button_names ();
1075 if (solo_isolated_led) {
1076 if (_route->solo_isolated()) {
1077 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1079 solo_isolated_led->unset_active_state ();
1083 if (solo_safe_led) {
1084 if (_route->solo_safe()) {
1085 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1087 solo_safe_led->unset_active_state ();
1091 solo_button->set_active_state (solo_active_state (_route));
1093 /* some changes to solo status can affect mute display, so catch up
1096 update_mute_display ();
1100 RouteUI::solo_changed_so_update_mute ()
1102 update_mute_display ();
1106 RouteUI::mute_changed(void* /*src*/)
1108 update_mute_display ();
1112 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1114 if (r->is_monitor()) {
1115 return ActiveState(0);
1119 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1123 return Gtkmm2ext::ExplicitActive;
1124 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1125 /* master is NEVER muted by others */
1126 return Gtkmm2ext::ImplicitActive;
1128 /* no mute at all */
1129 return Gtkmm2ext::Off;
1136 return Gtkmm2ext::ExplicitActive;
1138 /* no mute at all */
1139 return Gtkmm2ext::Off;
1143 return ActiveState(0);
1147 RouteUI::update_mute_display ()
1153 mute_button->set_active_state (mute_active_state (_session, _route));
1157 RouteUI::route_rec_enable_changed ()
1159 update_rec_display ();
1160 update_monitoring_display ();
1164 RouteUI::session_rec_enable_changed ()
1166 update_rec_display ();
1167 update_monitoring_display ();
1171 RouteUI::update_rec_display ()
1173 if (!rec_enable_button || !_route) {
1177 if (_route->record_enabled()) {
1178 switch (_session->record_status ()) {
1179 case Session::Recording:
1180 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1183 case Session::Disabled:
1184 case Session::Enabled:
1185 rec_enable_button->set_active_state (Gtkmm2ext::ImplicitActive);
1190 if (step_edit_item) {
1191 step_edit_item->set_sensitive (false);
1195 rec_enable_button->unset_active_state ();
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 Gtk::CheckMenuItem* check;
1216 check = new Gtk::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<Gtk::CheckMenuItem*>(&items.back());
1223 check = new Gtk::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<Gtk::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 Gtk::CheckMenuItem(_("Pre Fader Sends")));
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 Gtk::CheckMenuItem(_("Post Fader Sends")));
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 Gtk::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 Gtk::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, Gtk::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 DisplaySuspender ds;
1342 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1346 if (model == view) {
1348 /* flip just this route */
1350 boost::shared_ptr<RouteList> rl (new RouteList);
1351 rl->push_back (_route);
1352 DisplaySuspender ds;
1353 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1362 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1364 if (ev->button == 1) {
1365 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1372 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1374 bool view = check->get_active();
1375 bool model = _route->solo_isolated();
1377 /* called AFTER the view has changed */
1379 if (model != view) {
1380 _route->set_solo_isolated (view, this);
1385 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1387 _route->set_solo_safe (check->get_active(), this);
1390 /** Ask the user to choose a colour, and then apply that color to my route
1393 RouteUI::choose_color ()
1396 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1403 /** Set the route's own color. This may not be used for display if
1404 * the route is in a group which shares its color with its routes.
1407 RouteUI::set_color (const Gdk::Color & c)
1409 /* leave _color alone in the group case so that tracks can retain their
1410 * own pre-group colors.
1415 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1417 /* note: we use the route state ID here so that color is the same for both
1418 the time axis view and the mixer strip
1421 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1422 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1425 /** @return GUI state ID for things that are common to the route in all its representations */
1427 RouteUI::route_state_id () const
1429 return string_compose (X_("route %1"), _route->id().to_s());
1433 RouteUI::set_color_from_route ()
1435 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1443 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1446 _color.set_green (g);
1447 _color.set_blue (b);
1453 RouteUI::remove_this_route (bool apply_to_selection)
1455 if (apply_to_selection) {
1456 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1458 if ((route()->is_master() || route()->is_monitor()) &&
1459 !Config->get_allow_special_bus_removal()) {
1460 MessageDialog msg (_("That would be bad news ...."),
1464 msg.set_secondary_text (string_compose (_(
1465 "Removing the master or monitor bus is such a bad idea\n\
1466 that %1 is not going to allow it.\n\
1468 If you really want to do this sort of thing\n\
1469 edit your ardour.rc file to set the\n\
1470 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1477 vector<string> choices;
1481 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());
1483 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());
1486 choices.push_back (_("No, do nothing."));
1487 choices.push_back (_("Yes, remove it."));
1491 title = _("Remove track");
1493 title = _("Remove bus");
1496 Choice prompter (title, prompt, choices);
1498 if (prompter.run () == 1) {
1499 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1505 RouteUI::idle_remove_this_route (RouteUI *rui)
1507 rui->_session->remove_route (rui->route());
1511 /** @return true if this name should be used for the route, otherwise false */
1513 RouteUI::verify_new_route_name (const std::string& name)
1515 if (name.find (':') == string::npos) {
1519 MessageDialog colon_msg (
1520 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1521 false, MESSAGE_QUESTION, BUTTONS_NONE
1524 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1525 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1527 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1531 RouteUI::route_rename ()
1533 ArdourPrompter name_prompter (true);
1538 name_prompter.set_title (_("Rename Track"));
1540 name_prompter.set_title (_("Rename Bus"));
1542 name_prompter.set_prompt (_("New name:"));
1543 name_prompter.set_initial_text (_route->name());
1544 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1545 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1546 name_prompter.show_all ();
1549 switch (name_prompter.run ()) {
1550 case Gtk::RESPONSE_ACCEPT:
1551 name_prompter.get_result (result);
1552 name_prompter.hide ();
1553 if (result.length()) {
1554 if (verify_new_route_name (result)) {
1555 _route->set_name (result);
1558 /* back to name prompter */
1562 /* 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::toggle_comment_editor ()
1587 // if (ignore_toggle) {
1591 if (comment_window && comment_window->is_visible ()) {
1592 comment_window->hide ();
1594 open_comment_editor ();
1600 RouteUI::open_comment_editor ()
1602 if (comment_window == 0) {
1603 setup_comment_editor ();
1607 title = _route->name();
1608 title += _(": comment editor");
1610 comment_window->set_title (title);
1611 comment_window->present();
1615 RouteUI::setup_comment_editor ()
1617 comment_window = new ArdourWindow (""); // title will be reset to show route
1618 comment_window->set_skip_taskbar_hint (true);
1619 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1620 comment_window->set_default_size (400, 200);
1622 comment_area = manage (new TextView());
1623 comment_area->set_name ("MixerTrackCommentArea");
1624 comment_area->set_wrap_mode (WRAP_WORD);
1625 comment_area->set_editable (true);
1626 comment_area->get_buffer()->set_text (_route->comment());
1627 comment_area->show ();
1629 comment_window->add (*comment_area);
1633 RouteUI::comment_changed (void *src)
1635 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_changed, src)
1638 ignore_comment_edit = true;
1640 comment_area->get_buffer()->set_text (_route->comment());
1642 ignore_comment_edit = false;
1647 RouteUI::comment_editor_done_editing ()
1649 string const str = comment_area->get_buffer()->get_text();
1650 if (str == _route->comment ()) {
1654 _route->set_comment (str, this);
1658 RouteUI::set_route_active (bool a, bool apply_to_selection)
1660 if (apply_to_selection) {
1661 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1663 _route->set_active (a, this);
1668 RouteUI::toggle_denormal_protection ()
1670 if (denormal_menu_item) {
1674 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1676 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1677 _route->set_denormal_protection (x);
1683 RouteUI::denormal_protection_changed ()
1685 if (denormal_menu_item) {
1686 denormal_menu_item->set_active (_route->denormal_protection());
1691 RouteUI::disconnect_input ()
1693 _route->input()->disconnect (this);
1697 RouteUI::disconnect_output ()
1699 _route->output()->disconnect (this);
1703 RouteUI::is_track () const
1705 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1708 boost::shared_ptr<Track>
1709 RouteUI::track() const
1711 return boost::dynamic_pointer_cast<Track>(_route);
1715 RouteUI::is_audio_track () const
1717 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1720 boost::shared_ptr<AudioTrack>
1721 RouteUI::audio_track() const
1723 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1727 RouteUI::is_midi_track () const
1729 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1732 boost::shared_ptr<MidiTrack>
1733 RouteUI::midi_track() const
1735 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1739 RouteUI::has_audio_outputs () const
1741 return (_route->n_outputs().n_audio() > 0);
1745 RouteUI::name() const
1747 return _route->name();
1751 RouteUI::map_frozen ()
1753 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1755 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1758 switch (at->freeze_state()) {
1759 case AudioTrack::Frozen:
1760 rec_enable_button->set_sensitive (false);
1763 rec_enable_button->set_sensitive (true);
1770 RouteUI::adjust_latency ()
1772 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1776 RouteUI::save_as_template ()
1779 std::string safe_name;
1782 path = ARDOUR::user_route_template_directory ();
1784 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1785 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1789 Prompter p (true); // modal
1791 p.set_title (_("Save As Template"));
1792 p.set_prompt (_("Template name:"));
1793 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1795 case RESPONSE_ACCEPT:
1802 p.get_result (name, true);
1804 safe_name = legalize_for_path (name);
1805 safe_name += template_suffix;
1807 path = Glib::build_filename (path, safe_name);
1809 _route->save_as_template (path, name);
1813 RouteUI::check_rec_enable_sensitivity ()
1815 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1816 rec_enable_button->set_sensitive (false);
1818 rec_enable_button->set_sensitive (true);
1821 update_monitoring_display ();
1825 RouteUI::parameter_changed (string const & p)
1827 /* this handles RC and per-session parameter changes */
1829 if (p == "disable-disarm-during-roll") {
1830 check_rec_enable_sensitivity ();
1831 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1832 set_button_names ();
1833 } else if (p == "auto-input") {
1834 update_monitoring_display ();
1839 RouteUI::step_gain_up ()
1841 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1845 RouteUI::page_gain_up ()
1847 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1851 RouteUI::step_gain_down ()
1853 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1857 RouteUI::page_gain_down ()
1859 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1863 RouteUI::open_remote_control_id_dialog ()
1865 ArdourDialog dialog (_("Remote Control ID"));
1866 SpinButton* spin = 0;
1868 dialog.get_vbox()->set_border_width (18);
1870 if (Config->get_remote_model() == UserOrdered) {
1871 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1873 HBox* hbox = manage (new HBox);
1874 hbox->set_spacing (6);
1875 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1876 spin = manage (new SpinButton);
1877 spin->set_digits (0);
1878 spin->set_increments (1, 10);
1879 spin->set_range (0, limit);
1880 spin->set_value (_route->remote_control_id());
1881 hbox->pack_start (*spin);
1882 dialog.get_vbox()->pack_start (*hbox);
1884 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1885 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1887 Label* l = manage (new Label());
1888 if (_route->is_master() || _route->is_monitor()) {
1889 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
1890 "The remote control ID of %3 cannot be changed."),
1891 Glib::Markup::escape_text (_route->name()),
1892 _route->remote_control_id(),
1893 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
1895 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
1896 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
1897 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
1898 (is_track() ? _("track") : _("bus")),
1899 _route->remote_control_id(),
1900 "<span size=\"small\" style=\"italic\">",
1902 Glib::Markup::escape_text (_route->name()),
1905 dialog.get_vbox()->pack_start (*l);
1906 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1910 int const r = dialog.run ();
1912 if (r == RESPONSE_ACCEPT && spin) {
1913 _route->set_remote_control_id (spin->get_value_as_int ());
1918 RouteUI::setup_invert_buttons ()
1920 /* remove old invert buttons */
1921 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1922 _invert_button_box.remove (**i);
1925 _invert_buttons.clear ();
1927 if (!_route || !_route->input()) {
1931 uint32_t const N = _route->input()->n_ports().n_audio ();
1933 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1935 for (uint32_t i = 0; i < to_add; ++i) {
1936 ArdourButton* b = manage (new ArdourButton);
1937 b->set_size_request(20,20);
1938 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1939 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
1941 b->set_name (X_("invert button"));
1944 b->set_text (string_compose (X_("Ø (%1)"), N));
1946 b->set_text (X_("Ø"));
1949 b->set_text (string_compose (X_("Ø%1"), i + 1));
1952 if (N <= _max_invert_buttons) {
1953 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));
1955 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
1958 _invert_buttons.push_back (b);
1959 _invert_button_box.pack_start (*b);
1962 _invert_button_box.set_spacing (1);
1963 _invert_button_box.show_all ();
1967 RouteUI::set_invert_button_state ()
1969 uint32_t const N = _route->input()->n_ports().n_audio();
1970 if (N > _max_invert_buttons) {
1972 /* One button for many channels; explicit active if all channels are inverted,
1973 implicit active if some are, off if none are.
1976 ArdourButton* b = _invert_buttons.front ();
1978 if (_route->phase_invert().count() == _route->phase_invert().size()) {
1979 b->set_active_state (Gtkmm2ext::ExplicitActive);
1980 } else if (_route->phase_invert().any()) {
1981 b->set_active_state (Gtkmm2ext::ImplicitActive);
1983 b->set_active_state (Gtkmm2ext::Off);
1988 /* One button per channel; just set active */
1991 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1992 (*i)->set_active (_route->phase_invert (j));
1999 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2001 if (ev->button == 1 && i < _invert_buttons.size()) {
2002 uint32_t const N = _route->input()->n_ports().n_audio ();
2003 if (N <= _max_invert_buttons) {
2004 /* left-click inverts phase so long as we have a button per channel */
2005 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2014 RouteUI::invert_press (GdkEventButton* ev)
2016 using namespace Menu_Helpers;
2018 uint32_t const N = _route->input()->n_ports().n_audio();
2019 if (N <= _max_invert_buttons && ev->button != 3) {
2020 /* If we have an invert button per channel, we only pop
2021 up a menu on right-click; left click is handled
2027 delete _invert_menu;
2028 _invert_menu = new Menu;
2029 _invert_menu->set_name ("ArdourContextMenu");
2030 MenuList& items = _invert_menu->items ();
2032 for (uint32_t i = 0; i < N; ++i) {
2033 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2034 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2035 ++_i_am_the_modifier;
2036 e->set_active (_route->phase_invert (i));
2037 --_i_am_the_modifier;
2040 _invert_menu->popup (0, ev->time);
2046 RouteUI::invert_menu_toggled (uint32_t c)
2048 if (_i_am_the_modifier) {
2052 _route->set_phase_invert (c, !_route->phase_invert (c));
2056 RouteUI::set_invert_sensitive (bool yn)
2058 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2059 (*b)->set_sensitive (yn);
2064 RouteUI::request_redraw ()
2067 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2071 /** The Route's gui_changed signal has been emitted */
2073 RouteUI::route_gui_changed (string what_changed)
2075 if (what_changed == "color") {
2076 if (set_color_from_route () == 0) {
2077 route_color_changed ();
2082 /** @return the color that this route should use; it maybe its own,
2083 or it maybe that of its route group.
2086 RouteUI::color () const
2088 RouteGroup* g = _route->route_group ();
2090 if (g && g->is_color()) {
2092 set_color_from_rgba (c, GroupTabs::group_color (g));
2100 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2102 _showing_sends_to = send_to;
2103 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2107 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2109 if (_route == send_to) {
2110 show_sends_button->set_active (true);
2111 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2113 show_sends_button->set_active (false);
2114 send_blink_connection.disconnect ();
2119 RouteUI::route_group() const
2121 return _route->route_group();