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 <gtkmm/stock.h>
25 #include "pbd/memento_command.h"
26 #include "pbd/stacktrace.h"
27 #include "pbd/controllable.h"
28 #include "pbd/enumwriter.h"
30 #include "ardour/dB.h"
31 #include "ardour/route_group.h"
32 #include "ardour/solo_isolate_control.h"
33 #include "ardour/vca.h"
34 #include "ardour/vca_manager.h"
35 #include "ardour/audio_track.h"
36 #include "ardour/audio_port.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/filename_extensions.h"
39 #include "ardour/midi_track.h"
40 #include "ardour/monitor_control.h"
41 #include "ardour/internal_send.h"
42 #include "ardour/panner_shell.h"
43 #include "ardour/profile.h"
44 #include "ardour/phase_control.h"
45 #include "ardour/send.h"
46 #include "ardour/route.h"
47 #include "ardour/session.h"
48 #include "ardour/template_utils.h"
50 #include "gtkmm2ext/gtk_ui.h"
51 #include "gtkmm2ext/doi.h"
52 #include "gtkmm2ext/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
55 #include "widgets/ardour_button.h"
56 #include "widgets/binding_proxy.h"
57 #include "widgets/prompter.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 "patch_change_widget.h"
70 #include "plugin_pin_dialog.h"
71 #include "rgb_macros.h"
72 #include "route_time_axis.h"
74 #include "save_template_dialog.h"
76 #include "ui_config.h"
82 using namespace Gtkmm2ext;
83 using namespace ARDOUR;
84 using namespace ARDOUR_UI_UTILS;
85 using namespace ArdourWidgets;
89 uint32_t RouteUI::_max_invert_buttons = 3;
90 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
91 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
92 std::string RouteUI::program_port_prefix;
94 RouteUI::RouteUI (ARDOUR::Session* sess)
95 : monitor_input_button (0)
96 , monitor_disk_button (0)
104 , output_selector (0)
107 if (program_port_prefix.empty()) {
108 // compare to gtk2_ardour/port_group.cc
109 string lpn (PROGRAM_NAME);
110 boost::to_lower (lpn);
111 program_port_prefix = lpn + ":"; // e.g. "ardour:"
122 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
125 delete_patch_change_dialog ();
127 _route.reset (); /* drop reference to route, so that it can be cleaned up */
128 route_connections.drop_connections ();
134 delete comment_window;
135 delete input_selector;
136 delete output_selector;
137 delete monitor_input_button;
138 delete monitor_disk_button;
141 send_blink_connection.disconnect ();
142 rec_blink_connection.disconnect ();
148 self_destruct = true;
154 pre_fader_mute_check = 0;
155 post_fader_mute_check = 0;
156 listen_mute_check = 0;
159 solo_isolated_check = 0;
160 solo_isolated_led = 0;
164 denormal_menu_item = 0;
167 multiple_mute_change = false;
168 multiple_solo_change = false;
169 _i_am_the_modifier = 0;
174 setup_invert_buttons ();
176 mute_button = manage (new ArdourButton);
177 mute_button->set_name ("mute button");
178 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
180 solo_button = manage (new ArdourButton);
181 solo_button->set_name ("solo button");
182 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
183 solo_button->set_no_show_all (true);
185 rec_enable_button = manage (new ArdourButton);
186 rec_enable_button->set_name ("record enable button");
187 rec_enable_button->set_icon (ArdourIcon::RecButton);
188 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
190 if (UIConfiguration::instance().get_blink_rec_arm()) {
191 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
194 show_sends_button = manage (new ArdourButton);
195 show_sends_button->set_name ("send alert button");
196 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
198 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_input_button->set_name ("monitor button");
200 monitor_input_button->set_text (_("In"));
201 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
202 monitor_input_button->set_no_show_all (true);
204 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
205 monitor_disk_button->set_name ("monitor button");
206 monitor_disk_button->set_text (_("Disk"));
207 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
208 monitor_disk_button->set_no_show_all (true);
210 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
211 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
212 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
213 _session->MonitorBusAddedOrRemoved.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::set_button_names, this), gui_context());
215 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
216 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
217 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
219 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
220 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
222 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
223 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
225 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
226 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
227 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
228 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
230 monitor_input_button->set_distinct_led_click (false);
231 monitor_disk_button->set_distinct_led_click (false);
233 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
234 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
236 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
237 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
239 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
245 route_connections.drop_connections ();
253 delete_patch_change_dialog ();
254 _color_picker.reset ();
256 denormal_menu_item = 0;
260 RouteUI::self_delete ()
266 RouteUI::set_route (boost::shared_ptr<Route> rp)
272 if ( !_route->presentation_info().color_set() ) {
273 /* deal with older 4.x color, which was stored in the GUI object state */
275 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
279 /* old v4.x or earlier session. Use this information */
281 int red, green, blue;
286 /* old color format version was:
288 16bit value for red:16 bit value for green:16 bit value for blue
303 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
307 if (set_color_from_route()) {
308 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
312 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
315 delete input_selector;
318 delete output_selector;
321 mute_button->set_controllable (_route->mute_control());
322 solo_button->set_controllable (_route->solo_control());
324 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
326 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
328 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
329 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
330 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
331 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
332 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
333 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
336 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
337 track_mode_changed();
341 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
342 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
344 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
346 if (_session->writable() && is_track()) {
347 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
349 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
350 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
352 rec_enable_button->show();
353 rec_enable_button->set_controllable (t->rec_enable_control());
355 if (is_midi_track()) {
356 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
357 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
362 /* this will work for busses and tracks, and needs to be called to
363 set up the name entry/name label display.
367 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
368 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
370 update_monitoring_display ();
373 mute_button->unset_flags (Gtk::CAN_FOCUS);
374 solo_button->unset_flags (Gtk::CAN_FOCUS);
378 if (_route->is_monitor() || _route->is_master()) {
379 solo_button->hide ();
386 setup_invert_buttons ();
387 set_invert_button_state ();
389 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
390 bus_send_display_changed (s);
392 update_mute_display ();
393 update_solo_display ();
395 if (!UIConfiguration::instance().get_blink_rec_arm()) {
396 blink_rec_display(true); // set initial rec-en button state
399 check_rec_enable_sensitivity ();
400 maybe_add_route_print_mgr ();
401 route_color_changed();
402 route_gui_changed (PropertyChange (Properties::selected));
406 RouteUI::polarity_changed ()
412 set_invert_button_state ();
416 RouteUI::mute_press (GdkEventButton* ev)
418 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
422 //if this is a binding action, let the ArdourButton handle it
423 if (BindingProxy::is_bind_action(ev) )
426 multiple_mute_change = false;
428 if (Keyboard::is_context_menu_event (ev)) {
434 mute_menu->popup(0,ev->time);
440 if (Keyboard::is_button2_event (ev)) {
441 // button2-click is "momentary"
443 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
446 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
448 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
450 /* toggle mute on everything (but
451 * exclude the master and monitor)
453 * because we are going to erase
454 * elements of the list we need to work
458 boost::shared_ptr<RouteList> copy (new RouteList);
460 *copy = *_session->get_routes ();
462 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
463 if ((*i)->is_master() || (*i)->is_monitor()) {
471 _mute_release->routes = copy;
474 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
476 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
478 /* Primary-button1 inverts the implication of
479 the group being active. If the group is
480 active (for mute), then this modifier means
481 "do not apply to mute". If the group is
482 inactive (for mute), then this modifier
483 means "apply to route". This is all
484 accomplished by passing just the actual
485 route, along with the InverseGroup group
488 NOTE: Primary-button2 is MIDI learn.
491 boost::shared_ptr<RouteList> rl;
493 if (ev->button == 1) {
495 rl.reset (new RouteList);
496 rl->push_back (_route);
499 _mute_release->routes = rl;
502 boost::shared_ptr<MuteControl> mc = _route->mute_control();
503 mc->start_touch (_session->audible_sample ());
504 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
509 /* plain click applies change to this route */
511 boost::shared_ptr<RouteList> rl (new RouteList);
512 rl->push_back (_route);
515 _mute_release->routes = rl;
518 boost::shared_ptr<MuteControl> mc = _route->mute_control();
519 mc->start_touch (_session->audible_sample ());
520 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
529 RouteUI::mute_release (GdkEventButton* /*ev*/)
532 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
533 delete _mute_release;
537 _route->mute_control()->stop_touch (_session->audible_sample ());
543 RouteUI::edit_output_configuration ()
545 if (output_selector == 0) {
547 boost::shared_ptr<Send> send;
548 boost::shared_ptr<IO> output;
550 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
551 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
552 output = send->output();
554 output = _route->output ();
557 output = _route->output ();
560 output_selector = new IOSelectorWindow (_session, output);
563 if (output_selector->is_visible()) {
564 output_selector->get_toplevel()->get_window()->raise();
566 output_selector->present ();
569 //output_selector->set_keep_above (true);
573 RouteUI::edit_input_configuration ()
575 if (input_selector == 0) {
576 input_selector = new IOSelectorWindow (_session, _route->input());
579 if (input_selector->is_visible()) {
580 input_selector->get_toplevel()->get_window()->raise();
582 input_selector->present ();
585 //input_selector->set_keep_above (true);
589 RouteUI::solo_press(GdkEventButton* ev)
591 /* ignore double/triple clicks */
593 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
597 //if this is a binding action, let the ArdourButton handle it
598 if (BindingProxy::is_bind_action(ev) )
601 multiple_solo_change = false;
603 if (Keyboard::is_context_menu_event (ev)) {
605 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
606 ! (solo_safe_led && solo_safe_led->is_visible())) {
608 if (solo_menu == 0) {
612 solo_menu->popup (1, ev->time);
617 if (Keyboard::is_button2_event (ev)) {
619 // button2-click is "momentary"
620 _solo_release = new SoloMuteRelease (_route->self_soloed());
623 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
625 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
627 /* Primary-Tertiary-click applies change to all routes */
630 _solo_release->routes = _session->get_routes ();
633 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
635 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
637 /* Primary-Secondary-click: exclusively solo this track */
640 _solo_release->exclusive = true;
642 _solo_release->routes_on.reset (new RouteList);
643 _solo_release->routes_off.reset (new RouteList);
645 boost::shared_ptr<RouteList> routes = _session->get_routes();
646 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
648 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
652 if ((*i)->soloed ()) {
653 _solo_release->routes_on->push_back (*i);
655 _solo_release->routes_off->push_back (*i);
660 boost::shared_ptr<RouteList> rl (new RouteList);
661 boost::shared_ptr<RouteList> routes = _session->get_routes();
662 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
664 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
668 if ((*i)->soloed ()) {
672 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
674 if (Config->get_solo_control_is_listen_control()) {
675 /* ??? we need a just_one_listen() method */
678 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
681 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
683 // shift-click: toggle solo isolated status
685 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
686 delete _solo_release;
689 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
691 /* Primary-button1: solo mix group.
692 NOTE: Primary-button2 is MIDI learn.
695 /* Primary-button1 applies change to the mix group even if it is not active
696 NOTE: Primary-button2 is MIDI learn.
699 boost::shared_ptr<RouteList> rl;
701 if (ev->button == 1) {
703 /* Primary-button1 inverts the implication of
704 the group being active. If the group is
705 active (for solo), then this modifier means
706 "do not apply to solo". If the group is
707 inactive (for mute), then this modifier
708 means "apply to route". This is all
709 accomplished by passing just the actual
710 route, along with the InverseGroup group
713 NOTE: Primary-button2 is MIDI learn.
716 rl.reset (new RouteList);
717 rl->push_back (_route);
720 _solo_release->routes = rl;
723 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
726 delete _solo_release;
731 /* click: solo this route */
733 boost::shared_ptr<RouteList> rl (new RouteList);
734 rl->push_back (route());
737 _solo_release->routes = rl;
740 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
749 RouteUI::solo_release (GdkEventButton* /*ev*/)
752 if (_solo_release->exclusive) {
753 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
754 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
756 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
759 delete _solo_release;
767 RouteUI::rec_enable_press(GdkEventButton* ev)
769 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
773 //if this is a binding action, let the ArdourButton handle it
774 if (BindingProxy::is_bind_action(ev) )
777 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
781 if (is_midi_track()) {
783 /* rec-enable button exits from step editing, but not context click */
785 if (!Keyboard::is_context_menu_event (ev) && 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 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
909 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
911 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() | monitor_choice);
914 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
915 /* Primary-Tertiary-click applies change to all routes */
916 rl = _session->get_routes ();
917 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
918 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
919 /* Primary-click overrides group */
920 rl.reset (new RouteList);
921 rl->push_back (route());
922 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
924 rl.reset (new RouteList);
925 rl->push_back (route());
926 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
933 RouteUI::build_record_menu ()
936 record_menu = new Menu;
937 record_menu->set_name ("ArdourContextMenu");
938 using namespace Menu_Helpers;
939 MenuList& items = record_menu->items();
941 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
942 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
944 if (is_midi_track()) {
945 items.push_back (SeparatorElem());
946 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
947 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
951 if (step_edit_item) {
952 if (track()->rec_enable_control()->get_value()) {
953 step_edit_item->set_sensitive (false);
955 step_edit_item->set_active (midi_track()->step_editing());
958 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
959 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
964 RouteUI::toggle_step_edit ()
966 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
970 midi_track()->set_step_editing (step_edit_item->get_active());
974 RouteUI::toggle_rec_safe ()
976 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
982 /* This check is made inside the control too, but dong it here can't
986 if (_route->rec_enable_control()->get_value()) {
990 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
994 RouteUI::step_edit_changed (bool yn)
997 if (rec_enable_button) {
998 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1001 start_step_editing ();
1003 if (step_edit_item) {
1004 step_edit_item->set_active (true);
1009 if (rec_enable_button) {
1010 rec_enable_button->unset_active_state ();
1013 stop_step_editing ();
1015 if (step_edit_item) {
1016 step_edit_item->set_active (false);
1022 RouteUI::rec_enable_release (GdkEventButton* ev)
1024 if (Keyboard::is_context_menu_event (ev)) {
1025 build_record_menu ();
1027 record_menu->popup (1, ev->time);
1036 RouteUI::build_sends_menu ()
1038 using namespace Menu_Helpers;
1040 sends_menu = new Menu;
1041 sends_menu->set_name ("ArdourContextMenu");
1042 MenuList& items = sends_menu->items();
1045 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1049 MenuElem(_("Assign all tracks and busses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1053 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1057 MenuElem(_("Assign all tracks and busses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1061 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1065 MenuElem(_("Assign selected tracks and busses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1068 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1072 MenuElem(_("Assign selected tracks and busses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1075 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1076 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1077 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1082 RouteUI::create_sends (Placement p, bool include_buses)
1084 _session->globally_add_internal_sends (_route, p, include_buses);
1088 RouteUI::create_selected_sends (Placement p, bool include_buses)
1090 boost::shared_ptr<RouteList> rlist (new RouteList);
1091 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1093 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1094 RouteTimeAxisView* rtv;
1096 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1097 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1098 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1099 rlist->push_back (rui->route());
1105 _session->add_internal_sends (_route, p, rlist);
1109 RouteUI::set_sends_gain_from_track ()
1111 _session->globally_set_send_gains_from_track (_route);
1115 RouteUI::set_sends_gain_to_zero ()
1117 _session->globally_set_send_gains_to_zero (_route);
1121 RouteUI::set_sends_gain_to_unity ()
1123 _session->globally_set_send_gains_to_unity (_route);
1127 RouteUI::show_sends_press(GdkEventButton* ev)
1129 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1133 if (!is_track() && show_sends_button) {
1135 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1137 // do nothing on midi sigc::bind event
1140 } else if (Keyboard::is_context_menu_event (ev)) {
1142 if (sends_menu == 0) {
1143 build_sends_menu ();
1146 sends_menu->popup (0, ev->time);
1150 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1153 set_showing_sends_to (boost::shared_ptr<Route> ());
1155 set_showing_sends_to (_route);
1164 RouteUI::show_sends_release (GdkEventButton*)
1170 RouteUI::send_blink (bool onoff)
1172 if (!show_sends_button) {
1177 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1179 show_sends_button->unset_active_state ();
1183 Gtkmm2ext::ActiveState
1184 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1186 boost::shared_ptr<SoloControl> sc = s->solo_control();
1189 return Gtkmm2ext::Off;
1192 if (!sc->can_solo()) {
1193 return Gtkmm2ext::Off;
1197 if (sc->self_soloed()) {
1198 return Gtkmm2ext::ExplicitActive;
1199 } else if (sc->soloed_by_others()) {
1200 return Gtkmm2ext::ImplicitActive;
1202 return Gtkmm2ext::Off;
1206 Gtkmm2ext::ActiveState
1207 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1209 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1212 return Gtkmm2ext::Off;
1215 if (s->is_master() || s->is_monitor()) {
1216 return Gtkmm2ext::Off;
1219 if (sc->solo_isolated()) {
1220 return Gtkmm2ext::ExplicitActive;
1222 return Gtkmm2ext::Off;
1226 Gtkmm2ext::ActiveState
1227 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1229 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1232 return Gtkmm2ext::Off;
1235 if (s->is_master() || s->is_monitor()) {
1236 return Gtkmm2ext::Off;
1239 if (sc->solo_safe()) {
1240 return Gtkmm2ext::ExplicitActive;
1242 return Gtkmm2ext::Off;
1247 RouteUI::update_solo_display ()
1249 bool yn = _route->solo_safe_control()->solo_safe ();
1251 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1252 solo_safe_check->set_active (yn);
1255 yn = _route->solo_isolate_control()->solo_isolated ();
1257 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1258 solo_isolated_check->set_active (yn);
1261 set_button_names ();
1263 if (solo_isolated_led) {
1264 if (_route->solo_isolate_control()->solo_isolated()) {
1265 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1267 solo_isolated_led->unset_active_state ();
1271 if (solo_safe_led) {
1272 if (_route->solo_safe_control()->solo_safe()) {
1273 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1275 solo_safe_led->unset_active_state ();
1279 solo_button->set_active_state (solo_active_state (_route));
1281 /* some changes to solo status can affect mute display, so catch up
1284 update_mute_display ();
1288 RouteUI::solo_changed_so_update_mute ()
1290 update_mute_display ();
1294 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1296 boost::shared_ptr<MuteControl> mc = s->mute_control();
1298 if (s->is_monitor()) {
1299 return Gtkmm2ext::Off;
1303 return Gtkmm2ext::Off;
1306 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1308 if (mc->muted_by_self ()) {
1310 return Gtkmm2ext::ExplicitActive;
1311 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1312 /* this will reflect both solo mutes AND master mutes */
1313 return Gtkmm2ext::ImplicitActive;
1315 /* no mute at all */
1316 return Gtkmm2ext::Off;
1321 if (mc->muted_by_self()) {
1323 return Gtkmm2ext::ExplicitActive;
1324 } else if (mc->muted_by_masters ()) {
1325 /* this shows only master mutes, not mute-by-others-soloing */
1326 return Gtkmm2ext::ImplicitActive;
1328 /* no mute at all */
1329 return Gtkmm2ext::Off;
1333 return ActiveState(0);
1337 RouteUI::update_mute_display ()
1343 mute_button->set_active_state (mute_active_state (_session, _route));
1348 RouteUI::route_rec_enable_changed ()
1350 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1354 RouteUI::session_rec_enable_changed ()
1356 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1360 RouteUI::blink_rec_display (bool blinkOn)
1362 if (!rec_enable_button || !_route) {
1366 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1374 if (track()->rec_enable_control()->get_value()) {
1375 switch (_session->record_status ()) {
1376 case Session::Recording:
1377 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1380 case Session::Disabled:
1381 case Session::Enabled:
1382 if (UIConfiguration::instance().get_blink_rec_arm()) {
1383 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1385 rec_enable_button->set_active_state ( ImplicitActive );
1390 if (step_edit_item) {
1391 step_edit_item->set_sensitive (false);
1395 rec_enable_button->unset_active_state ();
1397 if (step_edit_item) {
1398 step_edit_item->set_sensitive (true);
1402 check_rec_enable_sensitivity ();
1406 RouteUI::build_solo_menu (void)
1408 using namespace Menu_Helpers;
1410 solo_menu = new Menu;
1411 solo_menu->set_name ("ArdourContextMenu");
1412 MenuList& items = solo_menu->items();
1413 Gtk::CheckMenuItem* check;
1415 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1416 check->set_active (_route->solo_isolate_control()->solo_isolated());
1417 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1418 items.push_back (CheckMenuElem(*check));
1419 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1422 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1423 check->set_active (_route->solo_safe_control()->solo_safe());
1424 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1425 items.push_back (CheckMenuElem(*check));
1426 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1431 RouteUI::build_mute_menu(void)
1433 using namespace Menu_Helpers;
1435 mute_menu = new Menu;
1436 mute_menu->set_name ("ArdourContextMenu");
1438 MenuList& items = mute_menu->items();
1440 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1441 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1442 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1443 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1444 pre_fader_mute_check->show_all();
1446 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1447 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1448 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1449 items.push_back (CheckMenuElem(*post_fader_mute_check));
1450 post_fader_mute_check->show_all();
1452 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1453 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1454 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1455 items.push_back (CheckMenuElem(*listen_mute_check));
1456 listen_mute_check->show_all();
1458 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1459 init_mute_menu(MuteMaster::Main, main_mute_check);
1460 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1461 items.push_back (CheckMenuElem(*main_mute_check));
1462 main_mute_check->show_all();
1464 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1468 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1470 check->set_active (_route->mute_control()->mute_points() & mp);
1474 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1476 if (check->get_active()) {
1477 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1479 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1484 RouteUI::muting_change ()
1486 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1489 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1491 yn = (current & MuteMaster::PreFader);
1493 if (pre_fader_mute_check->get_active() != yn) {
1494 pre_fader_mute_check->set_active (yn);
1497 yn = (current & MuteMaster::PostFader);
1499 if (post_fader_mute_check->get_active() != yn) {
1500 post_fader_mute_check->set_active (yn);
1503 yn = (current & MuteMaster::Listen);
1505 if (listen_mute_check->get_active() != yn) {
1506 listen_mute_check->set_active (yn);
1509 yn = (current & MuteMaster::Main);
1511 if (main_mute_check->get_active() != yn) {
1512 main_mute_check->set_active (yn);
1517 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1519 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1523 bool view = solo_isolated_led->active_state();
1524 bool model = _route->solo_isolate_control()->solo_isolated();
1526 /* called BEFORE the view has changed */
1528 if (ev->button == 1) {
1529 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1532 /* disable isolate for all routes */
1533 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1535 /* enable isolate for all routes */
1536 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1541 if (model == view) {
1543 /* flip just this route */
1545 boost::shared_ptr<RouteList> rl (new RouteList);
1546 rl->push_back (_route);
1547 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1556 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1558 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1562 bool view = solo_safe_led->active_state();
1563 bool model = _route->solo_safe_control()->solo_safe();
1565 if (ev->button == 1) {
1566 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1567 boost::shared_ptr<RouteList> rl (_session->get_routes());
1569 /* disable solo safe for all routes */
1570 DisplaySuspender ds;
1571 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1572 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1575 /* enable solo safe for all routes */
1576 DisplaySuspender ds;
1577 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1578 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1583 if (model == view) {
1584 /* flip just this route */
1585 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1594 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1596 bool view = check->get_active();
1597 bool model = _route->solo_isolate_control()->solo_isolated();
1599 /* called AFTER the view has changed */
1601 if (model != view) {
1602 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1607 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1609 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1613 RouteUI::delete_patch_change_dialog ()
1618 delete _route->patch_selector_dialog ();
1619 _route->set_patch_selector_dialog (0);
1622 PatchChangeGridDialog*
1623 RouteUI::patch_change_dialog () const
1625 return _route->patch_selector_dialog ();
1629 RouteUI::select_midi_patch ()
1631 if (patch_change_dialog ()) {
1632 patch_change_dialog()->present ();
1636 /* note: RouteTimeAxisView is resoponsible to updating
1637 * the Dialog (PatchChangeGridDialog::refresh())
1638 * when the midnam model changes.
1640 PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1641 _route->set_patch_selector_dialog (d);
1645 /** Ask the user to choose a colour, and then apply that color to my route */
1647 RouteUI::choose_color ()
1649 _color_picker.popup (_route);
1652 /** Set the route's own color. This may not be used for display if
1653 * the route is in a group which shares its color with its routes.
1656 RouteUI::set_color (uint32_t c)
1658 _route->presentation_info().set_color (c);
1661 /** @return GUI state ID for things that are common to the route in all its representations */
1663 RouteUI::route_state_id () const
1665 return string_compose (X_("route %1"), _route->id().to_s());
1669 RouteUI::set_color_from_route ()
1671 if (_route->presentation_info().color_set()) {
1672 return 0; /* nothing to do */
1675 return 1; /* pick a color */
1678 /** @return true if this name should be used for the route, otherwise false */
1680 RouteUI::verify_new_route_name (const std::string& name)
1682 if (name.find (':') == string::npos) {
1686 MessageDialog colon_msg (
1687 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1688 false, MESSAGE_QUESTION, BUTTONS_NONE
1691 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1692 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1694 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1698 RouteUI::route_rename ()
1700 ArdourWidgets::Prompter name_prompter (true);
1705 name_prompter.set_title (_("Rename Track"));
1707 name_prompter.set_title (_("Rename Bus"));
1709 name_prompter.set_prompt (_("New name:"));
1710 name_prompter.set_initial_text (_route->name());
1711 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1712 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1713 name_prompter.show_all ();
1716 switch (name_prompter.run ()) {
1717 case Gtk::RESPONSE_ACCEPT:
1718 name_prompter.get_result (result);
1719 name_prompter.hide ();
1720 if (result.length()) {
1721 if (verify_new_route_name (result)) {
1722 _route->set_name (result);
1725 /* back to name prompter */
1729 /* nothing entered, just get out of here */
1744 RouteUI::toggle_comment_editor ()
1746 // if (ignore_toggle) {
1750 if (comment_window && comment_window->is_visible ()) {
1751 comment_window->hide ();
1753 open_comment_editor ();
1759 RouteUI::open_comment_editor ()
1761 if (comment_window == 0) {
1762 setup_comment_editor ();
1766 title = _route->name();
1767 title += _(": comment editor");
1769 comment_window->set_title (title);
1770 comment_window->present();
1774 RouteUI::setup_comment_editor ()
1776 comment_window = new ArdourWindow (""); // title will be reset to show route
1777 comment_window->set_skip_taskbar_hint (true);
1778 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1779 comment_window->set_default_size (400, 200);
1781 comment_area = manage (new TextView());
1782 comment_area->set_name ("MixerTrackCommentArea");
1783 comment_area->set_wrap_mode (WRAP_WORD);
1784 comment_area->set_editable (true);
1785 comment_area->get_buffer()->set_text (_route->comment());
1786 comment_area->show ();
1788 comment_window->add (*comment_area);
1792 RouteUI::comment_changed ()
1794 ignore_comment_edit = true;
1796 comment_area->get_buffer()->set_text (_route->comment());
1798 ignore_comment_edit = false;
1802 RouteUI::comment_editor_done_editing ()
1804 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1806 string const str = comment_area->get_buffer()->get_text();
1807 if (str == _route->comment ()) {
1811 _route->set_comment (str, this);
1815 RouteUI::set_route_active (bool a, bool apply_to_selection)
1817 if (apply_to_selection) {
1818 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1820 _route->set_active (a, this);
1825 RouteUI::duplicate_selected_routes ()
1827 ARDOUR_UI::instance()->start_duplicate_routes();
1831 RouteUI::toggle_denormal_protection ()
1833 if (denormal_menu_item) {
1837 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1839 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1840 _route->set_denormal_protection (x);
1846 RouteUI::denormal_protection_changed ()
1848 if (denormal_menu_item) {
1849 denormal_menu_item->set_active (_route->denormal_protection());
1854 RouteUI::disconnect_input ()
1856 _route->input()->disconnect (this);
1860 RouteUI::disconnect_output ()
1862 _route->output()->disconnect (this);
1866 RouteUI::is_track () const
1868 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1871 boost::shared_ptr<Track>
1872 RouteUI::track() const
1874 return boost::dynamic_pointer_cast<Track>(_route);
1878 RouteUI::is_audio_track () const
1880 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1883 boost::shared_ptr<AudioTrack>
1884 RouteUI::audio_track() const
1886 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1890 RouteUI::is_midi_track () const
1892 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1895 boost::shared_ptr<MidiTrack>
1896 RouteUI::midi_track() const
1898 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1902 RouteUI::has_audio_outputs () const
1904 return (_route->n_outputs().n_audio() > 0);
1908 RouteUI::map_frozen ()
1910 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1912 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1915 check_rec_enable_sensitivity ();
1920 RouteUI::adjust_latency ()
1922 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->sample_rate(), AudioEngine::instance()->samples_per_cycle());
1927 RouteUI::save_as_template_dialog_response (int response, SaveTemplateDialog* d)
1929 if (response == RESPONSE_ACCEPT) {
1930 const string name = d->get_template_name ();
1931 const string desc = d->get_description ();
1932 const string path = Glib::build_filename(ARDOUR::user_route_template_directory (), name + ARDOUR::template_suffix);
1934 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { /* file already exists. */
1935 bool overwrite = overwrite_file_dialog (*d,
1936 _("Confirm Template Overwrite"),
1937 _("A template already exists with that name. Do you want to overwrite it?"));
1944 _route->save_as_template (path, name, desc);
1951 RouteUI::save_as_template ()
1953 const std::string dir = ARDOUR::user_route_template_directory ();
1955 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1956 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1960 SaveTemplateDialog* d = new SaveTemplateDialog (_route->name(), _route->comment());
1961 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::save_as_template_dialog_response), d));
1966 RouteUI::check_rec_enable_sensitivity ()
1968 if (!rec_enable_button) {
1969 assert (0); // This should not happen
1972 if (!_session->writable()) {
1973 rec_enable_button->set_sensitive (false);
1977 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1978 rec_enable_button->set_sensitive (false);
1979 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1980 rec_enable_button->set_sensitive (false);
1982 rec_enable_button->set_sensitive (true);
1984 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1985 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1987 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1989 update_monitoring_display ();
1993 RouteUI::parameter_changed (string const & p)
1995 /* this handles RC and per-session parameter changes */
1997 if (p == "disable-disarm-during-roll") {
1998 check_rec_enable_sensitivity ();
1999 } else if (p == "solo-control-is-listen-control" || p == "listen-position") {
2000 set_button_names ();
2001 } else if (p == "session-monitoring") {
2002 update_monitoring_display ();
2003 } else if (p == "auto-input") {
2004 update_monitoring_display ();
2005 } else if (p == "blink-rec-arm") {
2006 if (UIConfiguration::instance().get_blink_rec_arm()) {
2007 rec_blink_connection.disconnect ();
2008 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2010 rec_blink_connection.disconnect ();
2011 RouteUI::blink_rec_display(false);
2017 RouteUI::setup_invert_buttons ()
2019 /* remove old invert buttons */
2020 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2021 _invert_button_box.remove (**i);
2024 _invert_buttons.clear ();
2026 if (!_route || !_route->input()) {
2030 uint32_t const N = _route->input()->n_ports().n_audio ();
2032 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2034 for (uint32_t i = 0; i < to_add; ++i) {
2035 ArdourButton* b = manage (new ArdourButton);
2036 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2037 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2039 b->set_name (X_("invert button"));
2042 b->set_text (string_compose (X_("Ø (%1)"), N));
2044 b->set_text (X_("Ø"));
2047 b->set_text (string_compose (X_("Ø%1"), i + 1));
2050 if (N <= _max_invert_buttons) {
2051 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));
2053 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2056 _invert_buttons.push_back (b);
2057 _invert_button_box.pack_start (*b);
2060 _invert_button_box.set_spacing (1);
2061 _invert_button_box.show_all ();
2065 RouteUI::set_invert_button_state ()
2067 uint32_t const N = _route->input()->n_ports().n_audio();
2068 if (N > _max_invert_buttons) {
2070 /* One button for many channels; explicit active if all channels are inverted,
2071 implicit active if some are, off if none are.
2074 ArdourButton* b = _invert_buttons.front ();
2076 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2077 b->set_active_state (Gtkmm2ext::ExplicitActive);
2078 } else if (_route->phase_control()->any()) {
2079 b->set_active_state (Gtkmm2ext::ImplicitActive);
2081 b->set_active_state (Gtkmm2ext::Off);
2086 /* One button per channel; just set active */
2089 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2090 (*i)->set_active (_route->phase_control()->inverted (j));
2097 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2099 if (ev->button == 1 && i < _invert_buttons.size()) {
2100 uint32_t const N = _route->input()->n_ports().n_audio ();
2101 if (N <= _max_invert_buttons) {
2102 /* left-click inverts phase so long as we have a button per channel */
2103 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2112 RouteUI::invert_press (GdkEventButton* ev)
2114 using namespace Menu_Helpers;
2116 uint32_t const N = _route->input()->n_ports().n_audio();
2117 if (N <= _max_invert_buttons && ev->button != 3) {
2118 /* If we have an invert button per channel, we only pop
2119 up a menu on right-click; left click is handled
2125 delete _invert_menu;
2126 _invert_menu = new Menu;
2127 _invert_menu->set_name ("ArdourContextMenu");
2128 MenuList& items = _invert_menu->items ();
2130 for (uint32_t i = 0; i < N; ++i) {
2131 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2132 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2133 ++_i_am_the_modifier;
2134 e->set_active (_route->phase_control()->inverted (i));
2135 --_i_am_the_modifier;
2138 _invert_menu->popup (0, ev->time);
2144 RouteUI::invert_menu_toggled (uint32_t c)
2146 if (_i_am_the_modifier) {
2151 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2155 RouteUI::set_invert_sensitive (bool yn)
2157 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2158 (*b)->set_sensitive (yn);
2162 /** The Route's gui_changed signal has been emitted */
2164 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2166 if (what_changed.contains (Properties::color)) {
2167 if (set_color_from_route () == 0) {
2168 route_color_changed ();
2174 RouteUI::track_mode_changed (void)
2177 switch (track()->mode()) {
2178 case ARDOUR::NonLayered:
2179 case ARDOUR::Normal:
2180 rec_enable_button->set_icon (ArdourIcon::RecButton);
2182 case ARDOUR::Destructive:
2183 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2186 rec_enable_button->queue_draw();
2189 /** @return the color that this route should use; it maybe its own,
2190 * or it maybe that of its route group.
2193 RouteUI::route_color () const
2196 RouteGroup* g = _route->route_group ();
2199 if (g && g->is_color()) {
2200 set_color_from_rgba (c, GroupTabs::group_color (g));
2202 set_color_from_rgba (c, _route->presentation_info().color());
2209 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2211 _showing_sends_to = send_to;
2212 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2216 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2218 if (_route == send_to) {
2219 show_sends_button->set_active (true);
2220 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2222 show_sends_button->set_active (false);
2223 send_blink_connection.disconnect ();
2228 RouteUI::route_group() const
2230 return _route->route_group();
2234 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2235 : WM::ProxyBase (name, string())
2236 , _route (boost::weak_ptr<Route> (route))
2238 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2241 RoutePinWindowProxy::~RoutePinWindowProxy()
2246 ARDOUR::SessionHandlePtr*
2247 RoutePinWindowProxy::session_handle ()
2249 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2250 if (aw) { return aw; }
2255 RoutePinWindowProxy::get (bool create)
2257 boost::shared_ptr<Route> r = _route.lock ();
2266 _window = new PluginPinDialog (r);
2267 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2269 aw->set_session (_session);
2271 _window->show_all ();
2277 RoutePinWindowProxy::route_going_away ()
2281 WM::Manager::instance().remove (this);
2282 going_away_connection.disconnect();
2287 RouteUI::maybe_add_route_print_mgr ()
2289 if (_route->pinmgr_proxy ()) {
2292 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2293 string_compose ("RPM-%1", _route->id()), _route);
2294 wp->set_session (_session);
2296 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2298 wp->set_state (*ui_xml, 0);
2302 void* existing_ui = _route->pinmgr_proxy ();
2304 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2307 _route->set_pingmgr_proxy (wp);
2309 WM::Manager::instance().register_window (wp);
2313 RouteUI::manage_pins ()
2315 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2323 RouteUI::fan_out (bool to_busses, bool group)
2325 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
2329 DisplaySuspender ds;
2330 boost::shared_ptr<ARDOUR::Route> route = _route;
2331 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2334 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2335 if (route->n_outputs ().n_audio () != n_outputs) {
2336 MessageDialog msg (string_compose (
2337 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2338 n_outputs, route->n_outputs ().n_audio ()));
2343 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2345 /* count busses and channels/bus */
2346 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2347 std::map<std::string, uint32_t> busnames;
2348 for (uint32_t p = 0; p < n_outputs; ++p) {
2349 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2350 std::string bn = BUSNAME;
2354 if (busnames.size () < 2) {
2355 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2360 uint32_t outputs = 2;
2361 if (_session->master_out ()) {
2362 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2365 route->output ()->disconnect (this);
2366 route->panner_shell ()->set_bypassed (true);
2369 for (uint32_t p = 0; p < n_outputs; ++p) {
2370 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2371 std::string bn = BUSNAME;
2372 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2376 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2380 list<boost::shared_ptr<AudioTrack> > tl =
2381 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2385 boost::shared_ptr<ControlList> cl (new ControlList);
2386 cl->push_back (r->monitoring_control ());
2387 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2390 if (!to_group.empty()) {
2391 boost::shared_ptr<RouteList> rl (&to_group);
2392 _session->remove_routes (rl);
2396 r->input ()->disconnect (this);
2398 to_group.push_back (r);
2399 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2404 RouteGroup* rg = NULL;
2405 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2406 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2407 if ((*i)->name () == pi->name ()) {
2413 rg = new RouteGroup (*_session, pi->name ());
2414 _session->add_route_group (rg);
2415 rg->set_gain (false);
2418 GroupTabs::set_group_color (rg, route->presentation_info().color());
2419 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2426 RouteUI::mark_hidden (bool yn)
2428 if (yn != _route->presentation_info().hidden()) {
2429 _route->presentation_info().set_hidden (yn);
2430 return true; // things changed
2435 boost::shared_ptr<Stripable>
2436 RouteUI::stripable () const
2442 RouteUI::set_disk_io_point (DiskIOPoint diop)
2444 if (_route && is_track()) {
2445 track()->set_disk_io_point (diop);