2 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3 * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
5 * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
6 * Copyright (C) 2008-2012 Carl Hetherington <carl@carlh.net>
7 * Copyright (C) 2009 Sampo Savolainen <v2@iki.fi>
8 * Copyright (C) 2012-2015 Tim Mayberry <mojofunk@gmail.com>
9 * Copyright (C) 2013-2015 Nick Mainsbridge <mainsbridge@gmail.com>
10 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
11 * Copyright (C) 2014-2017 Ben Loftis <ben@harrisonconsoles.com>
12 * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
13 * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <boost/algorithm/string.hpp>
33 #include <gtkmm/stock.h>
35 #include "pbd/memento_command.h"
36 #include "pbd/stacktrace.h"
37 #include "pbd/controllable.h"
38 #include "pbd/enumwriter.h"
40 #include "ardour/dB.h"
41 #include "ardour/route_group.h"
42 #include "ardour/solo_isolate_control.h"
43 #include "ardour/vca.h"
44 #include "ardour/vca_manager.h"
45 #include "ardour/audio_track.h"
46 #include "ardour/audio_port.h"
47 #include "ardour/audioengine.h"
48 #include "ardour/filename_extensions.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/monitor_control.h"
51 #include "ardour/internal_send.h"
52 #include "ardour/panner_shell.h"
53 #include "ardour/profile.h"
54 #include "ardour/phase_control.h"
55 #include "ardour/send.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/template_utils.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/doi.h"
62 #include "gtkmm2ext/gtk_ui.h"
63 #include "gtkmm2ext/utils.h"
65 #include "widgets/ardour_button.h"
66 #include "widgets/binding_proxy.h"
67 #include "widgets/prompter.h"
69 #include "ardour_dialog.h"
70 #include "ardour_ui.h"
71 #include "automation_time_axis.h"
73 #include "group_tabs.h"
74 #include "gui_object.h"
75 #include "gui_thread.h"
77 #include "latency_gui.h"
78 #include "mixer_strip.h"
79 #include "patch_change_widget.h"
80 #include "plugin_pin_dialog.h"
81 #include "rgb_macros.h"
82 #include "route_time_axis.h"
84 #include "save_template_dialog.h"
86 #include "ui_config.h"
92 using namespace Gtkmm2ext;
93 using namespace ARDOUR;
94 using namespace ARDOUR_UI_UTILS;
95 using namespace ArdourWidgets;
99 uint32_t RouteUI::_max_invert_buttons = 3;
100 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
101 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
102 std::string RouteUI::program_port_prefix;
104 RouteUI::RouteUI (ARDOUR::Session* sess)
105 : monitor_input_button (0)
106 , monitor_disk_button (0)
114 , output_selector (0)
117 if (program_port_prefix.empty()) {
118 // compare to gtk2_ardour/port_group.cc
119 string lpn (PROGRAM_NAME);
120 boost::to_lower (lpn);
121 program_port_prefix = lpn + ":"; // e.g. "ardour:"
132 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
135 delete_patch_change_dialog ();
137 _route.reset (); /* drop reference to route, so that it can be cleaned up */
138 route_connections.drop_connections ();
144 delete comment_window;
145 delete input_selector;
146 delete output_selector;
147 delete monitor_input_button;
148 delete monitor_disk_button;
151 send_blink_connection.disconnect ();
152 rec_blink_connection.disconnect ();
158 self_destruct = true;
164 pre_fader_mute_check = 0;
165 post_fader_mute_check = 0;
166 listen_mute_check = 0;
169 solo_isolated_check = 0;
170 solo_isolated_led = 0;
174 denormal_menu_item = 0;
177 multiple_mute_change = false;
178 multiple_solo_change = false;
179 _i_am_the_modifier = 0;
184 setup_invert_buttons ();
186 mute_button = manage (new ArdourButton);
187 mute_button->set_name ("mute button");
188 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
190 solo_button = manage (new ArdourButton);
191 solo_button->set_name ("solo button");
192 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
193 solo_button->set_no_show_all (true);
195 rec_enable_button = manage (new ArdourButton);
196 rec_enable_button->set_name ("record enable button");
197 rec_enable_button->set_icon (ArdourIcon::RecButton);
198 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
200 if (UIConfiguration::instance().get_blink_rec_arm()) {
201 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
204 show_sends_button = manage (new ArdourButton);
205 show_sends_button->set_name ("send alert button");
206 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
208 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
209 monitor_input_button->set_name ("monitor button");
210 monitor_input_button->set_text (_("In"));
211 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
212 monitor_input_button->set_no_show_all (true);
214 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
215 monitor_disk_button->set_name ("monitor button");
216 monitor_disk_button->set_text (_("Disk"));
217 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
218 monitor_disk_button->set_no_show_all (true);
220 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
221 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
222 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
223 _session->MonitorBusAddedOrRemoved.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::set_button_names, this), gui_context());
225 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
226 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
227 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
229 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
230 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
232 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
233 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
235 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
236 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
237 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
238 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
240 monitor_input_button->set_distinct_led_click (false);
241 monitor_disk_button->set_distinct_led_click (false);
243 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
244 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
246 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
247 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
249 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
255 route_connections.drop_connections ();
263 delete_patch_change_dialog ();
264 _color_picker.reset ();
266 denormal_menu_item = 0;
270 RouteUI::self_delete ()
276 RouteUI::set_route (boost::shared_ptr<Route> rp)
282 if ( !_route->presentation_info().color_set() ) {
283 /* deal with older 4.x color, which was stored in the GUI object state */
285 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
289 /* old v4.x or earlier session. Use this information */
291 int red, green, blue;
296 /* old color format version was:
298 16bit value for red:16 bit value for green:16 bit value for blue
313 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
317 if (set_color_from_route()) {
318 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
322 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
325 delete input_selector;
328 delete output_selector;
331 mute_button->set_controllable (_route->mute_control());
332 solo_button->set_controllable (_route->solo_control());
334 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
336 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
338 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
339 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
340 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
341 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
342 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
343 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, false, true), gui_context());
346 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
347 track_mode_changed();
351 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
352 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
354 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
356 if (_session->writable() && is_track()) {
357 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
359 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
360 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
362 rec_enable_button->show();
363 rec_enable_button->set_controllable (t->rec_enable_control());
365 if (is_midi_track()) {
366 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
367 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
372 /* this will work for busses and tracks, and needs to be called to
373 set up the name entry/name label display.
377 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
378 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
380 update_monitoring_display ();
383 mute_button->unset_flags (Gtk::CAN_FOCUS);
384 solo_button->unset_flags (Gtk::CAN_FOCUS);
388 if (_route->is_monitor() || _route->is_master()) {
389 solo_button->hide ();
396 setup_invert_buttons ();
397 set_invert_button_state ();
399 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
400 bus_send_display_changed (s);
402 update_mute_display ();
403 update_solo_display ();
405 if (!UIConfiguration::instance().get_blink_rec_arm()) {
406 blink_rec_display(true); // set initial rec-en button state
409 check_rec_enable_sensitivity ();
410 maybe_add_route_print_mgr ();
411 route_color_changed();
412 route_gui_changed (PropertyChange (Properties::selected));
416 RouteUI::polarity_changed ()
422 set_invert_button_state ();
426 RouteUI::mute_press (GdkEventButton* ev)
428 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
432 //if this is a binding action, let the ArdourButton handle it
433 if (BindingProxy::is_bind_action(ev) )
436 multiple_mute_change = false;
438 if (Keyboard::is_context_menu_event (ev)) {
444 mute_menu->popup(0,ev->time);
450 if (Keyboard::is_button2_event (ev)) {
451 // button2-click is "momentary"
453 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
456 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
458 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
460 /* toggle mute on everything (but
461 * exclude the master and monitor)
463 * because we are going to erase
464 * elements of the list we need to work
468 boost::shared_ptr<RouteList> copy (new RouteList);
470 *copy = *_session->get_routes ();
472 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
473 if ((*i)->is_master() || (*i)->is_monitor()) {
481 _mute_release->routes = copy;
484 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
486 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
488 /* Primary-button1 inverts the implication of
489 the group being active. If the group is
490 active (for mute), then this modifier means
491 "do not apply to mute". If the group is
492 inactive (for mute), then this modifier
493 means "apply to route". This is all
494 accomplished by passing just the actual
495 route, along with the InverseGroup group
498 NOTE: Primary-button2 is MIDI learn.
501 boost::shared_ptr<RouteList> rl;
503 if (ev->button == 1) {
505 rl.reset (new RouteList);
506 rl->push_back (_route);
509 _mute_release->routes = rl;
512 boost::shared_ptr<MuteControl> mc = _route->mute_control();
513 mc->start_touch (_session->audible_sample ());
514 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
519 /* plain click applies change to this route */
521 boost::shared_ptr<RouteList> rl (new RouteList);
522 rl->push_back (_route);
525 _mute_release->routes = rl;
528 boost::shared_ptr<MuteControl> mc = _route->mute_control();
529 mc->start_touch (_session->audible_sample ());
530 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
539 RouteUI::mute_release (GdkEventButton* /*ev*/)
542 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
543 delete _mute_release;
547 _route->mute_control()->stop_touch (_session->audible_sample ());
553 RouteUI::edit_output_configuration ()
555 if (output_selector == 0) {
557 boost::shared_ptr<Send> send;
558 boost::shared_ptr<IO> output;
560 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
561 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
562 output = send->output();
564 output = _route->output ();
567 output = _route->output ();
570 output_selector = new IOSelectorWindow (_session, output);
573 if (output_selector->is_visible()) {
574 output_selector->get_toplevel()->get_window()->raise();
576 output_selector->present ();
579 //output_selector->set_keep_above (true);
583 RouteUI::edit_input_configuration ()
585 if (input_selector == 0) {
586 input_selector = new IOSelectorWindow (_session, _route->input());
589 if (input_selector->is_visible()) {
590 input_selector->get_toplevel()->get_window()->raise();
592 input_selector->present ();
595 //input_selector->set_keep_above (true);
599 RouteUI::solo_press(GdkEventButton* ev)
601 /* ignore double/triple clicks */
603 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
607 //if this is a binding action, let the ArdourButton handle it
608 if (BindingProxy::is_bind_action(ev) )
611 multiple_solo_change = false;
613 if (Keyboard::is_context_menu_event (ev)) {
615 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
616 ! (solo_safe_led && solo_safe_led->is_visible())) {
618 if (solo_menu == 0) {
622 solo_menu->popup (1, ev->time);
627 if (Keyboard::is_button2_event (ev)) {
629 // button2-click is "momentary"
630 _solo_release = new SoloMuteRelease (_route->self_soloed());
633 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
635 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
637 /* Primary-Tertiary-click applies change to all routes */
640 _solo_release->routes = _session->get_routes ();
643 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
645 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
647 /* Primary-Secondary-click: exclusively solo this track */
650 _solo_release->exclusive = true;
652 _solo_release->routes_on.reset (new RouteList);
653 _solo_release->routes_off.reset (new RouteList);
655 boost::shared_ptr<RouteList> routes = _session->get_routes();
656 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
658 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
662 if ((*i)->soloed ()) {
663 _solo_release->routes_on->push_back (*i);
665 _solo_release->routes_off->push_back (*i);
670 boost::shared_ptr<RouteList> rl (new RouteList);
671 boost::shared_ptr<RouteList> routes = _session->get_routes();
672 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
674 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
678 if ((*i)->soloed ()) {
682 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
684 if (Config->get_solo_control_is_listen_control()) {
685 /* ??? we need a just_one_listen() method */
688 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
691 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
693 // shift-click: toggle solo isolated status
695 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
696 delete _solo_release;
699 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
701 /* Primary-button1: solo mix group.
702 NOTE: Primary-button2 is MIDI learn.
705 /* Primary-button1 applies change to the mix group even if it is not active
706 NOTE: Primary-button2 is MIDI learn.
709 boost::shared_ptr<RouteList> rl;
711 if (ev->button == 1) {
713 /* Primary-button1 inverts the implication of
714 the group being active. If the group is
715 active (for solo), then this modifier means
716 "do not apply to solo". If the group is
717 inactive (for mute), then this modifier
718 means "apply to route". This is all
719 accomplished by passing just the actual
720 route, along with the InverseGroup group
723 NOTE: Primary-button2 is MIDI learn.
726 rl.reset (new RouteList);
727 rl->push_back (_route);
730 _solo_release->routes = rl;
733 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
736 delete _solo_release;
741 /* click: solo this route */
743 boost::shared_ptr<RouteList> rl (new RouteList);
744 rl->push_back (route());
747 _solo_release->routes = rl;
750 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
759 RouteUI::solo_release (GdkEventButton* /*ev*/)
762 if (_solo_release->exclusive) {
763 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
764 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
766 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
769 delete _solo_release;
777 RouteUI::rec_enable_press(GdkEventButton* ev)
779 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
783 //if this is a binding action, let the ArdourButton handle it
784 if (BindingProxy::is_bind_action(ev) )
787 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
791 if (is_midi_track()) {
793 /* rec-enable button exits from step editing, but not context click */
795 if (!Keyboard::is_context_menu_event (ev) && midi_track()->step_editing()) {
796 midi_track()->set_step_editing (false);
801 if (is_track() && rec_enable_button) {
803 if (Keyboard::is_button2_event (ev)) {
805 //rec arm does not have a momentary mode
808 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
810 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
812 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
814 /* Primary-button1 applies change to the route group (even if it is not active)
815 NOTE: Primary-button2 is MIDI learn.
818 if (ev->button == 1) {
820 boost::shared_ptr<RouteList> rl;
822 rl.reset (new RouteList);
823 rl->push_back (_route);
825 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
828 } else if (Keyboard::is_context_menu_event (ev)) {
830 /* do this on release */
834 boost::shared_ptr<Track> trk = track();
835 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
843 RouteUI::update_monitoring_display ()
849 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
855 MonitorState ms = t->monitoring_state();
857 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
858 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
860 if (ms & MonitoringInput) {
861 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
863 monitor_input_button->unset_active_state ();
867 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
868 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
870 if (ms & MonitoringDisk) {
871 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
873 monitor_disk_button->unset_active_state ();
879 RouteUI::monitor_input_press(GdkEventButton*)
885 RouteUI::monitor_input_release(GdkEventButton* ev)
887 return monitor_release (ev, MonitorInput);
891 RouteUI::monitor_disk_press (GdkEventButton*)
897 RouteUI::monitor_disk_release (GdkEventButton* ev)
899 return monitor_release (ev, MonitorDisk);
903 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
905 if (ev->button != 1) {
909 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
916 boost::shared_ptr<RouteList> rl;
918 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
919 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
921 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() | monitor_choice);
924 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
925 /* Primary-Tertiary-click applies change to all routes */
926 rl = _session->get_routes ();
927 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
928 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
929 /* Primary-click overrides group */
930 rl.reset (new RouteList);
931 rl->push_back (route());
932 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
934 rl.reset (new RouteList);
935 rl->push_back (route());
936 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
943 RouteUI::build_record_menu ()
946 record_menu = new Menu;
947 record_menu->set_name ("ArdourContextMenu");
948 using namespace Menu_Helpers;
949 MenuList& items = record_menu->items();
951 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
952 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
954 if (is_midi_track()) {
955 items.push_back (SeparatorElem());
956 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
957 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
961 if (step_edit_item) {
962 if (track()->rec_enable_control()->get_value()) {
963 step_edit_item->set_sensitive (false);
965 step_edit_item->set_active (midi_track()->step_editing());
968 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
969 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
974 RouteUI::toggle_step_edit ()
976 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
980 midi_track()->set_step_editing (step_edit_item->get_active());
984 RouteUI::toggle_rec_safe ()
986 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
992 /* This check is made inside the control too, but dong it here can't
996 if (_route->rec_enable_control()->get_value()) {
1000 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
1004 RouteUI::step_edit_changed (bool yn)
1007 if (rec_enable_button) {
1008 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1011 start_step_editing ();
1013 if (step_edit_item) {
1014 step_edit_item->set_active (true);
1019 if (rec_enable_button) {
1020 rec_enable_button->unset_active_state ();
1023 stop_step_editing ();
1025 if (step_edit_item) {
1026 step_edit_item->set_active (false);
1032 RouteUI::rec_enable_release (GdkEventButton* ev)
1034 if (Keyboard::is_context_menu_event (ev)) {
1035 build_record_menu ();
1037 record_menu->popup (1, ev->time);
1046 RouteUI::build_sends_menu ()
1048 using namespace Menu_Helpers;
1050 sends_menu = new Menu;
1051 sends_menu->set_name ("ArdourContextMenu");
1052 MenuList& items = sends_menu->items();
1055 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1059 MenuElem(_("Assign all tracks and busses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1063 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1067 MenuElem(_("Assign all tracks and busses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1071 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1075 MenuElem(_("Assign selected tracks and busses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1078 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1082 MenuElem(_("Assign selected tracks and busses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1085 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1086 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1087 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1092 RouteUI::create_sends (Placement p, bool include_buses)
1094 _session->globally_add_internal_sends (_route, p, include_buses);
1098 RouteUI::create_selected_sends (Placement p, bool include_buses)
1100 boost::shared_ptr<RouteList> rlist (new RouteList);
1101 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1103 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1104 RouteTimeAxisView* rtv;
1106 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1107 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1108 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1109 rlist->push_back (rui->route());
1115 _session->add_internal_sends (_route, p, rlist);
1119 RouteUI::set_sends_gain_from_track ()
1121 _session->globally_set_send_gains_from_track (_route);
1125 RouteUI::set_sends_gain_to_zero ()
1127 _session->globally_set_send_gains_to_zero (_route);
1131 RouteUI::set_sends_gain_to_unity ()
1133 _session->globally_set_send_gains_to_unity (_route);
1137 RouteUI::show_sends_press(GdkEventButton* ev)
1139 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1143 if (!is_track() && show_sends_button) {
1145 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1147 // do nothing on midi sigc::bind event
1150 } else if (Keyboard::is_context_menu_event (ev)) {
1152 if (sends_menu == 0) {
1153 build_sends_menu ();
1156 sends_menu->popup (0, ev->time);
1160 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1163 set_showing_sends_to (boost::shared_ptr<Route> ());
1165 set_showing_sends_to (_route);
1174 RouteUI::show_sends_release (GdkEventButton*)
1180 RouteUI::send_blink (bool onoff)
1182 if (!show_sends_button) {
1187 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1189 show_sends_button->unset_active_state ();
1193 Gtkmm2ext::ActiveState
1194 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1196 boost::shared_ptr<SoloControl> sc = s->solo_control();
1199 return Gtkmm2ext::Off;
1202 if (!sc->can_solo()) {
1203 return Gtkmm2ext::Off;
1207 if (sc->self_soloed()) {
1208 return Gtkmm2ext::ExplicitActive;
1209 } else if (sc->soloed_by_others()) {
1210 return Gtkmm2ext::ImplicitActive;
1212 return Gtkmm2ext::Off;
1216 Gtkmm2ext::ActiveState
1217 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1219 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1222 return Gtkmm2ext::Off;
1225 if (s->is_master() || s->is_monitor()) {
1226 return Gtkmm2ext::Off;
1229 if (sc->solo_isolated()) {
1230 return Gtkmm2ext::ExplicitActive;
1232 return Gtkmm2ext::Off;
1236 Gtkmm2ext::ActiveState
1237 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1239 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1242 return Gtkmm2ext::Off;
1245 if (s->is_master() || s->is_monitor()) {
1246 return Gtkmm2ext::Off;
1249 if (sc->solo_safe()) {
1250 return Gtkmm2ext::ExplicitActive;
1252 return Gtkmm2ext::Off;
1257 RouteUI::update_solo_display ()
1259 bool yn = _route->solo_safe_control()->solo_safe ();
1261 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1262 solo_safe_check->set_active (yn);
1265 yn = _route->solo_isolate_control()->solo_isolated ();
1267 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1268 solo_isolated_check->set_active (yn);
1271 set_button_names ();
1273 if (solo_isolated_led) {
1274 if (_route->solo_isolate_control()->solo_isolated()) {
1275 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1277 solo_isolated_led->unset_active_state ();
1281 if (solo_safe_led) {
1282 if (_route->solo_safe_control()->solo_safe()) {
1283 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1285 solo_safe_led->unset_active_state ();
1289 solo_button->set_active_state (solo_active_state (_route));
1291 /* some changes to solo status can affect mute display, so catch up
1294 update_mute_display ();
1298 RouteUI::solo_changed_so_update_mute ()
1300 update_mute_display ();
1304 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1306 boost::shared_ptr<MuteControl> mc = s->mute_control();
1308 if (s->is_monitor()) {
1309 return Gtkmm2ext::Off;
1313 return Gtkmm2ext::Off;
1316 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1318 if (mc->muted_by_self ()) {
1320 return Gtkmm2ext::ExplicitActive;
1321 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1322 /* this will reflect both solo mutes AND master mutes */
1323 return Gtkmm2ext::ImplicitActive;
1325 /* no mute at all */
1326 return Gtkmm2ext::Off;
1331 if (mc->muted_by_self()) {
1333 return Gtkmm2ext::ExplicitActive;
1334 } else if (mc->muted_by_masters ()) {
1335 /* this shows only master mutes, not mute-by-others-soloing */
1336 return Gtkmm2ext::ImplicitActive;
1338 /* no mute at all */
1339 return Gtkmm2ext::Off;
1343 return ActiveState(0);
1347 RouteUI::update_mute_display ()
1353 mute_button->set_active_state (mute_active_state (_session, _route));
1358 RouteUI::route_rec_enable_changed ()
1360 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1364 RouteUI::session_rec_enable_changed ()
1366 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1370 RouteUI::blink_rec_display (bool blinkOn)
1372 if (!rec_enable_button || !_route) {
1376 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1384 if (track()->rec_enable_control()->get_value()) {
1385 switch (_session->record_status ()) {
1386 case Session::Recording:
1387 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1390 case Session::Disabled:
1391 case Session::Enabled:
1392 if (UIConfiguration::instance().get_blink_rec_arm()) {
1393 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1395 rec_enable_button->set_active_state ( ImplicitActive );
1400 if (step_edit_item) {
1401 step_edit_item->set_sensitive (false);
1405 rec_enable_button->unset_active_state ();
1407 if (step_edit_item) {
1408 step_edit_item->set_sensitive (true);
1412 check_rec_enable_sensitivity ();
1416 RouteUI::build_solo_menu (void)
1418 using namespace Menu_Helpers;
1420 solo_menu = new Menu;
1421 solo_menu->set_name ("ArdourContextMenu");
1422 MenuList& items = solo_menu->items();
1423 Gtk::CheckMenuItem* check;
1425 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1426 check->set_active (_route->solo_isolate_control()->solo_isolated());
1427 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1428 items.push_back (CheckMenuElem(*check));
1429 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1432 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1433 check->set_active (_route->solo_safe_control()->solo_safe());
1434 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1435 items.push_back (CheckMenuElem(*check));
1436 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1441 RouteUI::build_mute_menu(void)
1443 using namespace Menu_Helpers;
1445 mute_menu = new Menu;
1446 mute_menu->set_name ("ArdourContextMenu");
1448 MenuList& items = mute_menu->items();
1450 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1451 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1452 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1453 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1454 pre_fader_mute_check->show_all();
1456 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1457 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1458 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1459 items.push_back (CheckMenuElem(*post_fader_mute_check));
1460 post_fader_mute_check->show_all();
1462 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1463 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1464 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1465 items.push_back (CheckMenuElem(*listen_mute_check));
1466 listen_mute_check->show_all();
1468 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1469 init_mute_menu(MuteMaster::Main, main_mute_check);
1470 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1471 items.push_back (CheckMenuElem(*main_mute_check));
1472 main_mute_check->show_all();
1474 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1478 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1480 check->set_active (_route->mute_control()->mute_points() & mp);
1484 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1486 if (check->get_active()) {
1487 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1489 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1494 RouteUI::muting_change ()
1496 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1499 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1501 yn = (current & MuteMaster::PreFader);
1503 if (pre_fader_mute_check->get_active() != yn) {
1504 pre_fader_mute_check->set_active (yn);
1507 yn = (current & MuteMaster::PostFader);
1509 if (post_fader_mute_check->get_active() != yn) {
1510 post_fader_mute_check->set_active (yn);
1513 yn = (current & MuteMaster::Listen);
1515 if (listen_mute_check->get_active() != yn) {
1516 listen_mute_check->set_active (yn);
1519 yn = (current & MuteMaster::Main);
1521 if (main_mute_check->get_active() != yn) {
1522 main_mute_check->set_active (yn);
1527 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1529 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1533 bool view = solo_isolated_led->active_state();
1534 bool model = _route->solo_isolate_control()->solo_isolated();
1536 /* called BEFORE the view has changed */
1538 if (ev->button == 1) {
1539 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1542 /* disable isolate for all routes */
1543 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1545 /* enable isolate for all routes */
1546 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1551 if (model == view) {
1553 /* flip just this route */
1555 boost::shared_ptr<RouteList> rl (new RouteList);
1556 rl->push_back (_route);
1557 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1566 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1568 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1572 bool view = solo_safe_led->active_state();
1573 bool model = _route->solo_safe_control()->solo_safe();
1575 if (ev->button == 1) {
1576 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1577 boost::shared_ptr<RouteList> rl (_session->get_routes());
1579 /* disable solo safe for all routes */
1580 DisplaySuspender ds;
1581 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1582 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1585 /* enable solo safe for all routes */
1586 DisplaySuspender ds;
1587 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1588 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1593 if (model == view) {
1594 /* flip just this route */
1595 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1604 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1606 bool view = check->get_active();
1607 bool model = _route->solo_isolate_control()->solo_isolated();
1609 /* called AFTER the view has changed */
1611 if (model != view) {
1612 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1617 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1619 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1623 RouteUI::delete_patch_change_dialog ()
1628 delete _route->patch_selector_dialog ();
1629 _route->set_patch_selector_dialog (0);
1632 PatchChangeGridDialog*
1633 RouteUI::patch_change_dialog () const
1635 return _route->patch_selector_dialog ();
1639 RouteUI::select_midi_patch ()
1641 if (patch_change_dialog ()) {
1642 patch_change_dialog()->present ();
1646 /* note: RouteTimeAxisView is resoponsible to updating
1647 * the Dialog (PatchChangeGridDialog::refresh())
1648 * when the midnam model changes.
1650 PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1651 _route->set_patch_selector_dialog (d);
1655 /** Ask the user to choose a colour, and then apply that color to my route */
1657 RouteUI::choose_color ()
1659 _color_picker.popup (_route);
1662 /** Set the route's own color. This may not be used for display if
1663 * the route is in a group which shares its color with its routes.
1666 RouteUI::set_color (uint32_t c)
1668 _route->presentation_info().set_color (c);
1671 /** @return GUI state ID for things that are common to the route in all its representations */
1673 RouteUI::route_state_id () const
1675 return string_compose (X_("route %1"), _route->id().to_s());
1679 RouteUI::set_color_from_route ()
1681 if (_route->presentation_info().color_set()) {
1682 return 0; /* nothing to do */
1685 return 1; /* pick a color */
1688 /** @return true if this name should be used for the route, otherwise false */
1690 RouteUI::verify_new_route_name (const std::string& name)
1692 if (name.find (':') == string::npos) {
1696 MessageDialog colon_msg (
1697 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1698 false, MESSAGE_QUESTION, BUTTONS_NONE
1701 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1702 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1704 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1708 RouteUI::route_rename ()
1710 ArdourWidgets::Prompter name_prompter (true);
1715 name_prompter.set_title (_("Rename Track"));
1717 name_prompter.set_title (_("Rename Bus"));
1719 name_prompter.set_prompt (_("New name:"));
1720 name_prompter.set_initial_text (_route->name());
1721 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1722 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1723 name_prompter.show_all ();
1726 switch (name_prompter.run ()) {
1727 case Gtk::RESPONSE_ACCEPT:
1728 name_prompter.get_result (result);
1729 name_prompter.hide ();
1730 if (result.length()) {
1731 if (verify_new_route_name (result)) {
1732 _route->set_name (result);
1735 /* back to name prompter */
1739 /* nothing entered, just get out of here */
1754 RouteUI::toggle_comment_editor ()
1756 // if (ignore_toggle) {
1760 if (comment_window && comment_window->is_visible ()) {
1761 comment_window->hide ();
1763 open_comment_editor ();
1769 RouteUI::open_comment_editor ()
1771 if (comment_window == 0) {
1772 setup_comment_editor ();
1776 title = _route->name();
1777 title += _(": comment editor");
1779 comment_window->set_title (title);
1780 comment_window->present();
1784 RouteUI::setup_comment_editor ()
1786 comment_window = new ArdourWindow (""); // title will be reset to show route
1787 comment_window->set_skip_taskbar_hint (true);
1788 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1789 comment_window->set_default_size (400, 200);
1791 comment_area = manage (new TextView());
1792 comment_area->set_name ("MixerTrackCommentArea");
1793 comment_area->set_wrap_mode (WRAP_WORD);
1794 comment_area->set_editable (true);
1795 comment_area->get_buffer()->set_text (_route->comment());
1796 comment_area->show ();
1798 comment_window->add (*comment_area);
1802 RouteUI::comment_changed ()
1804 ignore_comment_edit = true;
1806 comment_area->get_buffer()->set_text (_route->comment());
1808 ignore_comment_edit = false;
1812 RouteUI::comment_editor_done_editing ()
1814 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1816 string const str = comment_area->get_buffer()->get_text();
1817 if (str == _route->comment ()) {
1821 _route->set_comment (str, this);
1825 RouteUI::set_route_active (bool a, bool apply_to_selection)
1827 if (apply_to_selection) {
1828 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1830 _route->set_active (a, this);
1835 RouteUI::duplicate_selected_routes ()
1837 ARDOUR_UI::instance()->start_duplicate_routes();
1841 RouteUI::toggle_denormal_protection ()
1843 if (denormal_menu_item) {
1847 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1849 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1850 _route->set_denormal_protection (x);
1856 RouteUI::denormal_protection_changed ()
1858 if (denormal_menu_item) {
1859 denormal_menu_item->set_active (_route->denormal_protection());
1864 RouteUI::disconnect_input ()
1866 _route->input()->disconnect (this);
1870 RouteUI::disconnect_output ()
1872 _route->output()->disconnect (this);
1876 RouteUI::is_track () const
1878 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1881 boost::shared_ptr<Track>
1882 RouteUI::track() const
1884 return boost::dynamic_pointer_cast<Track>(_route);
1888 RouteUI::is_audio_track () const
1890 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1893 boost::shared_ptr<AudioTrack>
1894 RouteUI::audio_track() const
1896 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1900 RouteUI::is_midi_track () const
1902 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1905 boost::shared_ptr<MidiTrack>
1906 RouteUI::midi_track() const
1908 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1912 RouteUI::has_audio_outputs () const
1914 return (_route->n_outputs().n_audio() > 0);
1918 RouteUI::map_frozen ()
1920 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1922 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1925 check_rec_enable_sensitivity ();
1930 RouteUI::save_as_template_dialog_response (int response, SaveTemplateDialog* d)
1932 if (response == RESPONSE_ACCEPT) {
1933 const string name = d->get_template_name ();
1934 const string desc = d->get_description ();
1935 const string path = Glib::build_filename(ARDOUR::user_route_template_directory (), name + ARDOUR::template_suffix);
1937 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { /* file already exists. */
1938 bool overwrite = overwrite_file_dialog (*d,
1939 _("Confirm Template Overwrite"),
1940 _("A template already exists with that name. Do you want to overwrite it?"));
1947 _route->save_as_template (path, name, desc);
1954 RouteUI::save_as_template ()
1956 const std::string dir = ARDOUR::user_route_template_directory ();
1958 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1959 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1963 SaveTemplateDialog* d = new SaveTemplateDialog (_route->name(), _route->comment());
1964 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::save_as_template_dialog_response), d));
1969 RouteUI::check_rec_enable_sensitivity ()
1971 if (!rec_enable_button) {
1972 assert (0); // This should not happen
1975 if (!_session->writable()) {
1976 rec_enable_button->set_sensitive (false);
1980 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1981 rec_enable_button->set_sensitive (false);
1982 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1983 rec_enable_button->set_sensitive (false);
1985 rec_enable_button->set_sensitive (true);
1987 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1988 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1990 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1992 update_monitoring_display ();
1996 RouteUI::parameter_changed (string const & p)
1998 /* this handles RC and per-session parameter changes */
2000 if (p == "disable-disarm-during-roll") {
2001 check_rec_enable_sensitivity ();
2002 } else if (p == "solo-control-is-listen-control" || p == "listen-position") {
2003 set_button_names ();
2004 } else if (p == "session-monitoring") {
2005 update_monitoring_display ();
2006 } else if (p == "auto-input") {
2007 update_monitoring_display ();
2008 } else if (p == "blink-rec-arm") {
2009 if (UIConfiguration::instance().get_blink_rec_arm()) {
2010 rec_blink_connection.disconnect ();
2011 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2013 rec_blink_connection.disconnect ();
2014 RouteUI::blink_rec_display(false);
2020 RouteUI::setup_invert_buttons ()
2022 /* remove old invert buttons */
2023 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2024 _invert_button_box.remove (**i);
2027 _invert_buttons.clear ();
2029 if (!_route || !_route->input()) {
2033 uint32_t const N = _route->input()->n_ports().n_audio ();
2035 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2037 for (uint32_t i = 0; i < to_add; ++i) {
2038 ArdourButton* b = manage (new ArdourButton);
2039 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2040 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2042 b->set_name (X_("invert button"));
2045 b->set_text (string_compose (X_("Ă˜ (%1)"), N));
2047 b->set_text (X_("Ă˜"));
2050 b->set_text (string_compose (X_("Ă˜%1"), i + 1));
2053 if (N <= _max_invert_buttons) {
2054 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));
2056 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2059 _invert_buttons.push_back (b);
2060 _invert_button_box.pack_start (*b);
2063 _invert_button_box.set_spacing (1);
2064 _invert_button_box.show_all ();
2068 RouteUI::set_invert_button_state ()
2070 uint32_t const N = _route->input()->n_ports().n_audio();
2071 if (N > _max_invert_buttons) {
2073 /* One button for many channels; explicit active if all channels are inverted,
2074 implicit active if some are, off if none are.
2077 ArdourButton* b = _invert_buttons.front ();
2079 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2080 b->set_active_state (Gtkmm2ext::ExplicitActive);
2081 } else if (_route->phase_control()->any()) {
2082 b->set_active_state (Gtkmm2ext::ImplicitActive);
2084 b->set_active_state (Gtkmm2ext::Off);
2089 /* One button per channel; just set active */
2092 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2093 (*i)->set_active (_route->phase_control()->inverted (j));
2100 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2102 if (ev->button == 1 && i < _invert_buttons.size()) {
2103 uint32_t const N = _route->input()->n_ports().n_audio ();
2104 if (N <= _max_invert_buttons) {
2105 /* left-click inverts phase so long as we have a button per channel */
2106 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2115 RouteUI::invert_press (GdkEventButton* ev)
2117 using namespace Menu_Helpers;
2119 uint32_t const N = _route->input()->n_ports().n_audio();
2120 if (N <= _max_invert_buttons && ev->button != 3) {
2121 /* If we have an invert button per channel, we only pop
2122 up a menu on right-click; left click is handled
2128 delete _invert_menu;
2129 _invert_menu = new Menu;
2130 _invert_menu->set_name ("ArdourContextMenu");
2131 MenuList& items = _invert_menu->items ();
2133 for (uint32_t i = 0; i < N; ++i) {
2134 items.push_back (CheckMenuElem (string_compose (X_("Ă˜%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2135 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2136 ++_i_am_the_modifier;
2137 e->set_active (_route->phase_control()->inverted (i));
2138 --_i_am_the_modifier;
2141 _invert_menu->popup (0, ev->time);
2147 RouteUI::invert_menu_toggled (uint32_t c)
2149 if (_i_am_the_modifier) {
2154 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2158 RouteUI::set_invert_sensitive (bool yn)
2160 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2161 (*b)->set_sensitive (yn);
2165 /** The Route's gui_changed signal has been emitted */
2167 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2169 if (what_changed.contains (Properties::color)) {
2170 if (set_color_from_route () == 0) {
2171 route_color_changed ();
2177 RouteUI::track_mode_changed (void)
2180 switch (track()->mode()) {
2181 case ARDOUR::NonLayered:
2182 case ARDOUR::Normal:
2183 rec_enable_button->set_icon (ArdourIcon::RecButton);
2185 case ARDOUR::Destructive:
2186 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2189 rec_enable_button->queue_draw();
2192 /** @return the color that this route should use; it maybe its own,
2193 * or it maybe that of its route group.
2196 RouteUI::route_color () const
2199 RouteGroup* g = _route->route_group ();
2202 if (g && g->is_color()) {
2203 set_color_from_rgba (c, GroupTabs::group_color (g));
2205 set_color_from_rgba (c, _route->presentation_info().color());
2212 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2214 _showing_sends_to = send_to;
2215 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2219 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2221 if (_route == send_to) {
2222 show_sends_button->set_active (true);
2223 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2225 show_sends_button->set_active (false);
2226 send_blink_connection.disconnect ();
2231 RouteUI::route_group() const
2233 return _route->route_group();
2237 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2238 : WM::ProxyBase (name, string())
2239 , _route (boost::weak_ptr<Route> (route))
2241 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2244 RoutePinWindowProxy::~RoutePinWindowProxy()
2249 ARDOUR::SessionHandlePtr*
2250 RoutePinWindowProxy::session_handle ()
2252 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2253 if (aw) { return aw; }
2258 RoutePinWindowProxy::get (bool create)
2260 boost::shared_ptr<Route> r = _route.lock ();
2269 _window = new PluginPinDialog (r);
2270 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2272 aw->set_session (_session);
2274 _window->show_all ();
2280 RoutePinWindowProxy::route_going_away ()
2284 WM::Manager::instance().remove (this);
2285 going_away_connection.disconnect();
2290 RouteUI::maybe_add_route_print_mgr ()
2292 if (_route->pinmgr_proxy ()) {
2295 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2296 string_compose ("RPM-%1", _route->id()), _route);
2297 wp->set_session (_session);
2299 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2301 wp->set_state (*ui_xml, 0);
2305 void* existing_ui = _route->pinmgr_proxy ();
2307 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2310 _route->set_pingmgr_proxy (wp);
2312 WM::Manager::instance().register_window (wp);
2316 RouteUI::manage_pins ()
2318 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2326 RouteUI::fan_out (bool to_busses, bool group)
2328 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
2332 DisplaySuspender ds;
2333 boost::shared_ptr<ARDOUR::Route> route = _route;
2334 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2337 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2338 if (route->n_outputs ().n_audio () != n_outputs) {
2339 MessageDialog msg (string_compose (
2340 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2341 n_outputs, route->n_outputs ().n_audio ()));
2346 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2348 /* count busses and channels/bus */
2349 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2350 std::map<std::string, uint32_t> busnames;
2351 for (uint32_t p = 0; p < n_outputs; ++p) {
2352 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2353 std::string bn = BUSNAME;
2357 if (busnames.size () < 2) {
2358 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2363 uint32_t outputs = 2;
2364 if (_session->master_out ()) {
2365 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2368 route->output ()->disconnect (this);
2369 route->panner_shell ()->set_bypassed (true);
2371 boost::shared_ptr<AutomationControl> msac = route->master_send_enable_controllable ();
2373 msac->start_touch (msac->session().transport_sample());
2374 msac->set_value (0, PBD::Controllable::NoGroup);
2378 for (uint32_t p = 0; p < n_outputs; ++p) {
2379 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2380 std::string bn = BUSNAME;
2381 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2385 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2389 list<boost::shared_ptr<AudioTrack> > tl =
2390 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2394 boost::shared_ptr<ControlList> cl (new ControlList);
2395 cl->push_back (r->monitoring_control ());
2396 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2399 if (!to_group.empty()) {
2400 boost::shared_ptr<RouteList> rl (&to_group);
2401 _session->remove_routes (rl);
2405 r->input ()->disconnect (this);
2407 to_group.push_back (r);
2408 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2413 RouteGroup* rg = NULL;
2414 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2415 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2416 if ((*i)->name () == pi->name ()) {
2422 rg = new RouteGroup (*_session, pi->name ());
2423 _session->add_route_group (rg);
2424 rg->set_gain (false);
2427 GroupTabs::set_group_color (rg, route->presentation_info().color());
2428 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2435 RouteUI::mark_hidden (bool yn)
2437 if (yn != _route->presentation_info().hidden()) {
2438 _route->presentation_info().set_hidden (yn);
2439 return true; // things changed
2444 boost::shared_ptr<Stripable>
2445 RouteUI::stripable () const
2451 RouteUI::set_disk_io_point (DiskIOPoint diop)
2453 if (_route && is_track()) {
2454 track()->set_disk_io_point (diop);