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>
26 #include <gtkmm2ext/utils.h>
28 #include "ardour/route_group.h"
29 #include "ardour/dB.h"
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
35 #include "ardour_ui.h"
38 #include "ardour_button.h"
42 #include "gui_thread.h"
43 #include "ardour_dialog.h"
44 #include "latency_gui.h"
45 #include "mixer_strip.h"
46 #include "automation_time_axis.h"
47 #include "route_time_axis.h"
48 #include "group_tabs.h"
50 #include "ardour/audio_track.h"
51 #include "ardour/audioengine.h"
52 #include "ardour/filename_extensions.h"
53 #include "ardour/midi_track.h"
54 #include "ardour/internal_send.h"
55 #include "ardour/send.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/template_utils.h"
62 using namespace Gtkmm2ext;
63 using namespace ARDOUR;
64 using namespace ARDOUR_UI_UTILS;
67 uint32_t RouteUI::_max_invert_buttons = 3;
68 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
69 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
71 static const int _button_vpad = 2;
73 RouteUI::RouteUI (ARDOUR::Session* sess)
87 _route.reset (); /* drop reference to route, so that it can be cleaned up */
88 route_connections.drop_connections ();
95 delete comment_window;
96 delete input_selector;
97 delete output_selector;
103 self_destruct = true;
109 pre_fader_mute_check = 0;
110 post_fader_mute_check = 0;
111 listen_mute_check = 0;
114 solo_isolated_check = 0;
115 solo_isolated_led = 0;
119 denormal_menu_item = 0;
121 multiple_mute_change = false;
122 multiple_solo_change = false;
123 _i_am_the_modifier = 0;
128 setup_invert_buttons ();
130 mute_button = manage (new ArdourButton);
131 mute_button->set_name ("mute button");
132 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
134 solo_button = manage (new ArdourButton);
135 solo_button->set_name ("solo button");
136 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
137 solo_button->set_no_show_all (true);
139 rec_enable_button = manage (new ArdourButton);
140 rec_enable_button->set_name ("record enable button");
141 // rec_enable_button->set_tweaks (ArdourButton::ImplicitUsesSolidColor);
142 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
144 show_sends_button = manage (new ArdourButton);
145 show_sends_button->set_name ("send alert button");
146 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
148 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
149 monitor_input_button->set_name ("monitor button");
150 monitor_input_button->set_text (_("In"));
151 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
152 monitor_input_button->set_no_show_all (true);
154 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
155 monitor_disk_button->set_name ("monitor button");
156 monitor_disk_button->set_text (_("Disk"));
157 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
158 monitor_disk_button->set_no_show_all (true);
160 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
161 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
162 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
164 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
165 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
167 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
168 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
170 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
171 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
173 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
174 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
175 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
176 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
178 monitor_input_button->set_distinct_led_click (false);
179 monitor_disk_button->set_distinct_led_click (false);
181 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
182 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
184 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
185 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
187 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
193 route_connections.drop_connections ();
201 denormal_menu_item = 0;
205 RouteUI::self_delete ()
211 RouteUI::set_route (boost::shared_ptr<Route> rp)
217 if (set_color_from_route()) {
218 set_color (unique_random_color());
222 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
225 delete input_selector;
228 delete output_selector;
231 mute_button->set_controllable (_route->mute_control());
232 solo_button->set_controllable (_route->solo_control());
234 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
235 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::mute_changed, this, _1), gui_context());
237 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this, _1), gui_context());
239 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
240 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
241 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
242 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
244 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
245 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
247 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
248 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
250 if (_session->writable() && is_track()) {
251 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
253 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
255 rec_enable_button->show();
256 rec_enable_button->set_controllable (t->rec_enable_control());
258 if (is_midi_track()) {
259 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
260 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
265 /* this will work for busses and tracks, and needs to be called to
266 set up the name entry/name label display.
269 update_rec_display ();
272 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
273 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
275 update_monitoring_display ();
278 mute_button->unset_flags (Gtk::CAN_FOCUS);
279 solo_button->unset_flags (Gtk::CAN_FOCUS);
283 if (_route->is_monitor() || _route->is_master()) {
284 solo_button->hide ();
291 setup_invert_buttons ();
292 set_invert_button_state ();
294 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
295 bus_send_display_changed (s);
297 update_mute_display ();
298 update_solo_display ();
302 RouteUI::polarity_changed ()
308 set_invert_button_state ();
312 RouteUI::mute_press (GdkEventButton* ev)
314 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
318 multiple_mute_change = false;
320 if (Keyboard::is_context_menu_event (ev)) {
326 mute_menu->popup(0,ev->time);
330 if (Keyboard::is_button2_event (ev)) {
331 // Primary-button2 click is the midi binding click
332 // button2-click is "momentary"
335 if (mute_button->on_button_press_event (ev)) {
339 _mute_release = new SoloMuteRelease (_route->muted ());
342 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
344 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
346 /* toggle mute on everything (but
347 * exclude the master and monitor)
349 * because we are going to erase
350 * elements of the list we need to work
354 boost::shared_ptr<RouteList> copy (new RouteList);
356 *copy = *_session->get_routes ();
358 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
359 if ((*i)->is_master() || (*i)->is_monitor()) {
367 _mute_release->routes = copy;
371 _session->set_mute (copy, !_route->muted());
373 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
375 /* Primary-button1 applies change to the mix group even if it is not active
376 NOTE: Primary-button2 is MIDI learn.
379 boost::shared_ptr<RouteList> rl;
381 if (ev->button == 1) {
383 if (_route->route_group()) {
385 rl = _route->route_group()->route_list();
388 _mute_release->routes = rl;
391 rl.reset (new RouteList);
392 rl->push_back (_route);
396 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, true);
401 /* plain click applies change to this route */
403 boost::shared_ptr<RouteList> rl (new RouteList);
404 rl->push_back (_route);
407 _mute_release->routes = rl;
410 _session->set_mute (rl, !_route->muted());
420 RouteUI::mute_release (GdkEventButton*)
424 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
425 delete _mute_release;
433 RouteUI::edit_output_configuration ()
435 if (output_selector == 0) {
437 boost::shared_ptr<Send> send;
438 boost::shared_ptr<IO> output;
440 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
441 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
442 output = send->output();
444 output = _route->output ();
447 output = _route->output ();
450 output_selector = new IOSelectorWindow (_session, output);
453 if (output_selector->is_visible()) {
454 output_selector->get_toplevel()->get_window()->raise();
456 output_selector->present ();
459 output_selector->set_keep_above (true);
463 RouteUI::edit_input_configuration ()
465 if (input_selector == 0) {
466 input_selector = new IOSelectorWindow (_session, _route->input());
469 if (input_selector->is_visible()) {
470 input_selector->get_toplevel()->get_window()->raise();
472 input_selector->present ();
475 input_selector->set_keep_above (true);
479 RouteUI::solo_press(GdkEventButton* ev)
481 /* ignore double/triple clicks */
483 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
487 multiple_solo_change = false;
489 if (Keyboard::is_context_menu_event (ev)) {
491 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
492 ! (solo_safe_led && solo_safe_led->is_visible())) {
494 if (solo_menu == 0) {
498 solo_menu->popup (1, ev->time);
503 if (Keyboard::is_button2_event (ev)) {
505 // Primary-button2 click is the midi binding click
506 // button2-click is "momentary"
508 if (solo_button->on_button_press_event (ev)) {
512 _solo_release = new SoloMuteRelease (_route->self_soloed());
515 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
517 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
519 /* Primary-Tertiary-click applies change to all routes */
522 _solo_release->routes = _session->get_routes ();
526 if (Config->get_solo_control_is_listen_control()) {
527 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
529 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
532 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
534 // Primary-Secondary-click: exclusively solo this track
537 _solo_release->exclusive = true;
539 boost::shared_ptr<RouteList> routes = _session->get_routes();
541 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
542 if ((*i)->soloed ()) {
543 _solo_release->routes_on->push_back (*i);
545 _solo_release->routes_off->push_back (*i);
550 if (Config->get_solo_control_is_listen_control()) {
551 /* ??? we need a just_one_listen() method */
554 _session->set_just_one_solo (_route, true);
557 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
559 // shift-click: toggle solo isolated status
561 _route->set_solo_isolated (!_route->solo_isolated(), this);
562 delete _solo_release;
565 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
567 /* Primary-button1: solo mix group.
568 NOTE: Primary-button2 is MIDI learn.
571 /* Primary-button1 applies change to the mix group even if it is not active
572 NOTE: Primary-button2 is MIDI learn.
575 boost::shared_ptr<RouteList> rl;
577 if (ev->button == 1) {
579 if (_route->route_group()) {
581 rl = _route->route_group()->route_list();
584 _solo_release->routes = rl;
587 rl.reset (new RouteList);
588 rl->push_back (_route);
592 if (Config->get_solo_control_is_listen_control()) {
593 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, true);
595 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, true);
601 /* click: solo this route */
603 boost::shared_ptr<RouteList> rl (new RouteList);
604 rl->push_back (route());
607 _solo_release->routes = rl;
611 if (Config->get_solo_control_is_listen_control()) {
612 _session->set_listen (rl, !_route->listening_via_monitor());
614 _session->set_solo (rl, !_route->self_soloed());
624 RouteUI::solo_release (GdkEventButton*)
628 if (_solo_release->exclusive) {
632 if (Config->get_solo_control_is_listen_control()) {
633 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
635 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
639 delete _solo_release;
647 RouteUI::rec_enable_press(GdkEventButton* ev)
649 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
653 if (!_session->engine().connected()) {
654 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
659 if (is_midi_track()) {
661 /* rec-enable button exits from step editing */
663 if (midi_track()->step_editing()) {
664 midi_track()->set_step_editing (false);
669 if (is_track() && rec_enable_button) {
671 if (Keyboard::is_button2_event (ev)) {
673 // do nothing on midi sigc::bind event
674 return rec_enable_button->on_button_press_event (ev);
676 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
679 _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
681 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
683 /* Primary-button1 applies change to the route group (even if it is not active)
684 NOTE: Primary-button2 is MIDI learn.
687 if (ev->button == 1) {
689 boost::shared_ptr<RouteList> rl;
691 if (_route->route_group()) {
693 rl = _route->route_group()->route_list();
696 rl.reset (new RouteList);
697 rl->push_back (_route);
701 _session->set_record_enabled (rl, !rec_enable_button->active_state(), Session::rt_cleanup, true);
704 } else if (Keyboard::is_context_menu_event (ev)) {
706 /* do this on release */
710 boost::shared_ptr<RouteList> rl (new RouteList);
711 rl->push_back (route());
713 _session->set_record_enabled (rl, !rec_enable_button->active_state());
721 RouteUI::monitoring_changed ()
723 update_monitoring_display ();
727 RouteUI::update_monitoring_display ()
733 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
739 MonitorState ms = t->monitoring_state();
741 if (t->monitoring_choice() & MonitorInput) {
742 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
744 if (ms & MonitoringInput) {
745 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
747 monitor_input_button->unset_active_state ();
751 if (t->monitoring_choice() & MonitorDisk) {
752 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
754 if (ms & MonitoringDisk) {
755 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
757 monitor_disk_button->unset_active_state ();
763 RouteUI::monitor_input_press(GdkEventButton*)
769 RouteUI::monitor_input_release(GdkEventButton* ev)
771 return monitor_release (ev, MonitorInput);
775 RouteUI::monitor_disk_press (GdkEventButton*)
781 RouteUI::monitor_disk_release (GdkEventButton* ev)
783 return monitor_release (ev, MonitorDisk);
787 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
789 if (ev->button != 1) {
793 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
800 boost::shared_ptr<RouteList> rl;
802 /* XXX for now, monitoring choices are orthogonal. cue monitoring
803 will follow in 3.X but requires mixing the input and playback (disk)
804 signal together, which requires yet more buffers.
807 if (t->monitoring_choice() & monitor_choice) {
808 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
810 /* this line will change when the options are non-orthogonal */
811 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
815 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
816 rl = _session->get_routes ();
818 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
819 if (_route->route_group() && _route->route_group()->is_monitoring()) {
820 rl = _route->route_group()->route_list();
822 rl.reset (new RouteList);
823 rl->push_back (route());
826 rl.reset (new RouteList);
827 rl->push_back (route());
831 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
837 RouteUI::build_record_menu ()
843 /* no rec-button context menu for non-MIDI tracks
846 if (is_midi_track()) {
847 record_menu = new Menu;
848 record_menu->set_name ("ArdourContextMenu");
850 using namespace Menu_Helpers;
851 MenuList& items = record_menu->items();
853 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
854 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
856 if (_route->record_enabled()) {
857 step_edit_item->set_sensitive (false);
860 step_edit_item->set_active (midi_track()->step_editing());
865 RouteUI::toggle_step_edit ()
867 if (!is_midi_track() || _route->record_enabled()) {
871 midi_track()->set_step_editing (step_edit_item->get_active());
875 RouteUI::step_edit_changed (bool yn)
878 if (rec_enable_button) {
879 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
882 start_step_editing ();
884 if (step_edit_item) {
885 step_edit_item->set_active (true);
890 if (rec_enable_button) {
891 rec_enable_button->unset_active_state ();
894 stop_step_editing ();
896 if (step_edit_item) {
897 step_edit_item->set_active (false);
903 RouteUI::rec_enable_release (GdkEventButton* ev)
905 if (Keyboard::is_context_menu_event (ev)) {
906 build_record_menu ();
908 record_menu->popup (1, ev->time);
917 RouteUI::build_sends_menu ()
919 using namespace Menu_Helpers;
921 sends_menu = new Menu;
922 sends_menu->set_name ("ArdourContextMenu");
923 MenuList& items = sends_menu->items();
926 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
930 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
934 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
938 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
942 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
946 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
949 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
953 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
956 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
957 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
958 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
963 RouteUI::create_sends (Placement p, bool include_buses)
965 _session->globally_add_internal_sends (_route, p, include_buses);
969 RouteUI::create_selected_sends (Placement p, bool include_buses)
971 boost::shared_ptr<RouteList> rlist (new RouteList);
972 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
974 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
975 RouteTimeAxisView* rtv;
977 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
978 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
979 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
980 rlist->push_back (rui->route());
986 _session->add_internal_sends (_route, p, rlist);
990 RouteUI::set_sends_gain_from_track ()
992 _session->globally_set_send_gains_from_track (_route);
996 RouteUI::set_sends_gain_to_zero ()
998 _session->globally_set_send_gains_to_zero (_route);
1002 RouteUI::set_sends_gain_to_unity ()
1004 _session->globally_set_send_gains_to_unity (_route);
1008 RouteUI::show_sends_press(GdkEventButton* ev)
1010 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1014 if (!is_track() && show_sends_button) {
1016 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1018 // do nothing on midi sigc::bind event
1021 } else if (Keyboard::is_context_menu_event (ev)) {
1023 if (sends_menu == 0) {
1024 build_sends_menu ();
1027 sends_menu->popup (0, ev->time);
1031 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1034 set_showing_sends_to (boost::shared_ptr<Route> ());
1036 set_showing_sends_to (_route);
1045 RouteUI::show_sends_release (GdkEventButton*)
1051 RouteUI::send_blink (bool onoff)
1053 if (!show_sends_button) {
1058 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1060 show_sends_button->unset_active_state ();
1064 Gtkmm2ext::ActiveState
1065 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1067 if (r->is_master() || r->is_monitor()) {
1068 return Gtkmm2ext::Off;
1071 if (Config->get_solo_control_is_listen_control()) {
1073 if (r->listening_via_monitor()) {
1074 return Gtkmm2ext::ExplicitActive;
1076 return Gtkmm2ext::Off;
1082 if (!r->self_soloed()) {
1083 return Gtkmm2ext::ImplicitActive;
1085 return Gtkmm2ext::ExplicitActive;
1088 return Gtkmm2ext::Off;
1092 Gtkmm2ext::ActiveState
1093 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1095 if (r->is_master() || r->is_monitor()) {
1096 return Gtkmm2ext::Off;
1099 if (r->solo_isolated()) {
1100 return Gtkmm2ext::ExplicitActive;
1102 return Gtkmm2ext::Off;
1106 Gtkmm2ext::ActiveState
1107 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1109 if (r->is_master() || r->is_monitor()) {
1110 return Gtkmm2ext::Off;
1113 if (r->solo_safe()) {
1114 return Gtkmm2ext::ExplicitActive;
1116 return Gtkmm2ext::Off;
1121 RouteUI::update_solo_display ()
1123 bool yn = _route->solo_safe ();
1125 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1126 solo_safe_check->set_active (yn);
1129 yn = _route->solo_isolated ();
1131 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1132 solo_isolated_check->set_active (yn);
1135 set_button_names ();
1137 if (solo_isolated_led) {
1138 if (_route->solo_isolated()) {
1139 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1141 solo_isolated_led->unset_active_state ();
1145 if (solo_safe_led) {
1146 if (_route->solo_safe()) {
1147 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1149 solo_safe_led->unset_active_state ();
1153 solo_button->set_active_state (solo_active_state (_route));
1155 /* some changes to solo status can affect mute display, so catch up
1158 update_mute_display ();
1162 RouteUI::solo_changed_so_update_mute ()
1164 update_mute_display ();
1168 RouteUI::mute_changed(void* /*src*/)
1170 update_mute_display ();
1174 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1176 if (r->is_monitor()) {
1177 return ActiveState(0);
1181 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1185 return Gtkmm2ext::ExplicitActive;
1186 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1187 /* master is NEVER muted by others */
1188 return Gtkmm2ext::ImplicitActive;
1190 /* no mute at all */
1191 return Gtkmm2ext::Off;
1198 return Gtkmm2ext::ExplicitActive;
1200 /* no mute at all */
1201 return Gtkmm2ext::Off;
1205 return ActiveState(0);
1209 RouteUI::update_mute_display ()
1215 mute_button->set_active_state (mute_active_state (_session, _route));
1219 RouteUI::route_rec_enable_changed ()
1221 update_rec_display ();
1222 update_monitoring_display ();
1226 RouteUI::session_rec_enable_changed ()
1228 update_rec_display ();
1229 update_monitoring_display ();
1233 RouteUI::update_rec_display ()
1235 if (!rec_enable_button || !_route) {
1239 if (_route->record_enabled()) {
1240 switch (_session->record_status ()) {
1241 case Session::Recording:
1242 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1245 case Session::Disabled:
1246 case Session::Enabled:
1247 rec_enable_button->set_active_state (Gtkmm2ext::ImplicitActive);
1252 if (step_edit_item) {
1253 step_edit_item->set_sensitive (false);
1257 rec_enable_button->unset_active_state ();
1259 if (step_edit_item) {
1260 step_edit_item->set_sensitive (true);
1265 check_rec_enable_sensitivity ();
1269 RouteUI::build_solo_menu (void)
1271 using namespace Menu_Helpers;
1273 solo_menu = new Menu;
1274 solo_menu->set_name ("ArdourContextMenu");
1275 MenuList& items = solo_menu->items();
1276 Gtk::CheckMenuItem* check;
1278 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1279 check->set_active (_route->solo_isolated());
1280 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1281 items.push_back (CheckMenuElem(*check));
1282 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1285 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1286 check->set_active (_route->solo_safe());
1287 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1288 items.push_back (CheckMenuElem(*check));
1289 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1292 //items.push_back (SeparatorElem());
1293 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1298 RouteUI::build_mute_menu(void)
1300 using namespace Menu_Helpers;
1302 mute_menu = new Menu;
1303 mute_menu->set_name ("ArdourContextMenu");
1305 MenuList& items = mute_menu->items();
1307 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1308 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1309 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1310 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1311 pre_fader_mute_check->show_all();
1313 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1314 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1315 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1316 items.push_back (CheckMenuElem(*post_fader_mute_check));
1317 post_fader_mute_check->show_all();
1319 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1320 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1321 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1322 items.push_back (CheckMenuElem(*listen_mute_check));
1323 listen_mute_check->show_all();
1325 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1326 init_mute_menu(MuteMaster::Main, main_mute_check);
1327 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1328 items.push_back (CheckMenuElem(*main_mute_check));
1329 main_mute_check->show_all();
1331 //items.push_back (SeparatorElem());
1332 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1334 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1338 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1340 check->set_active (_route->mute_points() & mp);
1344 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1346 if (check->get_active()) {
1347 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1349 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1354 RouteUI::muting_change ()
1356 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1359 MuteMaster::MutePoint current = _route->mute_points ();
1361 yn = (current & MuteMaster::PreFader);
1363 if (pre_fader_mute_check->get_active() != yn) {
1364 pre_fader_mute_check->set_active (yn);
1367 yn = (current & MuteMaster::PostFader);
1369 if (post_fader_mute_check->get_active() != yn) {
1370 post_fader_mute_check->set_active (yn);
1373 yn = (current & MuteMaster::Listen);
1375 if (listen_mute_check->get_active() != yn) {
1376 listen_mute_check->set_active (yn);
1379 yn = (current & MuteMaster::Main);
1381 if (main_mute_check->get_active() != yn) {
1382 main_mute_check->set_active (yn);
1387 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1389 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1393 bool view = solo_isolated_led->active_state();
1394 bool model = _route->solo_isolated();
1396 /* called BEFORE the view has changed */
1398 if (ev->button == 1) {
1399 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1402 /* disable isolate for all routes */
1403 DisplaySuspender ds;
1404 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1408 if (model == view) {
1410 /* flip just this route */
1412 boost::shared_ptr<RouteList> rl (new RouteList);
1413 rl->push_back (_route);
1414 DisplaySuspender ds;
1415 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1424 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1426 if (ev->button == 1) {
1427 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1434 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1436 bool view = check->get_active();
1437 bool model = _route->solo_isolated();
1439 /* called AFTER the view has changed */
1441 if (model != view) {
1442 _route->set_solo_isolated (view, this);
1447 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1449 _route->set_solo_safe (check->get_active(), this);
1452 /** Ask the user to choose a colour, and then apply that color to my route
1455 RouteUI::choose_color ()
1458 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1465 /** Set the route's own color. This may not be used for display if
1466 * the route is in a group which shares its color with its routes.
1469 RouteUI::set_color (const Gdk::Color & c)
1471 /* leave _color alone in the group case so that tracks can retain their
1472 * own pre-group colors.
1477 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1479 /* note: we use the route state ID here so that color is the same for both
1480 the time axis view and the mixer strip
1483 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1484 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1487 /** @return GUI state ID for things that are common to the route in all its representations */
1489 RouteUI::route_state_id () const
1491 return string_compose (X_("route %1"), _route->id().to_s());
1495 RouteUI::set_color_from_route ()
1497 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1505 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1508 _color.set_green (g);
1509 _color.set_blue (b);
1515 RouteUI::remove_this_route (bool apply_to_selection)
1517 if (apply_to_selection) {
1518 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1520 if ((route()->is_master() || route()->is_monitor()) &&
1521 !Config->get_allow_special_bus_removal()) {
1522 MessageDialog msg (_("That would be bad news ...."),
1526 msg.set_secondary_text (string_compose (_(
1527 "Removing the master or monitor bus is such a bad idea\n\
1528 that %1 is not going to allow it.\n\
1530 If you really want to do this sort of thing\n\
1531 edit your ardour.rc file to set the\n\
1532 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1539 vector<string> choices;
1543 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());
1545 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());
1548 choices.push_back (_("No, do nothing."));
1549 choices.push_back (_("Yes, remove it."));
1553 title = _("Remove track");
1555 title = _("Remove bus");
1558 Choice prompter (title, prompt, choices);
1560 if (prompter.run () == 1) {
1561 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1567 RouteUI::idle_remove_this_route (RouteUI *rui)
1569 rui->_session->remove_route (rui->route());
1573 /** @return true if this name should be used for the route, otherwise false */
1575 RouteUI::verify_new_route_name (const std::string& name)
1577 if (name.find (':') == string::npos) {
1581 MessageDialog colon_msg (
1582 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1583 false, MESSAGE_QUESTION, BUTTONS_NONE
1586 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1587 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1589 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1593 RouteUI::route_rename ()
1595 ArdourPrompter name_prompter (true);
1600 name_prompter.set_title (_("Rename Track"));
1602 name_prompter.set_title (_("Rename Bus"));
1604 name_prompter.set_prompt (_("New name:"));
1605 name_prompter.set_initial_text (_route->name());
1606 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1607 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1608 name_prompter.show_all ();
1611 switch (name_prompter.run ()) {
1612 case Gtk::RESPONSE_ACCEPT:
1613 name_prompter.get_result (result);
1614 name_prompter.hide ();
1615 if (result.length()) {
1616 if (verify_new_route_name (result)) {
1617 _route->set_name (result);
1620 /* back to name prompter */
1624 /* nothing entered, just get out of here */
1639 RouteUI::property_changed (const PropertyChange& what_changed)
1641 if (what_changed.contains (ARDOUR::Properties::name)) {
1642 name_label.set_text (_route->name());
1647 RouteUI::toggle_comment_editor ()
1649 // if (ignore_toggle) {
1653 if (comment_window && comment_window->is_visible ()) {
1654 comment_window->hide ();
1656 open_comment_editor ();
1662 RouteUI::open_comment_editor ()
1664 if (comment_window == 0) {
1665 setup_comment_editor ();
1669 title = _route->name();
1670 title += _(": comment editor");
1672 comment_window->set_title (title);
1673 comment_window->present();
1677 RouteUI::setup_comment_editor ()
1679 comment_window = new ArdourWindow (""); // title will be reset to show route
1680 comment_window->set_skip_taskbar_hint (true);
1681 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1682 comment_window->set_default_size (400, 200);
1684 comment_area = manage (new TextView());
1685 comment_area->set_name ("MixerTrackCommentArea");
1686 comment_area->set_wrap_mode (WRAP_WORD);
1687 comment_area->set_editable (true);
1688 comment_area->get_buffer()->set_text (_route->comment());
1689 comment_area->show ();
1691 comment_window->add (*comment_area);
1695 RouteUI::comment_changed (void *src)
1697 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_changed, src)
1700 ignore_comment_edit = true;
1702 comment_area->get_buffer()->set_text (_route->comment());
1704 ignore_comment_edit = false;
1709 RouteUI::comment_editor_done_editing ()
1711 string const str = comment_area->get_buffer()->get_text();
1712 if (str == _route->comment ()) {
1716 _route->set_comment (str, this);
1720 RouteUI::set_route_active (bool a, bool apply_to_selection)
1722 if (apply_to_selection) {
1723 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1725 _route->set_active (a, this);
1730 RouteUI::toggle_denormal_protection ()
1732 if (denormal_menu_item) {
1736 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1738 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1739 _route->set_denormal_protection (x);
1745 RouteUI::denormal_protection_changed ()
1747 if (denormal_menu_item) {
1748 denormal_menu_item->set_active (_route->denormal_protection());
1753 RouteUI::disconnect_input ()
1755 _route->input()->disconnect (this);
1759 RouteUI::disconnect_output ()
1761 _route->output()->disconnect (this);
1765 RouteUI::is_track () const
1767 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1770 boost::shared_ptr<Track>
1771 RouteUI::track() const
1773 return boost::dynamic_pointer_cast<Track>(_route);
1777 RouteUI::is_audio_track () const
1779 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1782 boost::shared_ptr<AudioTrack>
1783 RouteUI::audio_track() const
1785 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1789 RouteUI::is_midi_track () const
1791 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1794 boost::shared_ptr<MidiTrack>
1795 RouteUI::midi_track() const
1797 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1801 RouteUI::has_audio_outputs () const
1803 return (_route->n_outputs().n_audio() > 0);
1807 RouteUI::name() const
1809 return _route->name();
1813 RouteUI::map_frozen ()
1815 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1817 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1820 switch (at->freeze_state()) {
1821 case AudioTrack::Frozen:
1822 rec_enable_button->set_sensitive (false);
1825 rec_enable_button->set_sensitive (true);
1832 RouteUI::adjust_latency ()
1834 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1838 RouteUI::save_as_template ()
1841 std::string safe_name;
1844 path = ARDOUR::user_route_template_directory ();
1846 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1847 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1851 Prompter p (true); // modal
1853 p.set_title (_("Save As Template"));
1854 p.set_prompt (_("Template name:"));
1855 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1857 case RESPONSE_ACCEPT:
1864 p.get_result (name, true);
1866 safe_name = legalize_for_path (name);
1867 safe_name += template_suffix;
1869 path = Glib::build_filename (path, safe_name);
1871 _route->save_as_template (path, name);
1875 RouteUI::check_rec_enable_sensitivity ()
1877 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1878 rec_enable_button->set_sensitive (false);
1880 rec_enable_button->set_sensitive (true);
1883 update_monitoring_display ();
1887 RouteUI::parameter_changed (string const & p)
1889 /* this handles RC and per-session parameter changes */
1891 if (p == "disable-disarm-during-roll") {
1892 check_rec_enable_sensitivity ();
1893 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1894 set_button_names ();
1895 } else if (p == "auto-input") {
1896 update_monitoring_display ();
1901 RouteUI::step_gain_up ()
1903 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1907 RouteUI::page_gain_up ()
1909 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1913 RouteUI::step_gain_down ()
1915 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1919 RouteUI::page_gain_down ()
1921 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1925 RouteUI::open_remote_control_id_dialog ()
1927 ArdourDialog dialog (_("Remote Control ID"));
1928 SpinButton* spin = 0;
1930 dialog.get_vbox()->set_border_width (18);
1932 if (Config->get_remote_model() == UserOrdered) {
1933 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1935 HBox* hbox = manage (new HBox);
1936 hbox->set_spacing (6);
1937 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1938 spin = manage (new SpinButton);
1939 spin->set_digits (0);
1940 spin->set_increments (1, 10);
1941 spin->set_range (0, limit);
1942 spin->set_value (_route->remote_control_id());
1943 hbox->pack_start (*spin);
1944 dialog.get_vbox()->pack_start (*hbox);
1946 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1947 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1949 Label* l = manage (new Label());
1950 if (_route->is_master() || _route->is_monitor()) {
1951 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
1952 "The remote control ID of %3 cannot be changed."),
1953 Glib::Markup::escape_text (_route->name()),
1954 _route->remote_control_id(),
1955 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
1957 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
1958 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
1959 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
1960 (is_track() ? _("track") : _("bus")),
1961 _route->remote_control_id(),
1962 "<span size=\"small\" style=\"italic\">",
1964 Glib::Markup::escape_text (_route->name()),
1967 dialog.get_vbox()->pack_start (*l);
1968 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1972 int const r = dialog.run ();
1974 if (r == RESPONSE_ACCEPT && spin) {
1975 _route->set_remote_control_id (spin->get_value_as_int ());
1980 RouteUI::setup_invert_buttons ()
1982 /* remove old invert buttons */
1983 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1984 _invert_button_box.remove (**i);
1987 _invert_buttons.clear ();
1989 if (!_route || !_route->input()) {
1993 uint32_t const N = _route->input()->n_ports().n_audio ();
1995 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1997 for (uint32_t i = 0; i < to_add; ++i) {
1998 ArdourButton* b = manage (new ArdourButton);
1999 b->set_size_request(20,20);
2000 Gtkmm2ext::set_height_request_to_display_any_text (*b, _button_vpad);
2001 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
2002 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
2004 b->set_name (X_("invert button"));
2007 b->set_text (string_compose (X_("Ø (%1)"), N));
2009 b->set_text (X_("Ø"));
2012 b->set_text (string_compose (X_("Ø%1"), i + 1));
2015 if (N <= _max_invert_buttons) {
2016 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));
2018 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2021 _invert_buttons.push_back (b);
2022 _invert_button_box.pack_start (*b);
2025 _invert_button_box.set_spacing (1);
2026 _invert_button_box.show_all ();
2030 RouteUI::set_invert_button_state ()
2032 uint32_t const N = _route->input()->n_ports().n_audio();
2033 if (N > _max_invert_buttons) {
2035 /* One button for many channels; explicit active if all channels are inverted,
2036 implicit active if some are, off if none are.
2039 ArdourButton* b = _invert_buttons.front ();
2041 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2042 b->set_active_state (Gtkmm2ext::ExplicitActive);
2043 } else if (_route->phase_invert().any()) {
2044 b->set_active_state (Gtkmm2ext::ImplicitActive);
2046 b->set_active_state (Gtkmm2ext::Off);
2051 /* One button per channel; just set active */
2054 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2055 (*i)->set_active (_route->phase_invert (j));
2062 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2064 if (ev->button == 1 && i < _invert_buttons.size()) {
2065 uint32_t const N = _route->input()->n_ports().n_audio ();
2066 if (N <= _max_invert_buttons) {
2067 /* left-click inverts phase so long as we have a button per channel */
2068 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2077 RouteUI::invert_press (GdkEventButton* ev)
2079 using namespace Menu_Helpers;
2081 uint32_t const N = _route->input()->n_ports().n_audio();
2082 if (N <= _max_invert_buttons && ev->button != 3) {
2083 /* If we have an invert button per channel, we only pop
2084 up a menu on right-click; left click is handled
2090 delete _invert_menu;
2091 _invert_menu = new Menu;
2092 _invert_menu->set_name ("ArdourContextMenu");
2093 MenuList& items = _invert_menu->items ();
2095 for (uint32_t i = 0; i < N; ++i) {
2096 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2097 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2098 ++_i_am_the_modifier;
2099 e->set_active (_route->phase_invert (i));
2100 --_i_am_the_modifier;
2103 _invert_menu->popup (0, ev->time);
2109 RouteUI::invert_menu_toggled (uint32_t c)
2111 if (_i_am_the_modifier) {
2115 _route->set_phase_invert (c, !_route->phase_invert (c));
2119 RouteUI::set_invert_sensitive (bool yn)
2121 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2122 (*b)->set_sensitive (yn);
2127 RouteUI::request_redraw ()
2130 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2134 /** The Route's gui_changed signal has been emitted */
2136 RouteUI::route_gui_changed (string what_changed)
2138 if (what_changed == "color") {
2139 if (set_color_from_route () == 0) {
2140 route_color_changed ();
2145 /** @return the color that this route should use; it maybe its own,
2146 or it maybe that of its route group.
2149 RouteUI::color () const
2151 RouteGroup* g = _route->route_group ();
2153 if (g && g->is_color()) {
2155 set_color_from_rgba (c, GroupTabs::group_color (g));
2163 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2165 _showing_sends_to = send_to;
2166 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2170 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2172 if (_route == send_to) {
2173 show_sends_button->set_active (true);
2174 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2176 show_sends_button->set_active (false);
2177 send_blink_connection.disconnect ();
2182 RouteUI::route_group() const
2184 return _route->route_group();