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.
21 #include <boost/algorithm/string.hpp>
23 #include "gtkmm2ext/gtk_ui.h"
24 #include "gtkmm2ext/choice.h"
25 #include "gtkmm2ext/doi.h"
26 #include "gtkmm2ext/bindable_button.h"
27 #include "gtkmm2ext/barcontroller.h"
28 #include "gtkmm2ext/gtk_ui.h"
29 #include "gtkmm2ext/utils.h"
31 #include "widgets/ardour_button.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/stacktrace.h"
35 #include "pbd/controllable.h"
36 #include "pbd/enumwriter.h"
38 #include "ardour/dB.h"
39 #include "ardour/route_group.h"
40 #include "ardour/solo_isolate_control.h"
41 #include "ardour/vca.h"
42 #include "ardour/vca_manager.h"
43 #include "ardour/audio_track.h"
44 #include "ardour/audio_port.h"
45 #include "ardour/audioengine.h"
46 #include "ardour/filename_extensions.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/monitor_control.h"
49 #include "ardour/internal_send.h"
50 #include "ardour/panner_shell.h"
51 #include "ardour/profile.h"
52 #include "ardour/phase_control.h"
53 #include "ardour/send.h"
54 #include "ardour/route.h"
55 #include "ardour/session.h"
56 #include "ardour/template_utils.h"
59 #include "ardour_dialog.h"
60 #include "ardour_ui.h"
61 #include "automation_time_axis.h"
63 #include "group_tabs.h"
64 #include "gui_object.h"
65 #include "gui_thread.h"
67 #include "latency_gui.h"
68 #include "mixer_strip.h"
69 #include "plugin_pin_dialog.h"
71 #include "rgb_macros.h"
72 #include "route_time_axis.h"
75 #include "ui_config.h"
81 using namespace Gtkmm2ext;
82 using namespace ARDOUR;
83 using namespace ARDOUR_UI_UTILS;
84 using namespace ArdourWidgets;
88 uint32_t RouteUI::_max_invert_buttons = 3;
89 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
90 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
91 std::string RouteUI::program_port_prefix;
93 RouteUI::RouteUI (ARDOUR::Session* sess)
94 : monitor_input_button (0)
95 , monitor_disk_button (0)
103 , output_selector (0)
106 if (program_port_prefix.empty()) {
107 // compare to gtk2_ardour/port_group.cc
108 string lpn (PROGRAM_NAME);
109 boost::to_lower (lpn);
110 program_port_prefix = lpn + ":"; // e.g. "ardour:"
121 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
124 _route.reset (); /* drop reference to route, so that it can be cleaned up */
125 route_connections.drop_connections ();
131 delete comment_window;
132 delete input_selector;
133 delete output_selector;
134 delete monitor_input_button;
135 delete monitor_disk_button;
138 send_blink_connection.disconnect ();
139 rec_blink_connection.disconnect ();
145 self_destruct = true;
151 pre_fader_mute_check = 0;
152 post_fader_mute_check = 0;
153 listen_mute_check = 0;
156 solo_isolated_check = 0;
157 solo_isolated_led = 0;
161 denormal_menu_item = 0;
164 multiple_mute_change = false;
165 multiple_solo_change = false;
166 _i_am_the_modifier = 0;
171 setup_invert_buttons ();
173 mute_button = manage (new ArdourButton);
174 mute_button->set_name ("mute button");
175 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
177 solo_button = manage (new ArdourButton);
178 solo_button->set_name ("solo button");
179 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
180 solo_button->set_no_show_all (true);
182 rec_enable_button = manage (new ArdourButton);
183 rec_enable_button->set_name ("record enable button");
184 rec_enable_button->set_icon (ArdourIcon::RecButton);
185 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
187 if (UIConfiguration::instance().get_blink_rec_arm()) {
188 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
191 show_sends_button = manage (new ArdourButton);
192 show_sends_button->set_name ("send alert button");
193 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
195 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
196 monitor_input_button->set_name ("monitor button");
197 monitor_input_button->set_text (_("In"));
198 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
199 monitor_input_button->set_no_show_all (true);
201 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
202 monitor_disk_button->set_name ("monitor button");
203 monitor_disk_button->set_text (_("Disk"));
204 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
205 monitor_disk_button->set_no_show_all (true);
207 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
208 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
209 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
211 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
212 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
213 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
215 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
216 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
218 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
219 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
221 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
222 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
223 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
224 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
226 monitor_input_button->set_distinct_led_click (false);
227 monitor_disk_button->set_distinct_led_click (false);
229 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
230 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
232 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
233 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
235 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
241 route_connections.drop_connections ();
249 _color_picker.reset ();
251 denormal_menu_item = 0;
255 RouteUI::self_delete ()
261 RouteUI::set_route (boost::shared_ptr<Route> rp)
267 if ( !_route->presentation_info().color_set() ) {
268 /* deal with older 4.x color, which was stored in the GUI object state */
270 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
274 /* old v4.x or earlier session. Use this information */
276 int red, green, blue;
281 /* old color format version was:
283 16bit value for red:16 bit value for green:16 bit value for blue
298 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
302 if (set_color_from_route()) {
303 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
307 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
310 delete input_selector;
313 delete output_selector;
316 mute_button->set_controllable (_route->mute_control());
317 solo_button->set_controllable (_route->solo_control());
319 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
321 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
323 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
324 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
325 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
326 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
327 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
328 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
331 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
332 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
333 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
335 track_mode_changed();
339 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
340 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
342 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
344 if (_session->writable() && is_track()) {
345 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
347 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
348 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
350 rec_enable_button->show();
351 rec_enable_button->set_controllable (t->rec_enable_control());
353 if (is_midi_track()) {
354 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
355 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
360 /* this will work for busses and tracks, and needs to be called to
361 set up the name entry/name label display.
365 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
366 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
368 update_monitoring_display ();
371 mute_button->unset_flags (Gtk::CAN_FOCUS);
372 solo_button->unset_flags (Gtk::CAN_FOCUS);
376 if (_route->is_monitor() || _route->is_master()) {
377 solo_button->hide ();
384 setup_invert_buttons ();
385 set_invert_button_state ();
387 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
388 bus_send_display_changed (s);
390 update_mute_display ();
391 update_solo_display ();
393 if (!UIConfiguration::instance().get_blink_rec_arm()) {
394 blink_rec_display(true); // set initial rec-en button state
397 check_rec_enable_sensitivity ();
398 maybe_add_route_print_mgr ();
399 route_color_changed();
400 route_gui_changed (PropertyChange (Properties::selected));
404 RouteUI::polarity_changed ()
410 set_invert_button_state ();
414 RouteUI::mute_press (GdkEventButton* ev)
416 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
420 //if this is a binding action, let the ArdourButton handle it
421 if ( BindingProxy::is_bind_action(ev) )
424 multiple_mute_change = false;
426 if (Keyboard::is_context_menu_event (ev)) {
432 mute_menu->popup(0,ev->time);
438 if (Keyboard::is_button2_event (ev)) {
439 // button2-click is "momentary"
441 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
444 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
446 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
448 /* toggle mute on everything (but
449 * exclude the master and monitor)
451 * because we are going to erase
452 * elements of the list we need to work
456 boost::shared_ptr<RouteList> copy (new RouteList);
458 *copy = *_session->get_routes ();
460 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
461 if ((*i)->is_master() || (*i)->is_monitor()) {
469 _mute_release->routes = copy;
472 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
474 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
476 /* Primary-button1 inverts the implication of
477 the group being active. If the group is
478 active (for mute), then this modifier means
479 "do not apply to mute". If the group is
480 inactive (for mute), then this modifier
481 means "apply to route". This is all
482 accomplished by passing just the actual
483 route, along with the InverseGroup group
486 NOTE: Primary-button2 is MIDI learn.
489 boost::shared_ptr<RouteList> rl;
491 if (ev->button == 1) {
493 rl.reset (new RouteList);
494 rl->push_back (_route);
497 _mute_release->routes = rl;
500 boost::shared_ptr<MuteControl> mc = _route->mute_control();
501 mc->start_touch (_session->audible_frame ());
502 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
507 /* plain click applies change to this route */
509 boost::shared_ptr<RouteList> rl (new RouteList);
510 rl->push_back (_route);
513 _mute_release->routes = rl;
516 boost::shared_ptr<MuteControl> mc = _route->mute_control();
517 mc->start_touch (_session->audible_frame ());
518 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
527 RouteUI::mute_release (GdkEventButton* /*ev*/)
530 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
531 delete _mute_release;
535 _route->mute_control()->stop_touch (false, _session->audible_frame ());
541 RouteUI::edit_output_configuration ()
543 if (output_selector == 0) {
545 boost::shared_ptr<Send> send;
546 boost::shared_ptr<IO> output;
548 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
549 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
550 output = send->output();
552 output = _route->output ();
555 output = _route->output ();
558 output_selector = new IOSelectorWindow (_session, output);
561 if (output_selector->is_visible()) {
562 output_selector->get_toplevel()->get_window()->raise();
564 output_selector->present ();
567 //output_selector->set_keep_above (true);
571 RouteUI::edit_input_configuration ()
573 if (input_selector == 0) {
574 input_selector = new IOSelectorWindow (_session, _route->input());
577 if (input_selector->is_visible()) {
578 input_selector->get_toplevel()->get_window()->raise();
580 input_selector->present ();
583 //input_selector->set_keep_above (true);
587 RouteUI::solo_press(GdkEventButton* ev)
589 /* ignore double/triple clicks */
591 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
595 //if this is a binding action, let the ArdourButton handle it
596 if ( BindingProxy::is_bind_action(ev) )
599 multiple_solo_change = false;
601 if (Keyboard::is_context_menu_event (ev)) {
603 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
604 ! (solo_safe_led && solo_safe_led->is_visible())) {
606 if (solo_menu == 0) {
610 solo_menu->popup (1, ev->time);
615 if (Keyboard::is_button2_event (ev)) {
617 // button2-click is "momentary"
618 _solo_release = new SoloMuteRelease (_route->self_soloed());
621 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
623 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
625 /* Primary-Tertiary-click applies change to all routes */
628 _solo_release->routes = _session->get_routes ();
631 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
633 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
635 /* Primary-Secondary-click: exclusively solo this track */
638 _solo_release->exclusive = true;
640 _solo_release->routes_on.reset (new RouteList);
641 _solo_release->routes_off.reset (new RouteList);
643 boost::shared_ptr<RouteList> routes = _session->get_routes();
644 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
646 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
650 if ((*i)->soloed ()) {
651 _solo_release->routes_on->push_back (*i);
653 _solo_release->routes_off->push_back (*i);
658 boost::shared_ptr<RouteList> rl (new RouteList);
659 boost::shared_ptr<RouteList> routes = _session->get_routes();
660 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
662 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
666 if ((*i)->soloed ()) {
670 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
672 if (Config->get_solo_control_is_listen_control()) {
673 /* ??? we need a just_one_listen() method */
676 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
679 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
681 // shift-click: toggle solo isolated status
683 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
684 delete _solo_release;
687 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
689 /* Primary-button1: solo mix group.
690 NOTE: Primary-button2 is MIDI learn.
693 /* Primary-button1 applies change to the mix group even if it is not active
694 NOTE: Primary-button2 is MIDI learn.
697 boost::shared_ptr<RouteList> rl;
699 if (ev->button == 1) {
701 /* Primary-button1 inverts the implication of
702 the group being active. If the group is
703 active (for solo), then this modifier means
704 "do not apply to solo". If the group is
705 inactive (for mute), then this modifier
706 means "apply to route". This is all
707 accomplished by passing just the actual
708 route, along with the InverseGroup group
711 NOTE: Primary-button2 is MIDI learn.
714 rl.reset (new RouteList);
715 rl->push_back (_route);
718 _solo_release->routes = rl;
721 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
724 delete _solo_release;
729 /* click: solo this route */
731 boost::shared_ptr<RouteList> rl (new RouteList);
732 rl->push_back (route());
735 _solo_release->routes = rl;
738 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
747 RouteUI::solo_release (GdkEventButton* /*ev*/)
750 if (_solo_release->exclusive) {
751 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
752 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
754 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
757 delete _solo_release;
765 RouteUI::rec_enable_press(GdkEventButton* ev)
767 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
771 //if this is a binding action, let the ArdourButton handle it
772 if ( BindingProxy::is_bind_action(ev) )
775 if (!_session->engine().connected()) {
776 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
781 if (is_midi_track()) {
783 /* rec-enable button exits from step editing */
785 if (midi_track()->step_editing()) {
786 midi_track()->set_step_editing (false);
791 if (is_track() && rec_enable_button) {
793 if (Keyboard::is_button2_event (ev)) {
795 //rec arm does not have a momentary mode
798 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
800 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
802 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
804 /* Primary-button1 applies change to the route group (even if it is not active)
805 NOTE: Primary-button2 is MIDI learn.
808 if (ev->button == 1) {
810 boost::shared_ptr<RouteList> rl;
812 rl.reset (new RouteList);
813 rl->push_back (_route);
815 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
818 } else if (Keyboard::is_context_menu_event (ev)) {
820 /* do this on release */
824 boost::shared_ptr<Track> trk = track();
825 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
833 RouteUI::update_monitoring_display ()
839 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
845 MonitorState ms = t->monitoring_state();
847 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
848 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
850 if (ms & MonitoringInput) {
851 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
853 monitor_input_button->unset_active_state ();
857 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
858 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
860 if (ms & MonitoringDisk) {
861 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
863 monitor_disk_button->unset_active_state ();
869 RouteUI::monitor_input_press(GdkEventButton*)
875 RouteUI::monitor_input_release(GdkEventButton* ev)
877 return monitor_release (ev, MonitorInput);
881 RouteUI::monitor_disk_press (GdkEventButton*)
887 RouteUI::monitor_disk_release (GdkEventButton* ev)
889 return monitor_release (ev, MonitorDisk);
893 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
895 if (ev->button != 1) {
899 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
906 boost::shared_ptr<RouteList> rl;
908 /* XXX for now, monitoring choices are orthogonal. cue monitoring
909 will follow in 3.X but requires mixing the input and playback (disk)
910 signal together, which requires yet more buffers.
913 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
914 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
916 /* this line will change when the options are non-orthogonal */
917 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
921 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
922 /* Primary-Tertiary-click applies change to all routes */
923 rl = _session->get_routes ();
924 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
925 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
926 /* Primary-click overrides group */
927 rl.reset (new RouteList);
928 rl->push_back (route());
929 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
931 rl.reset (new RouteList);
932 rl->push_back (route());
933 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
940 RouteUI::build_record_menu ()
943 record_menu = new Menu;
944 record_menu->set_name ("ArdourContextMenu");
945 using namespace Menu_Helpers;
946 MenuList& items = record_menu->items();
948 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
949 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
951 if (is_midi_track()) {
952 items.push_back (SeparatorElem());
953 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
954 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
958 if (step_edit_item) {
959 if (track()->rec_enable_control()->get_value()) {
960 step_edit_item->set_sensitive (false);
962 step_edit_item->set_active (midi_track()->step_editing());
965 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
966 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
971 RouteUI::toggle_step_edit ()
973 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
977 midi_track()->set_step_editing (step_edit_item->get_active());
981 RouteUI::toggle_rec_safe ()
983 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
989 /* This check is made inside the control too, but dong it here can't
993 if (_route->rec_enable_control()->get_value()) {
997 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
1001 RouteUI::step_edit_changed (bool yn)
1004 if (rec_enable_button) {
1005 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1008 start_step_editing ();
1010 if (step_edit_item) {
1011 step_edit_item->set_active (true);
1016 if (rec_enable_button) {
1017 rec_enable_button->unset_active_state ();
1020 stop_step_editing ();
1022 if (step_edit_item) {
1023 step_edit_item->set_active (false);
1029 RouteUI::rec_enable_release (GdkEventButton* ev)
1031 if (Keyboard::is_context_menu_event (ev)) {
1032 build_record_menu ();
1034 record_menu->popup (1, ev->time);
1043 RouteUI::build_sends_menu ()
1045 using namespace Menu_Helpers;
1047 sends_menu = new Menu;
1048 sends_menu->set_name ("ArdourContextMenu");
1049 MenuList& items = sends_menu->items();
1052 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1056 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1060 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1064 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1068 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1072 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1075 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1079 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1082 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1083 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1084 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1089 RouteUI::create_sends (Placement p, bool include_buses)
1091 _session->globally_add_internal_sends (_route, p, include_buses);
1095 RouteUI::create_selected_sends (Placement p, bool include_buses)
1097 boost::shared_ptr<RouteList> rlist (new RouteList);
1098 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1100 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1101 RouteTimeAxisView* rtv;
1103 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1104 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1105 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1106 rlist->push_back (rui->route());
1112 _session->add_internal_sends (_route, p, rlist);
1116 RouteUI::set_sends_gain_from_track ()
1118 _session->globally_set_send_gains_from_track (_route);
1122 RouteUI::set_sends_gain_to_zero ()
1124 _session->globally_set_send_gains_to_zero (_route);
1128 RouteUI::set_sends_gain_to_unity ()
1130 _session->globally_set_send_gains_to_unity (_route);
1134 RouteUI::show_sends_press(GdkEventButton* ev)
1136 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1140 if (!is_track() && show_sends_button) {
1142 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1144 // do nothing on midi sigc::bind event
1147 } else if (Keyboard::is_context_menu_event (ev)) {
1149 if (sends_menu == 0) {
1150 build_sends_menu ();
1153 sends_menu->popup (0, ev->time);
1157 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1160 set_showing_sends_to (boost::shared_ptr<Route> ());
1162 set_showing_sends_to (_route);
1171 RouteUI::show_sends_release (GdkEventButton*)
1177 RouteUI::send_blink (bool onoff)
1179 if (!show_sends_button) {
1184 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1186 show_sends_button->unset_active_state ();
1190 Gtkmm2ext::ActiveState
1191 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1193 boost::shared_ptr<SoloControl> sc = s->solo_control();
1196 return Gtkmm2ext::Off;
1199 if (!sc->can_solo()) {
1200 return Gtkmm2ext::Off;
1204 if (sc->self_soloed()) {
1205 return Gtkmm2ext::ExplicitActive;
1206 } else if (sc->soloed_by_others()) {
1207 return Gtkmm2ext::ImplicitActive;
1209 return Gtkmm2ext::Off;
1213 Gtkmm2ext::ActiveState
1214 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1216 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1219 return Gtkmm2ext::Off;
1222 if (s->is_master() || s->is_monitor()) {
1223 return Gtkmm2ext::Off;
1226 if (sc->solo_isolated()) {
1227 return Gtkmm2ext::ExplicitActive;
1229 return Gtkmm2ext::Off;
1233 Gtkmm2ext::ActiveState
1234 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1236 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1239 return Gtkmm2ext::Off;
1242 if (s->is_master() || s->is_monitor()) {
1243 return Gtkmm2ext::Off;
1246 if (sc->solo_safe()) {
1247 return Gtkmm2ext::ExplicitActive;
1249 return Gtkmm2ext::Off;
1254 RouteUI::update_solo_display ()
1256 bool yn = _route->solo_safe_control()->solo_safe ();
1258 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1259 solo_safe_check->set_active (yn);
1262 yn = _route->solo_isolate_control()->solo_isolated ();
1264 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1265 solo_isolated_check->set_active (yn);
1268 set_button_names ();
1270 if (solo_isolated_led) {
1271 if (_route->solo_isolate_control()->solo_isolated()) {
1272 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1274 solo_isolated_led->unset_active_state ();
1278 if (solo_safe_led) {
1279 if (_route->solo_safe_control()->solo_safe()) {
1280 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1282 solo_safe_led->unset_active_state ();
1286 solo_button->set_active_state (solo_active_state (_route));
1288 /* some changes to solo status can affect mute display, so catch up
1291 update_mute_display ();
1295 RouteUI::solo_changed_so_update_mute ()
1297 update_mute_display ();
1301 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1303 boost::shared_ptr<MuteControl> mc = s->mute_control();
1305 if (s->is_monitor()) {
1306 return Gtkmm2ext::Off;
1310 return Gtkmm2ext::Off;
1313 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1315 if (mc->muted_by_self ()) {
1317 return Gtkmm2ext::ExplicitActive;
1318 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1319 /* this will reflect both solo mutes AND master mutes */
1320 return Gtkmm2ext::ImplicitActive;
1322 /* no mute at all */
1323 return Gtkmm2ext::Off;
1328 if (mc->muted_by_self()) {
1330 return Gtkmm2ext::ExplicitActive;
1331 } else if (mc->muted_by_masters ()) {
1332 /* this shows only master mutes, not mute-by-others-soloing */
1333 return Gtkmm2ext::ImplicitActive;
1335 /* no mute at all */
1336 return Gtkmm2ext::Off;
1340 return ActiveState(0);
1344 RouteUI::update_mute_display ()
1350 mute_button->set_active_state (mute_active_state (_session, _route));
1355 RouteUI::route_rec_enable_changed ()
1357 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1361 RouteUI::session_rec_enable_changed ()
1363 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1367 RouteUI::blink_rec_display (bool blinkOn)
1369 if (!rec_enable_button || !_route) {
1373 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1381 if (track()->rec_enable_control()->get_value()) {
1382 switch (_session->record_status ()) {
1383 case Session::Recording:
1384 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1387 case Session::Disabled:
1388 case Session::Enabled:
1389 if (UIConfiguration::instance().get_blink_rec_arm()) {
1390 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1392 rec_enable_button->set_active_state ( ImplicitActive );
1397 if (step_edit_item) {
1398 step_edit_item->set_sensitive (false);
1402 rec_enable_button->unset_active_state ();
1404 if (step_edit_item) {
1405 step_edit_item->set_sensitive (true);
1409 check_rec_enable_sensitivity ();
1413 RouteUI::build_solo_menu (void)
1415 using namespace Menu_Helpers;
1417 solo_menu = new Menu;
1418 solo_menu->set_name ("ArdourContextMenu");
1419 MenuList& items = solo_menu->items();
1420 Gtk::CheckMenuItem* check;
1422 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1423 check->set_active (_route->solo_isolate_control()->solo_isolated());
1424 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1425 items.push_back (CheckMenuElem(*check));
1426 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1429 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1430 check->set_active (_route->solo_safe_control()->solo_safe());
1431 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1432 items.push_back (CheckMenuElem(*check));
1433 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1436 //items.push_back (SeparatorElem());
1437 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1442 RouteUI::build_mute_menu(void)
1444 using namespace Menu_Helpers;
1446 mute_menu = new Menu;
1447 mute_menu->set_name ("ArdourContextMenu");
1449 MenuList& items = mute_menu->items();
1451 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1452 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1453 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1454 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1455 pre_fader_mute_check->show_all();
1457 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1458 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1459 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1460 items.push_back (CheckMenuElem(*post_fader_mute_check));
1461 post_fader_mute_check->show_all();
1463 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1464 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1465 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1466 items.push_back (CheckMenuElem(*listen_mute_check));
1467 listen_mute_check->show_all();
1469 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1470 init_mute_menu(MuteMaster::Main, main_mute_check);
1471 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1472 items.push_back (CheckMenuElem(*main_mute_check));
1473 main_mute_check->show_all();
1475 //items.push_back (SeparatorElem());
1476 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1478 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1482 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1484 check->set_active (_route->mute_control()->mute_points() & mp);
1488 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1490 if (check->get_active()) {
1491 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1493 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1498 RouteUI::muting_change ()
1500 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1503 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1505 yn = (current & MuteMaster::PreFader);
1507 if (pre_fader_mute_check->get_active() != yn) {
1508 pre_fader_mute_check->set_active (yn);
1511 yn = (current & MuteMaster::PostFader);
1513 if (post_fader_mute_check->get_active() != yn) {
1514 post_fader_mute_check->set_active (yn);
1517 yn = (current & MuteMaster::Listen);
1519 if (listen_mute_check->get_active() != yn) {
1520 listen_mute_check->set_active (yn);
1523 yn = (current & MuteMaster::Main);
1525 if (main_mute_check->get_active() != yn) {
1526 main_mute_check->set_active (yn);
1531 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1533 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1537 bool view = solo_isolated_led->active_state();
1538 bool model = _route->solo_isolate_control()->solo_isolated();
1540 /* called BEFORE the view has changed */
1542 if (ev->button == 1) {
1543 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1546 /* disable isolate for all routes */
1547 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1549 /* enable isolate for all routes */
1550 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1555 if (model == view) {
1557 /* flip just this route */
1559 boost::shared_ptr<RouteList> rl (new RouteList);
1560 rl->push_back (_route);
1561 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1570 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1572 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1576 bool view = solo_safe_led->active_state();
1577 bool model = _route->solo_safe_control()->solo_safe();
1579 if (ev->button == 1) {
1580 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1581 boost::shared_ptr<RouteList> rl (_session->get_routes());
1583 /* disable solo safe for all routes */
1584 DisplaySuspender ds;
1585 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1586 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1589 /* enable solo safe for all routes */
1590 DisplaySuspender ds;
1591 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1592 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1597 if (model == view) {
1598 /* flip just this route */
1599 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1608 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1610 bool view = check->get_active();
1611 bool model = _route->solo_isolate_control()->solo_isolated();
1613 /* called AFTER the view has changed */
1615 if (model != view) {
1616 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1621 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1623 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1626 /** Ask the user to choose a colour, and then apply that color to my route */
1628 RouteUI::choose_color ()
1630 _color_picker.popup (_route);
1633 /** Set the route's own color. This may not be used for display if
1634 * the route is in a group which shares its color with its routes.
1637 RouteUI::set_color (uint32_t c)
1639 _route->presentation_info().set_color (c);
1642 /** @return GUI state ID for things that are common to the route in all its representations */
1644 RouteUI::route_state_id () const
1646 return string_compose (X_("route %1"), _route->id().to_s());
1650 RouteUI::set_color_from_route ()
1652 if (_route->presentation_info().color_set()) {
1653 return 0; /* nothing to do */
1656 return 1; /* pick a color */
1659 /** @return true if this name should be used for the route, otherwise false */
1661 RouteUI::verify_new_route_name (const std::string& name)
1663 if (name.find (':') == string::npos) {
1667 MessageDialog colon_msg (
1668 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1669 false, MESSAGE_QUESTION, BUTTONS_NONE
1672 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1673 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1675 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1679 RouteUI::route_rename ()
1681 ArdourPrompter name_prompter (true);
1686 name_prompter.set_title (_("Rename Track"));
1688 name_prompter.set_title (_("Rename Bus"));
1690 name_prompter.set_prompt (_("New name:"));
1691 name_prompter.set_initial_text (_route->name());
1692 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1693 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1694 name_prompter.show_all ();
1697 switch (name_prompter.run ()) {
1698 case Gtk::RESPONSE_ACCEPT:
1699 name_prompter.get_result (result);
1700 name_prompter.hide ();
1701 if (result.length()) {
1702 if (verify_new_route_name (result)) {
1703 _route->set_name (result);
1706 /* back to name prompter */
1710 /* nothing entered, just get out of here */
1725 RouteUI::toggle_comment_editor ()
1727 // if (ignore_toggle) {
1731 if (comment_window && comment_window->is_visible ()) {
1732 comment_window->hide ();
1734 open_comment_editor ();
1740 RouteUI::open_comment_editor ()
1742 if (comment_window == 0) {
1743 setup_comment_editor ();
1747 title = _route->name();
1748 title += _(": comment editor");
1750 comment_window->set_title (title);
1751 comment_window->present();
1755 RouteUI::setup_comment_editor ()
1757 comment_window = new ArdourWindow (""); // title will be reset to show route
1758 comment_window->set_skip_taskbar_hint (true);
1759 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1760 comment_window->set_default_size (400, 200);
1762 comment_area = manage (new TextView());
1763 comment_area->set_name ("MixerTrackCommentArea");
1764 comment_area->set_wrap_mode (WRAP_WORD);
1765 comment_area->set_editable (true);
1766 comment_area->get_buffer()->set_text (_route->comment());
1767 comment_area->show ();
1769 comment_window->add (*comment_area);
1773 RouteUI::comment_changed ()
1775 ignore_comment_edit = true;
1777 comment_area->get_buffer()->set_text (_route->comment());
1779 ignore_comment_edit = false;
1783 RouteUI::comment_editor_done_editing ()
1785 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1787 string const str = comment_area->get_buffer()->get_text();
1788 if (str == _route->comment ()) {
1792 _route->set_comment (str, this);
1796 RouteUI::set_route_active (bool a, bool apply_to_selection)
1798 if (apply_to_selection) {
1799 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1801 _route->set_active (a, this);
1806 RouteUI::duplicate_selected_routes ()
1808 ARDOUR_UI::instance()->start_duplicate_routes();
1812 RouteUI::toggle_denormal_protection ()
1814 if (denormal_menu_item) {
1818 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1820 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1821 _route->set_denormal_protection (x);
1827 RouteUI::denormal_protection_changed ()
1829 if (denormal_menu_item) {
1830 denormal_menu_item->set_active (_route->denormal_protection());
1835 RouteUI::disconnect_input ()
1837 _route->input()->disconnect (this);
1841 RouteUI::disconnect_output ()
1843 _route->output()->disconnect (this);
1847 RouteUI::is_track () const
1849 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1852 boost::shared_ptr<Track>
1853 RouteUI::track() const
1855 return boost::dynamic_pointer_cast<Track>(_route);
1859 RouteUI::is_audio_track () const
1861 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1864 boost::shared_ptr<AudioTrack>
1865 RouteUI::audio_track() const
1867 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1871 RouteUI::is_midi_track () const
1873 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1876 boost::shared_ptr<MidiTrack>
1877 RouteUI::midi_track() const
1879 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1883 RouteUI::has_audio_outputs () const
1885 return (_route->n_outputs().n_audio() > 0);
1889 RouteUI::map_frozen ()
1891 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1893 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1896 check_rec_enable_sensitivity ();
1901 RouteUI::adjust_latency ()
1903 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1907 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1910 std::string safe_name;
1913 prompter.get_result (name, true);
1915 safe_name = legalize_for_path (name);
1916 safe_name += template_suffix;
1918 path = Glib::build_filename (dir, safe_name);
1920 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1921 bool overwrite = overwrite_file_dialog (prompter,
1922 _("Confirm Template Overwrite"),
1923 _("A template already exists with that name. Do you want to overwrite it?"));
1930 _route->save_as_template (path, name);
1936 RouteUI::save_as_template ()
1940 dir = ARDOUR::user_route_template_directory ();
1942 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1943 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1947 ArdourPrompter prompter (true); // modal
1949 prompter.set_title (_("Save As Template"));
1950 prompter.set_prompt (_("Template name:"));
1951 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1953 bool finished = false;
1955 switch (prompter.run()) {
1956 case RESPONSE_ACCEPT:
1957 finished = process_save_template_prompter (prompter, dir);
1967 RouteUI::check_rec_enable_sensitivity ()
1969 if (!rec_enable_button) {
1970 assert (0); // This should not happen
1973 if (!_session->writable()) {
1974 rec_enable_button->set_sensitive (false);
1978 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1979 rec_enable_button->set_sensitive (false);
1980 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1981 rec_enable_button->set_sensitive (false);
1983 rec_enable_button->set_sensitive (true);
1985 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1986 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1988 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1990 update_monitoring_display ();
1994 RouteUI::parameter_changed (string const & p)
1996 /* this handles RC and per-session parameter changes */
1998 if (p == "disable-disarm-during-roll") {
1999 check_rec_enable_sensitivity ();
2000 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2001 set_button_names ();
2002 } else if (p == "session-monitoring") {
2003 update_monitoring_display ();
2004 } else if (p == "auto-input") {
2005 update_monitoring_display ();
2006 } else if (p == "blink-rec-arm") {
2007 if (UIConfiguration::instance().get_blink_rec_arm()) {
2008 rec_blink_connection.disconnect ();
2009 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2011 rec_blink_connection.disconnect ();
2012 RouteUI::blink_rec_display(false);
2018 RouteUI::setup_invert_buttons ()
2020 /* remove old invert buttons */
2021 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2022 _invert_button_box.remove (**i);
2025 _invert_buttons.clear ();
2027 if (!_route || !_route->input()) {
2031 uint32_t const N = _route->input()->n_ports().n_audio ();
2033 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2035 for (uint32_t i = 0; i < to_add; ++i) {
2036 ArdourButton* b = manage (new ArdourButton);
2037 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2038 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2040 b->set_name (X_("invert button"));
2043 b->set_text (string_compose (X_("Ø (%1)"), N));
2045 b->set_text (X_("Ø"));
2048 b->set_text (string_compose (X_("Ø%1"), i + 1));
2051 if (N <= _max_invert_buttons) {
2052 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert polarity of channel %1 of this track. Right-click to show menu."), i + 1));
2054 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2057 _invert_buttons.push_back (b);
2058 _invert_button_box.pack_start (*b);
2061 _invert_button_box.set_spacing (1);
2062 _invert_button_box.show_all ();
2066 RouteUI::set_invert_button_state ()
2068 uint32_t const N = _route->input()->n_ports().n_audio();
2069 if (N > _max_invert_buttons) {
2071 /* One button for many channels; explicit active if all channels are inverted,
2072 implicit active if some are, off if none are.
2075 ArdourButton* b = _invert_buttons.front ();
2077 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2078 b->set_active_state (Gtkmm2ext::ExplicitActive);
2079 } else if (_route->phase_control()->any()) {
2080 b->set_active_state (Gtkmm2ext::ImplicitActive);
2082 b->set_active_state (Gtkmm2ext::Off);
2087 /* One button per channel; just set active */
2090 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2091 (*i)->set_active (_route->phase_control()->inverted (j));
2098 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2100 if (ev->button == 1 && i < _invert_buttons.size()) {
2101 uint32_t const N = _route->input()->n_ports().n_audio ();
2102 if (N <= _max_invert_buttons) {
2103 /* left-click inverts phase so long as we have a button per channel */
2104 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2113 RouteUI::invert_press (GdkEventButton* ev)
2115 using namespace Menu_Helpers;
2117 uint32_t const N = _route->input()->n_ports().n_audio();
2118 if (N <= _max_invert_buttons && ev->button != 3) {
2119 /* If we have an invert button per channel, we only pop
2120 up a menu on right-click; left click is handled
2126 delete _invert_menu;
2127 _invert_menu = new Menu;
2128 _invert_menu->set_name ("ArdourContextMenu");
2129 MenuList& items = _invert_menu->items ();
2131 for (uint32_t i = 0; i < N; ++i) {
2132 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2133 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2134 ++_i_am_the_modifier;
2135 e->set_active (_route->phase_control()->inverted (i));
2136 --_i_am_the_modifier;
2139 _invert_menu->popup (0, ev->time);
2145 RouteUI::invert_menu_toggled (uint32_t c)
2147 if (_i_am_the_modifier) {
2152 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2156 RouteUI::set_invert_sensitive (bool yn)
2158 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2159 (*b)->set_sensitive (yn);
2163 /** The Route's gui_changed signal has been emitted */
2165 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2167 if (what_changed.contains (Properties::color)) {
2168 if (set_color_from_route () == 0) {
2169 route_color_changed ();
2175 RouteUI::track_mode_changed (void)
2178 switch (track()->mode()) {
2179 case ARDOUR::NonLayered:
2180 case ARDOUR::Normal:
2181 rec_enable_button->set_icon (ArdourIcon::RecButton);
2183 case ARDOUR::Destructive:
2184 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2187 rec_enable_button->queue_draw();
2190 /** @return the color that this route should use; it maybe its own,
2191 * or it maybe that of its route group.
2194 RouteUI::route_color () const
2197 RouteGroup* g = _route->route_group ();
2200 if (g && g->is_color()) {
2201 set_color_from_rgba (c, GroupTabs::group_color (g));
2203 set_color_from_rgba (c, _route->presentation_info().color());
2210 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2212 _showing_sends_to = send_to;
2213 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2217 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2219 if (_route == send_to) {
2220 show_sends_button->set_active (true);
2221 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2223 show_sends_button->set_active (false);
2224 send_blink_connection.disconnect ();
2229 RouteUI::route_group() const
2231 return _route->route_group();
2235 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2236 : WM::ProxyBase (name, string())
2237 , _route (boost::weak_ptr<Route> (route))
2239 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2242 RoutePinWindowProxy::~RoutePinWindowProxy()
2247 ARDOUR::SessionHandlePtr*
2248 RoutePinWindowProxy::session_handle ()
2250 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2251 if (aw) { return aw; }
2256 RoutePinWindowProxy::get (bool create)
2258 boost::shared_ptr<Route> r = _route.lock ();
2267 _window = new PluginPinDialog (r);
2268 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2270 aw->set_session (_session);
2272 _window->show_all ();
2278 RoutePinWindowProxy::route_going_away ()
2282 WM::Manager::instance().remove (this);
2283 going_away_connection.disconnect();
2288 RouteUI::maybe_add_route_print_mgr ()
2290 if (_route->pinmgr_proxy ()) {
2293 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2294 string_compose ("RPM-%1", _route->id()), _route);
2295 wp->set_session (_session);
2297 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2299 wp->set_state (*ui_xml, 0);
2303 void* existing_ui = _route->pinmgr_proxy ();
2305 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2308 _route->set_pingmgr_proxy (wp);
2310 WM::Manager::instance().register_window (wp);
2314 RouteUI::manage_pins ()
2316 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2324 RouteUI::fan_out (bool to_busses, bool group)
2326 DisplaySuspender ds;
2327 boost::shared_ptr<ARDOUR::Route> route = _route;
2328 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2331 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2332 if (route->n_outputs ().n_audio () != n_outputs) {
2333 MessageDialog msg (string_compose (
2334 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2335 n_outputs, route->n_outputs ().n_audio ()));
2340 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2342 /* count busses and channels/bus */
2343 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2344 std::map<std::string, uint32_t> busnames;
2345 for (uint32_t p = 0; p < n_outputs; ++p) {
2346 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2347 std::string bn = BUSNAME;
2351 if (busnames.size () < 2) {
2352 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2357 uint32_t outputs = 2;
2358 if (_session->master_out ()) {
2359 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2362 route->output ()->disconnect (this);
2363 route->panner_shell ()->set_bypassed (true);
2366 for (uint32_t p = 0; p < n_outputs; ++p) {
2367 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2368 std::string bn = BUSNAME;
2369 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2372 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2376 list<boost::shared_ptr<AudioTrack> > tl =
2377 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2381 boost::shared_ptr<ControlList> cl (new ControlList);
2382 cl->push_back (r->monitoring_control ());
2383 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2385 r->input ()->disconnect (this);
2387 to_group.push_back (r);
2388 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2393 RouteGroup* rg = NULL;
2394 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2395 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2396 if ((*i)->name () == pi->name ()) {
2402 rg = new RouteGroup (*_session, pi->name ());
2403 _session->add_route_group (rg);
2404 rg->set_gain (false);
2407 GroupTabs::set_group_color (rg, route->presentation_info().color());
2408 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2415 RouteUI::mark_hidden (bool yn)
2417 if (yn != _route->presentation_info().hidden()) {
2418 _route->presentation_info().set_hidden (yn);
2419 return true; // things changed
2424 boost::shared_ptr<Stripable>
2425 RouteUI::stripable () const