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 "pbd/memento_command.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour/dB.h"
37 #include "ardour/route_group.h"
38 #include "ardour/solo_isolate_control.h"
39 #include "ardour/vca.h"
40 #include "ardour/vca_manager.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/filename_extensions.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/monitor_control.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/profile.h"
50 #include "ardour/phase_control.h"
51 #include "ardour/send.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/template_utils.h"
56 #include "ardour_button.h"
57 #include "ardour_dialog.h"
58 #include "ardour_ui.h"
59 #include "automation_time_axis.h"
61 #include "group_tabs.h"
62 #include "gui_object.h"
63 #include "gui_thread.h"
65 #include "latency_gui.h"
66 #include "mixer_strip.h"
67 #include "plugin_pin_dialog.h"
69 #include "rgb_macros.h"
70 #include "route_time_axis.h"
73 #include "ui_config.h"
79 using namespace Gtkmm2ext;
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
85 uint32_t RouteUI::_max_invert_buttons = 3;
86 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
87 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
88 std::string RouteUI::program_port_prefix;
90 RouteUI::RouteUI (ARDOUR::Session* sess)
91 : monitor_input_button (0)
92 , monitor_disk_button (0)
100 , output_selector (0)
103 if (program_port_prefix.empty()) {
104 // compare to gtk2_ardour/port_group.cc
105 string lpn (PROGRAM_NAME);
106 boost::to_lower (lpn);
107 program_port_prefix = lpn + ":"; // e.g. "ardour:"
118 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
121 _route.reset (); /* drop reference to route, so that it can be cleaned up */
122 route_connections.drop_connections ();
128 delete comment_window;
129 delete input_selector;
130 delete output_selector;
131 delete monitor_input_button;
132 delete monitor_disk_button;
135 send_blink_connection.disconnect ();
136 rec_blink_connection.disconnect ();
142 self_destruct = true;
148 pre_fader_mute_check = 0;
149 post_fader_mute_check = 0;
150 listen_mute_check = 0;
153 solo_isolated_check = 0;
154 solo_isolated_led = 0;
158 denormal_menu_item = 0;
161 multiple_mute_change = false;
162 multiple_solo_change = false;
163 _i_am_the_modifier = 0;
168 setup_invert_buttons ();
170 mute_button = manage (new ArdourButton);
171 mute_button->set_name ("mute button");
172 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
174 solo_button = manage (new ArdourButton);
175 solo_button->set_name ("solo button");
176 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
177 solo_button->set_no_show_all (true);
179 rec_enable_button = manage (new ArdourButton);
180 rec_enable_button->set_name ("record enable button");
181 rec_enable_button->set_icon (ArdourIcon::RecButton);
182 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
184 if (UIConfiguration::instance().get_blink_rec_arm()) {
185 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
188 show_sends_button = manage (new ArdourButton);
189 show_sends_button->set_name ("send alert button");
190 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
192 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
193 monitor_input_button->set_name ("monitor button");
194 monitor_input_button->set_text (_("In"));
195 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
196 monitor_input_button->set_no_show_all (true);
198 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_disk_button->set_name ("monitor button");
200 monitor_disk_button->set_text (_("Disk"));
201 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
202 monitor_disk_button->set_no_show_all (true);
204 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
205 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
206 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
208 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
209 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
212 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
213 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
215 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
216 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
218 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
219 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
220 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
221 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
223 monitor_input_button->set_distinct_led_click (false);
224 monitor_disk_button->set_distinct_led_click (false);
226 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
227 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
229 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
230 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
232 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
238 route_connections.drop_connections ();
246 denormal_menu_item = 0;
250 RouteUI::self_delete ()
256 RouteUI::set_route (boost::shared_ptr<Route> rp)
262 if ( !_route->presentation_info().color_set() ) {
263 /* deal with older 4.x color, which was stored in the GUI object state */
265 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
269 /* old v4.x or earlier session. Use this information */
271 int red, green, blue;
276 /* old color format version was:
278 16bit value for red:16 bit value for green:16 bit value for blue
293 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
297 if (set_color_from_route()) {
298 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
302 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
305 delete input_selector;
308 delete output_selector;
311 mute_button->set_controllable (_route->mute_control());
312 solo_button->set_controllable (_route->solo_control());
314 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
316 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
318 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
319 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
320 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
321 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
322 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
323 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
326 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
327 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
328 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
330 track_mode_changed();
334 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
335 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
337 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
339 if (_session->writable() && is_track()) {
340 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
342 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
343 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
345 rec_enable_button->show();
346 rec_enable_button->set_controllable (t->rec_enable_control());
348 if (is_midi_track()) {
349 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
350 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
355 /* this will work for busses and tracks, and needs to be called to
356 set up the name entry/name label display.
360 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
361 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
363 update_monitoring_display ();
366 mute_button->unset_flags (Gtk::CAN_FOCUS);
367 solo_button->unset_flags (Gtk::CAN_FOCUS);
371 if (_route->is_monitor() || _route->is_master()) {
372 solo_button->hide ();
379 setup_invert_buttons ();
380 set_invert_button_state ();
382 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
383 bus_send_display_changed (s);
385 update_mute_display ();
386 update_solo_display ();
388 if (!UIConfiguration::instance().get_blink_rec_arm()) {
389 blink_rec_display(true); // set initial rec-en button state
392 check_rec_enable_sensitivity ();
393 maybe_add_route_print_mgr ();
394 route_color_changed();
395 route_gui_changed (PropertyChange (Properties::selected));
399 RouteUI::polarity_changed ()
405 set_invert_button_state ();
409 RouteUI::mute_press (GdkEventButton* ev)
411 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
415 //if this is a binding action, let the ArdourButton handle it
416 if ( BindingProxy::is_bind_action(ev) )
419 multiple_mute_change = false;
421 if (Keyboard::is_context_menu_event (ev)) {
427 mute_menu->popup(0,ev->time);
433 if (Keyboard::is_button2_event (ev)) {
434 // button2-click is "momentary"
436 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
439 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
441 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
443 /* toggle mute on everything (but
444 * exclude the master and monitor)
446 * because we are going to erase
447 * elements of the list we need to work
451 boost::shared_ptr<RouteList> copy (new RouteList);
453 *copy = *_session->get_routes ();
455 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
456 if ((*i)->is_master() || (*i)->is_monitor()) {
464 _mute_release->routes = copy;
467 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
469 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
471 /* Primary-button1 inverts the implication of
472 the group being active. If the group is
473 active (for mute), then this modifier means
474 "do not apply to mute". If the group is
475 inactive (for mute), then this modifier
476 means "apply to route". This is all
477 accomplished by passing just the actual
478 route, along with the InverseGroup group
481 NOTE: Primary-button2 is MIDI learn.
484 boost::shared_ptr<RouteList> rl;
486 if (ev->button == 1) {
488 rl.reset (new RouteList);
489 rl->push_back (_route);
492 _mute_release->routes = rl;
495 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
500 /* plain click applies change to this route */
502 boost::shared_ptr<RouteList> rl (new RouteList);
503 rl->push_back (_route);
506 _mute_release->routes = rl;
509 _route->mute_control()->set_value (!_route->muted_by_self(), Controllable::UseGroup);
518 RouteUI::mute_release (GdkEventButton* /*ev*/)
521 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
522 delete _mute_release;
530 RouteUI::edit_output_configuration ()
532 if (output_selector == 0) {
534 boost::shared_ptr<Send> send;
535 boost::shared_ptr<IO> output;
537 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
538 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
539 output = send->output();
541 output = _route->output ();
544 output = _route->output ();
547 output_selector = new IOSelectorWindow (_session, output);
550 if (output_selector->is_visible()) {
551 output_selector->get_toplevel()->get_window()->raise();
553 output_selector->present ();
556 //output_selector->set_keep_above (true);
560 RouteUI::edit_input_configuration ()
562 if (input_selector == 0) {
563 input_selector = new IOSelectorWindow (_session, _route->input());
566 if (input_selector->is_visible()) {
567 input_selector->get_toplevel()->get_window()->raise();
569 input_selector->present ();
572 //input_selector->set_keep_above (true);
576 RouteUI::solo_press(GdkEventButton* ev)
578 /* ignore double/triple clicks */
580 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
584 //if this is a binding action, let the ArdourButton handle it
585 if ( BindingProxy::is_bind_action(ev) )
588 multiple_solo_change = false;
590 if (Keyboard::is_context_menu_event (ev)) {
592 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
593 ! (solo_safe_led && solo_safe_led->is_visible())) {
595 if (solo_menu == 0) {
599 solo_menu->popup (1, ev->time);
604 if (Keyboard::is_button2_event (ev)) {
606 // button2-click is "momentary"
607 _solo_release = new SoloMuteRelease (_route->self_soloed());
610 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
612 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
614 /* Primary-Tertiary-click applies change to all routes */
617 _solo_release->routes = _session->get_routes ();
620 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
622 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
624 // Primary-Secondary-click: exclusively solo this track
627 _solo_release->exclusive = true;
629 boost::shared_ptr<RouteList> routes = _session->get_routes();
631 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
632 if ((*i)->soloed ()) {
633 _solo_release->routes_on->push_back (*i);
635 _solo_release->routes_off->push_back (*i);
640 if (Config->get_solo_control_is_listen_control()) {
641 /* ??? we need a just_one_listen() method */
644 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
647 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
649 // shift-click: toggle solo isolated status
651 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
652 delete _solo_release;
655 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
657 /* Primary-button1: solo mix group.
658 NOTE: Primary-button2 is MIDI learn.
661 /* Primary-button1 applies change to the mix group even if it is not active
662 NOTE: Primary-button2 is MIDI learn.
665 boost::shared_ptr<RouteList> rl;
667 if (ev->button == 1) {
669 /* Primary-button1 inverts the implication of
670 the group being active. If the group is
671 active (for solo), then this modifier means
672 "do not apply to solo". If the group is
673 inactive (for mute), then this modifier
674 means "apply to route". This is all
675 accomplished by passing just the actual
676 route, along with the InverseGroup group
679 NOTE: Primary-button2 is MIDI learn.
682 rl.reset (new RouteList);
683 rl->push_back (_route);
686 _solo_release->routes = rl;
689 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
692 delete _solo_release;
697 /* click: solo this route */
699 boost::shared_ptr<RouteList> rl (new RouteList);
700 rl->push_back (route());
703 _solo_release->routes = rl;
706 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
715 RouteUI::solo_release (GdkEventButton* /*ev*/)
719 if (_solo_release->exclusive) {
722 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
725 delete _solo_release;
733 RouteUI::rec_enable_press(GdkEventButton* ev)
735 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
739 //if this is a binding action, let the ArdourButton handle it
740 if ( BindingProxy::is_bind_action(ev) )
743 if (!_session->engine().connected()) {
744 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
749 if (is_midi_track()) {
751 /* rec-enable button exits from step editing */
753 if (midi_track()->step_editing()) {
754 midi_track()->set_step_editing (false);
759 if (is_track() && rec_enable_button) {
761 if (Keyboard::is_button2_event (ev)) {
763 //rec arm does not have a momentary mode
766 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
768 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
770 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
772 /* Primary-button1 applies change to the route group (even if it is not active)
773 NOTE: Primary-button2 is MIDI learn.
776 if (ev->button == 1) {
778 boost::shared_ptr<RouteList> rl;
780 rl.reset (new RouteList);
781 rl->push_back (_route);
783 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
786 } else if (Keyboard::is_context_menu_event (ev)) {
788 /* do this on release */
792 boost::shared_ptr<Track> trk = track();
793 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
801 RouteUI::update_monitoring_display ()
807 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
813 MonitorState ms = t->monitoring_state();
815 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
816 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
818 if (ms & MonitoringInput) {
819 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
821 monitor_input_button->unset_active_state ();
825 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
826 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
828 if (ms & MonitoringDisk) {
829 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
831 monitor_disk_button->unset_active_state ();
837 RouteUI::monitor_input_press(GdkEventButton*)
843 RouteUI::monitor_input_release(GdkEventButton* ev)
845 return monitor_release (ev, MonitorInput);
849 RouteUI::monitor_disk_press (GdkEventButton*)
855 RouteUI::monitor_disk_release (GdkEventButton* ev)
857 return monitor_release (ev, MonitorDisk);
861 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
863 if (ev->button != 1) {
867 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
874 boost::shared_ptr<RouteList> rl;
876 /* XXX for now, monitoring choices are orthogonal. cue monitoring
877 will follow in 3.X but requires mixing the input and playback (disk)
878 signal together, which requires yet more buffers.
881 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
882 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
884 /* this line will change when the options are non-orthogonal */
885 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
889 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
890 rl = _session->get_routes ();
892 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
893 if (_route->route_group() && _route->route_group()->is_monitoring()) {
894 rl = _route->route_group()->route_list();
896 rl.reset (new RouteList);
897 rl->push_back (route());
900 rl.reset (new RouteList);
901 rl->push_back (route());
904 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
910 RouteUI::build_record_menu ()
913 record_menu = new Menu;
914 record_menu->set_name ("ArdourContextMenu");
915 using namespace Menu_Helpers;
916 MenuList& items = record_menu->items();
918 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
919 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
921 if (is_midi_track()) {
922 items.push_back (SeparatorElem());
923 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
924 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
928 if (step_edit_item) {
929 if (track()->rec_enable_control()->get_value()) {
930 step_edit_item->set_sensitive (false);
932 step_edit_item->set_active (midi_track()->step_editing());
935 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
936 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
941 RouteUI::toggle_step_edit ()
943 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
947 midi_track()->set_step_editing (step_edit_item->get_active());
951 RouteUI::toggle_rec_safe ()
953 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
959 /* This check is made inside the control too, but dong it here can't
963 if (_route->rec_enable_control()->get_value()) {
967 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
971 RouteUI::step_edit_changed (bool yn)
974 if (rec_enable_button) {
975 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
978 start_step_editing ();
980 if (step_edit_item) {
981 step_edit_item->set_active (true);
986 if (rec_enable_button) {
987 rec_enable_button->unset_active_state ();
990 stop_step_editing ();
992 if (step_edit_item) {
993 step_edit_item->set_active (false);
999 RouteUI::rec_enable_release (GdkEventButton* ev)
1001 if (Keyboard::is_context_menu_event (ev)) {
1002 build_record_menu ();
1004 record_menu->popup (1, ev->time);
1013 RouteUI::build_sends_menu ()
1015 using namespace Menu_Helpers;
1017 sends_menu = new Menu;
1018 sends_menu->set_name ("ArdourContextMenu");
1019 MenuList& items = sends_menu->items();
1022 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1026 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1030 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1034 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1038 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1042 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1045 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1049 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1052 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1053 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1054 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1059 RouteUI::create_sends (Placement p, bool include_buses)
1061 _session->globally_add_internal_sends (_route, p, include_buses);
1065 RouteUI::create_selected_sends (Placement p, bool include_buses)
1067 boost::shared_ptr<RouteList> rlist (new RouteList);
1068 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1070 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1071 RouteTimeAxisView* rtv;
1073 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1074 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1075 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1076 rlist->push_back (rui->route());
1082 _session->add_internal_sends (_route, p, rlist);
1086 RouteUI::set_sends_gain_from_track ()
1088 _session->globally_set_send_gains_from_track (_route);
1092 RouteUI::set_sends_gain_to_zero ()
1094 _session->globally_set_send_gains_to_zero (_route);
1098 RouteUI::set_sends_gain_to_unity ()
1100 _session->globally_set_send_gains_to_unity (_route);
1104 RouteUI::show_sends_press(GdkEventButton* ev)
1106 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1110 if (!is_track() && show_sends_button) {
1112 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1114 // do nothing on midi sigc::bind event
1117 } else if (Keyboard::is_context_menu_event (ev)) {
1119 if (sends_menu == 0) {
1120 build_sends_menu ();
1123 sends_menu->popup (0, ev->time);
1127 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1130 set_showing_sends_to (boost::shared_ptr<Route> ());
1132 set_showing_sends_to (_route);
1141 RouteUI::show_sends_release (GdkEventButton*)
1147 RouteUI::send_blink (bool onoff)
1149 if (!show_sends_button) {
1154 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1156 show_sends_button->unset_active_state ();
1160 Gtkmm2ext::ActiveState
1161 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1163 boost::shared_ptr<SoloControl> sc = s->solo_control();
1166 return Gtkmm2ext::Off;
1169 if (!sc->can_solo()) {
1170 return Gtkmm2ext::Off;
1174 if (sc->self_soloed()) {
1175 return Gtkmm2ext::ExplicitActive;
1176 } else if (sc->soloed_by_others()) {
1177 return Gtkmm2ext::ImplicitActive;
1179 return Gtkmm2ext::Off;
1183 Gtkmm2ext::ActiveState
1184 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1186 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1189 return Gtkmm2ext::Off;
1192 if (s->is_master() || s->is_monitor()) {
1193 return Gtkmm2ext::Off;
1196 if (sc->solo_isolated()) {
1197 return Gtkmm2ext::ExplicitActive;
1199 return Gtkmm2ext::Off;
1203 Gtkmm2ext::ActiveState
1204 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1206 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1209 return Gtkmm2ext::Off;
1212 if (s->is_master() || s->is_monitor()) {
1213 return Gtkmm2ext::Off;
1216 if (sc->solo_safe()) {
1217 return Gtkmm2ext::ExplicitActive;
1219 return Gtkmm2ext::Off;
1224 RouteUI::update_solo_display ()
1226 bool yn = _route->solo_safe_control()->solo_safe ();
1228 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1229 solo_safe_check->set_active (yn);
1232 yn = _route->solo_isolate_control()->solo_isolated ();
1234 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1235 solo_isolated_check->set_active (yn);
1238 set_button_names ();
1240 if (solo_isolated_led) {
1241 if (_route->solo_isolate_control()->solo_isolated()) {
1242 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1244 solo_isolated_led->unset_active_state ();
1248 if (solo_safe_led) {
1249 if (_route->solo_safe_control()->solo_safe()) {
1250 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1252 solo_safe_led->unset_active_state ();
1256 solo_button->set_active_state (solo_active_state (_route));
1258 /* some changes to solo status can affect mute display, so catch up
1261 update_mute_display ();
1265 RouteUI::solo_changed_so_update_mute ()
1267 update_mute_display ();
1271 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1273 boost::shared_ptr<MuteControl> mc = s->mute_control();
1275 if (s->is_monitor()) {
1276 return Gtkmm2ext::Off;
1280 return Gtkmm2ext::Off;
1283 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1285 if (mc->muted_by_self ()) {
1287 return Gtkmm2ext::ExplicitActive;
1288 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1289 /* this will reflect both solo mutes AND master mutes */
1290 return Gtkmm2ext::ImplicitActive;
1292 /* no mute at all */
1293 return Gtkmm2ext::Off;
1298 if (mc->muted_by_self()) {
1300 return Gtkmm2ext::ExplicitActive;
1301 } else if (mc->muted_by_masters ()) {
1302 /* this shows only master mutes, not mute-by-others-soloing */
1303 return Gtkmm2ext::ImplicitActive;
1305 /* no mute at all */
1306 return Gtkmm2ext::Off;
1310 return ActiveState(0);
1314 RouteUI::update_mute_display ()
1320 mute_button->set_active_state (mute_active_state (_session, _route));
1325 RouteUI::route_rec_enable_changed ()
1327 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1331 RouteUI::session_rec_enable_changed ()
1333 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1337 RouteUI::blink_rec_display (bool blinkOn)
1339 if (!rec_enable_button || !_route) {
1343 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1351 if (track()->rec_enable_control()->get_value()) {
1352 switch (_session->record_status ()) {
1353 case Session::Recording:
1354 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1357 case Session::Disabled:
1358 case Session::Enabled:
1359 if (UIConfiguration::instance().get_blink_rec_arm()) {
1360 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1362 rec_enable_button->set_active_state ( ImplicitActive );
1367 if (step_edit_item) {
1368 step_edit_item->set_sensitive (false);
1372 rec_enable_button->unset_active_state ();
1374 if (step_edit_item) {
1375 step_edit_item->set_sensitive (true);
1379 check_rec_enable_sensitivity ();
1383 RouteUI::build_solo_menu (void)
1385 using namespace Menu_Helpers;
1387 solo_menu = new Menu;
1388 solo_menu->set_name ("ArdourContextMenu");
1389 MenuList& items = solo_menu->items();
1390 Gtk::CheckMenuItem* check;
1392 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1393 check->set_active (_route->solo_isolate_control()->solo_isolated());
1394 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1395 items.push_back (CheckMenuElem(*check));
1396 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1399 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1400 check->set_active (_route->solo_safe_control()->solo_safe());
1401 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1402 items.push_back (CheckMenuElem(*check));
1403 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1406 //items.push_back (SeparatorElem());
1407 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1412 RouteUI::build_mute_menu(void)
1414 using namespace Menu_Helpers;
1416 mute_menu = new Menu;
1417 mute_menu->set_name ("ArdourContextMenu");
1419 MenuList& items = mute_menu->items();
1421 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1422 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1423 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1424 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1425 pre_fader_mute_check->show_all();
1427 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1428 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1429 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1430 items.push_back (CheckMenuElem(*post_fader_mute_check));
1431 post_fader_mute_check->show_all();
1433 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1434 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1435 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1436 items.push_back (CheckMenuElem(*listen_mute_check));
1437 listen_mute_check->show_all();
1439 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1440 init_mute_menu(MuteMaster::Main, main_mute_check);
1441 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1442 items.push_back (CheckMenuElem(*main_mute_check));
1443 main_mute_check->show_all();
1445 //items.push_back (SeparatorElem());
1446 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1448 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1452 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1454 check->set_active (_route->mute_control()->mute_points() & mp);
1458 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1460 if (check->get_active()) {
1461 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1463 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1468 RouteUI::muting_change ()
1470 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1473 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1475 yn = (current & MuteMaster::PreFader);
1477 if (pre_fader_mute_check->get_active() != yn) {
1478 pre_fader_mute_check->set_active (yn);
1481 yn = (current & MuteMaster::PostFader);
1483 if (post_fader_mute_check->get_active() != yn) {
1484 post_fader_mute_check->set_active (yn);
1487 yn = (current & MuteMaster::Listen);
1489 if (listen_mute_check->get_active() != yn) {
1490 listen_mute_check->set_active (yn);
1493 yn = (current & MuteMaster::Main);
1495 if (main_mute_check->get_active() != yn) {
1496 main_mute_check->set_active (yn);
1501 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1503 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1507 bool view = solo_isolated_led->active_state();
1508 bool model = _route->solo_isolate_control()->solo_isolated();
1510 /* called BEFORE the view has changed */
1512 if (ev->button == 1) {
1513 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1516 /* disable isolate for all routes */
1517 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1519 /* enable isolate for all routes */
1520 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1525 if (model == view) {
1527 /* flip just this route */
1529 boost::shared_ptr<RouteList> rl (new RouteList);
1530 rl->push_back (_route);
1531 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1540 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1542 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1546 bool view = solo_safe_led->active_state();
1547 bool model = _route->solo_safe_control()->solo_safe();
1549 if (ev->button == 1) {
1550 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1551 boost::shared_ptr<RouteList> rl (_session->get_routes());
1553 /* disable solo safe for all routes */
1554 DisplaySuspender ds;
1555 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1556 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1559 /* enable solo safe for all routes */
1560 DisplaySuspender ds;
1561 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1562 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1567 if (model == view) {
1568 /* flip just this route */
1569 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1578 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1580 bool view = check->get_active();
1581 bool model = _route->solo_isolate_control()->solo_isolated();
1583 /* called AFTER the view has changed */
1585 if (model != view) {
1586 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1591 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1593 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1596 /** Ask the user to choose a colour, and then apply that color to my route
1599 RouteUI::choose_color ()
1602 Gdk::Color c (gdk_color_from_rgba (_route->presentation_info().color()));
1603 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1606 set_color (gdk_color_to_rgba (color));
1610 /** Set the route's own color. This may not be used for display if
1611 * the route is in a group which shares its color with its routes.
1614 RouteUI::set_color (uint32_t c)
1616 _route->presentation_info().set_color (c);
1619 /** @return GUI state ID for things that are common to the route in all its representations */
1621 RouteUI::route_state_id () const
1623 return string_compose (X_("route %1"), _route->id().to_s());
1627 RouteUI::set_color_from_route ()
1629 if (_route->presentation_info().color_set()) {
1630 return 0; /* nothing to do */
1633 return 1; /* pick a color */
1636 /** @return true if this name should be used for the route, otherwise false */
1638 RouteUI::verify_new_route_name (const std::string& name)
1640 if (name.find (':') == string::npos) {
1644 MessageDialog colon_msg (
1645 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1646 false, MESSAGE_QUESTION, BUTTONS_NONE
1649 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1650 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1652 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1656 RouteUI::route_rename ()
1658 ArdourPrompter name_prompter (true);
1663 name_prompter.set_title (_("Rename Track"));
1665 name_prompter.set_title (_("Rename Bus"));
1667 name_prompter.set_prompt (_("New name:"));
1668 name_prompter.set_initial_text (_route->name());
1669 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1670 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1671 name_prompter.show_all ();
1674 switch (name_prompter.run ()) {
1675 case Gtk::RESPONSE_ACCEPT:
1676 name_prompter.get_result (result);
1677 name_prompter.hide ();
1678 if (result.length()) {
1679 if (verify_new_route_name (result)) {
1680 _route->set_name (result);
1683 /* back to name prompter */
1687 /* nothing entered, just get out of here */
1702 RouteUI::toggle_comment_editor ()
1704 // if (ignore_toggle) {
1708 if (comment_window && comment_window->is_visible ()) {
1709 comment_window->hide ();
1711 open_comment_editor ();
1717 RouteUI::open_comment_editor ()
1719 if (comment_window == 0) {
1720 setup_comment_editor ();
1724 title = _route->name();
1725 title += _(": comment editor");
1727 comment_window->set_title (title);
1728 comment_window->present();
1732 RouteUI::setup_comment_editor ()
1734 comment_window = new ArdourWindow (""); // title will be reset to show route
1735 comment_window->set_skip_taskbar_hint (true);
1736 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1737 comment_window->set_default_size (400, 200);
1739 comment_area = manage (new TextView());
1740 comment_area->set_name ("MixerTrackCommentArea");
1741 comment_area->set_wrap_mode (WRAP_WORD);
1742 comment_area->set_editable (true);
1743 comment_area->get_buffer()->set_text (_route->comment());
1744 comment_area->show ();
1746 comment_window->add (*comment_area);
1750 RouteUI::comment_changed ()
1752 ignore_comment_edit = true;
1754 comment_area->get_buffer()->set_text (_route->comment());
1756 ignore_comment_edit = false;
1760 RouteUI::comment_editor_done_editing ()
1762 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1764 string const str = comment_area->get_buffer()->get_text();
1765 if (str == _route->comment ()) {
1769 _route->set_comment (str, this);
1773 RouteUI::set_route_active (bool a, bool apply_to_selection)
1775 if (apply_to_selection) {
1776 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1778 _route->set_active (a, this);
1783 RouteUI::duplicate_selected_routes ()
1785 ARDOUR_UI::instance()->start_duplicate_routes();
1789 RouteUI::toggle_denormal_protection ()
1791 if (denormal_menu_item) {
1795 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1797 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1798 _route->set_denormal_protection (x);
1804 RouteUI::denormal_protection_changed ()
1806 if (denormal_menu_item) {
1807 denormal_menu_item->set_active (_route->denormal_protection());
1812 RouteUI::disconnect_input ()
1814 _route->input()->disconnect (this);
1818 RouteUI::disconnect_output ()
1820 _route->output()->disconnect (this);
1824 RouteUI::is_track () const
1826 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1829 boost::shared_ptr<Track>
1830 RouteUI::track() const
1832 return boost::dynamic_pointer_cast<Track>(_route);
1836 RouteUI::is_audio_track () const
1838 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1841 boost::shared_ptr<AudioTrack>
1842 RouteUI::audio_track() const
1844 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1848 RouteUI::is_midi_track () const
1850 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1853 boost::shared_ptr<MidiTrack>
1854 RouteUI::midi_track() const
1856 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1860 RouteUI::has_audio_outputs () const
1862 return (_route->n_outputs().n_audio() > 0);
1866 RouteUI::map_frozen ()
1868 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1870 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1873 check_rec_enable_sensitivity ();
1878 RouteUI::adjust_latency ()
1880 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1884 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1887 std::string safe_name;
1890 prompter.get_result (name, true);
1892 safe_name = legalize_for_path (name);
1893 safe_name += template_suffix;
1895 path = Glib::build_filename (dir, safe_name);
1897 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1898 bool overwrite = overwrite_file_dialog (prompter,
1899 _("Confirm Template Overwrite"),
1900 _("A template already exists with that name. Do you want to overwrite it?"));
1907 _route->save_as_template (path, name);
1913 RouteUI::save_as_template ()
1917 dir = ARDOUR::user_route_template_directory ();
1919 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1920 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1924 ArdourPrompter prompter (true); // modal
1926 prompter.set_title (_("Save As Template"));
1927 prompter.set_prompt (_("Template name:"));
1928 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1930 bool finished = false;
1932 switch (prompter.run()) {
1933 case RESPONSE_ACCEPT:
1934 finished = process_save_template_prompter (prompter, dir);
1944 RouteUI::check_rec_enable_sensitivity ()
1946 if (!rec_enable_button) {
1947 assert (0); // This should not happen
1950 if (!_session->writable()) {
1951 rec_enable_button->set_sensitive (false);
1955 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1956 rec_enable_button->set_sensitive (false);
1957 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1958 rec_enable_button->set_sensitive (false);
1960 rec_enable_button->set_sensitive (true);
1962 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1963 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1965 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1967 update_monitoring_display ();
1971 RouteUI::parameter_changed (string const & p)
1973 /* this handles RC and per-session parameter changes */
1975 if (p == "disable-disarm-during-roll") {
1976 check_rec_enable_sensitivity ();
1977 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1978 set_button_names ();
1979 } else if (p == "session-monitoring") {
1980 update_monitoring_display ();
1981 } else if (p == "auto-input") {
1982 update_monitoring_display ();
1983 } else if (p == "blink-rec-arm") {
1984 if (UIConfiguration::instance().get_blink_rec_arm()) {
1985 rec_blink_connection.disconnect ();
1986 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1988 rec_blink_connection.disconnect ();
1989 RouteUI::blink_rec_display(false);
1995 RouteUI::step_gain_up ()
1997 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2001 RouteUI::page_gain_up ()
2003 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2007 RouteUI::step_gain_down ()
2009 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2013 RouteUI::page_gain_down ()
2015 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2019 RouteUI::setup_invert_buttons ()
2021 /* remove old invert buttons */
2022 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2023 _invert_button_box.remove (**i);
2026 _invert_buttons.clear ();
2028 if (!_route || !_route->input()) {
2032 uint32_t const N = _route->input()->n_ports().n_audio ();
2034 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2036 for (uint32_t i = 0; i < to_add; ++i) {
2037 ArdourButton* b = manage (new ArdourButton);
2038 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2039 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2041 b->set_name (X_("invert button"));
2044 b->set_text (string_compose (X_("Ø (%1)"), N));
2046 b->set_text (X_("Ø"));
2049 b->set_text (string_compose (X_("Ø%1"), i + 1));
2052 if (N <= _max_invert_buttons) {
2053 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));
2055 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2058 _invert_buttons.push_back (b);
2059 _invert_button_box.pack_start (*b);
2062 _invert_button_box.set_spacing (1);
2063 _invert_button_box.show_all ();
2067 RouteUI::set_invert_button_state ()
2069 uint32_t const N = _route->input()->n_ports().n_audio();
2070 if (N > _max_invert_buttons) {
2072 /* One button for many channels; explicit active if all channels are inverted,
2073 implicit active if some are, off if none are.
2076 ArdourButton* b = _invert_buttons.front ();
2078 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2079 b->set_active_state (Gtkmm2ext::ExplicitActive);
2080 } else if (_route->phase_control()->any()) {
2081 b->set_active_state (Gtkmm2ext::ImplicitActive);
2083 b->set_active_state (Gtkmm2ext::Off);
2088 /* One button per channel; just set active */
2091 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2092 (*i)->set_active (_route->phase_control()->inverted (j));
2099 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2101 if (ev->button == 1 && i < _invert_buttons.size()) {
2102 uint32_t const N = _route->input()->n_ports().n_audio ();
2103 if (N <= _max_invert_buttons) {
2104 /* left-click inverts phase so long as we have a button per channel */
2105 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2114 RouteUI::invert_press (GdkEventButton* ev)
2116 using namespace Menu_Helpers;
2118 uint32_t const N = _route->input()->n_ports().n_audio();
2119 if (N <= _max_invert_buttons && ev->button != 3) {
2120 /* If we have an invert button per channel, we only pop
2121 up a menu on right-click; left click is handled
2127 delete _invert_menu;
2128 _invert_menu = new Menu;
2129 _invert_menu->set_name ("ArdourContextMenu");
2130 MenuList& items = _invert_menu->items ();
2132 for (uint32_t i = 0; i < N; ++i) {
2133 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2134 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2135 ++_i_am_the_modifier;
2136 e->set_active (_route->phase_control()->inverted (i));
2137 --_i_am_the_modifier;
2140 _invert_menu->popup (0, ev->time);
2146 RouteUI::invert_menu_toggled (uint32_t c)
2148 if (_i_am_the_modifier) {
2153 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2157 RouteUI::set_invert_sensitive (bool yn)
2159 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2160 (*b)->set_sensitive (yn);
2165 RouteUI::request_redraw ()
2168 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2172 /** The Route's gui_changed signal has been emitted */
2174 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2176 if (what_changed.contains (Properties::color)) {
2177 if (set_color_from_route () == 0) {
2178 route_color_changed ();
2184 RouteUI::track_mode_changed (void)
2187 switch (track()->mode()) {
2188 case ARDOUR::NonLayered:
2189 case ARDOUR::Normal:
2190 rec_enable_button->set_icon (ArdourIcon::RecButton);
2192 case ARDOUR::Destructive:
2193 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2196 rec_enable_button->queue_draw();
2199 /** @return the color that this route should use; it maybe its own,
2200 or it maybe that of its route group.
2204 RouteUI::route_color () const
2207 RouteGroup* g = _route->route_group ();
2210 if (g && g->is_color()) {
2211 set_color_from_rgba (c, GroupTabs::group_color (g));
2213 set_color_from_rgba (c, _route->presentation_info().color());
2220 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2222 _showing_sends_to = send_to;
2223 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2227 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2229 if (_route == send_to) {
2230 show_sends_button->set_active (true);
2231 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2233 show_sends_button->set_active (false);
2234 send_blink_connection.disconnect ();
2239 RouteUI::route_group() const
2241 return _route->route_group();
2245 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2246 : WM::ProxyBase (name, string())
2247 , _route (boost::weak_ptr<Route> (route))
2249 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2252 RoutePinWindowProxy::~RoutePinWindowProxy()
2257 ARDOUR::SessionHandlePtr*
2258 RoutePinWindowProxy::session_handle ()
2260 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2261 if (aw) { return aw; }
2266 RoutePinWindowProxy::get (bool create)
2268 boost::shared_ptr<Route> r = _route.lock ();
2277 _window = new PluginPinDialog (r);
2278 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2280 aw->set_session (_session);
2282 _window->show_all ();
2288 RoutePinWindowProxy::route_going_away ()
2292 WM::Manager::instance().remove (this);
2293 going_away_connection.disconnect();
2298 RouteUI::maybe_add_route_print_mgr ()
2300 if (_route->pinmgr_proxy ()) {
2303 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2304 string_compose ("RPM-%1", _route->id()), _route);
2305 wp->set_session (_session);
2307 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2309 wp->set_state (*ui_xml, 0);
2313 void* existing_ui = _route->pinmgr_proxy ();
2315 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2318 _route->set_pingmgr_proxy (wp);
2320 WM::Manager::instance().register_window (wp);
2324 RouteUI::manage_pins ()
2326 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2334 RouteUI::fan_out (bool to_busses, bool group)
2336 DisplaySuspender ds;
2337 boost::shared_ptr<ARDOUR::Route> route = _route;
2338 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2341 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2342 if (route->n_outputs ().n_audio () != n_outputs) {
2343 MessageDialog msg (string_compose (
2344 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2345 n_outputs, route->n_outputs ().n_audio ()));
2350 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2352 /* count busses and channels/bus */
2353 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2354 std::map<std::string, uint32_t> busnames;
2355 for (uint32_t p = 0; p < n_outputs; ++p) {
2356 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2357 std::string bn = BUSNAME;
2361 if (busnames.size () < 2) {
2362 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2367 uint32_t outputs = 2;
2368 if (_session->master_out ()) {
2369 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2372 route->output ()->disconnect (this);
2373 route->panner_shell ()->set_bypassed (true);
2376 for (uint32_t p = 0; p < n_outputs; ++p) {
2377 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2378 std::string bn = BUSNAME;
2379 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2382 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2386 list<boost::shared_ptr<AudioTrack> > tl =
2387 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2391 boost::shared_ptr<ControlList> cl (new ControlList);
2392 cl->push_back (r->monitoring_control ());
2393 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2395 r->input ()->disconnect (this);
2397 to_group.push_back (r);
2398 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2403 RouteGroup* rg = NULL;
2404 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2405 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2406 if ((*i)->name () == pi->name ()) {
2412 rg = new RouteGroup (*_session, pi->name ());
2413 _session->add_route_group (rg);
2414 rg->set_gain (false);
2417 GroupTabs::set_group_color (rg, route->presentation_info().color());
2418 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2425 RouteUI::mark_hidden (bool yn)
2427 if (yn != _route->presentation_info().hidden()) {
2428 _route->presentation_info().set_hidden (yn);
2429 return true; // things changed
2434 boost::shared_ptr<Stripable>
2435 RouteUI::stripable () const