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, true, 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::adjust_latency ()
1932 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->sample_rate(), AudioEngine::instance()->samples_per_cycle());
1937 RouteUI::save_as_template_dialog_response (int response, SaveTemplateDialog* d)
1939 if (response == RESPONSE_ACCEPT) {
1940 const string name = d->get_template_name ();
1941 const string desc = d->get_description ();
1942 const string path = Glib::build_filename(ARDOUR::user_route_template_directory (), name + ARDOUR::template_suffix);
1944 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { /* file already exists. */
1945 bool overwrite = overwrite_file_dialog (*d,
1946 _("Confirm Template Overwrite"),
1947 _("A template already exists with that name. Do you want to overwrite it?"));
1954 _route->save_as_template (path, name, desc);
1961 RouteUI::save_as_template ()
1963 const std::string dir = ARDOUR::user_route_template_directory ();
1965 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1966 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1970 SaveTemplateDialog* d = new SaveTemplateDialog (_route->name(), _route->comment());
1971 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::save_as_template_dialog_response), d));
1976 RouteUI::check_rec_enable_sensitivity ()
1978 if (!rec_enable_button) {
1979 assert (0); // This should not happen
1982 if (!_session->writable()) {
1983 rec_enable_button->set_sensitive (false);
1987 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1988 rec_enable_button->set_sensitive (false);
1989 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1990 rec_enable_button->set_sensitive (false);
1992 rec_enable_button->set_sensitive (true);
1994 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1995 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1997 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1999 update_monitoring_display ();
2003 RouteUI::parameter_changed (string const & p)
2005 /* this handles RC and per-session parameter changes */
2007 if (p == "disable-disarm-during-roll") {
2008 check_rec_enable_sensitivity ();
2009 } else if (p == "solo-control-is-listen-control" || p == "listen-position") {
2010 set_button_names ();
2011 } else if (p == "session-monitoring") {
2012 update_monitoring_display ();
2013 } else if (p == "auto-input") {
2014 update_monitoring_display ();
2015 } else if (p == "blink-rec-arm") {
2016 if (UIConfiguration::instance().get_blink_rec_arm()) {
2017 rec_blink_connection.disconnect ();
2018 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2020 rec_blink_connection.disconnect ();
2021 RouteUI::blink_rec_display(false);
2027 RouteUI::setup_invert_buttons ()
2029 /* remove old invert buttons */
2030 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2031 _invert_button_box.remove (**i);
2034 _invert_buttons.clear ();
2036 if (!_route || !_route->input()) {
2040 uint32_t const N = _route->input()->n_ports().n_audio ();
2042 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2044 for (uint32_t i = 0; i < to_add; ++i) {
2045 ArdourButton* b = manage (new ArdourButton);
2046 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2047 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2049 b->set_name (X_("invert button"));
2052 b->set_text (string_compose (X_("Ă˜ (%1)"), N));
2054 b->set_text (X_("Ă˜"));
2057 b->set_text (string_compose (X_("Ă˜%1"), i + 1));
2060 if (N <= _max_invert_buttons) {
2061 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));
2063 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2066 _invert_buttons.push_back (b);
2067 _invert_button_box.pack_start (*b);
2070 _invert_button_box.set_spacing (1);
2071 _invert_button_box.show_all ();
2075 RouteUI::set_invert_button_state ()
2077 uint32_t const N = _route->input()->n_ports().n_audio();
2078 if (N > _max_invert_buttons) {
2080 /* One button for many channels; explicit active if all channels are inverted,
2081 implicit active if some are, off if none are.
2084 ArdourButton* b = _invert_buttons.front ();
2086 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2087 b->set_active_state (Gtkmm2ext::ExplicitActive);
2088 } else if (_route->phase_control()->any()) {
2089 b->set_active_state (Gtkmm2ext::ImplicitActive);
2091 b->set_active_state (Gtkmm2ext::Off);
2096 /* One button per channel; just set active */
2099 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2100 (*i)->set_active (_route->phase_control()->inverted (j));
2107 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2109 if (ev->button == 1 && i < _invert_buttons.size()) {
2110 uint32_t const N = _route->input()->n_ports().n_audio ();
2111 if (N <= _max_invert_buttons) {
2112 /* left-click inverts phase so long as we have a button per channel */
2113 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2122 RouteUI::invert_press (GdkEventButton* ev)
2124 using namespace Menu_Helpers;
2126 uint32_t const N = _route->input()->n_ports().n_audio();
2127 if (N <= _max_invert_buttons && ev->button != 3) {
2128 /* If we have an invert button per channel, we only pop
2129 up a menu on right-click; left click is handled
2135 delete _invert_menu;
2136 _invert_menu = new Menu;
2137 _invert_menu->set_name ("ArdourContextMenu");
2138 MenuList& items = _invert_menu->items ();
2140 for (uint32_t i = 0; i < N; ++i) {
2141 items.push_back (CheckMenuElem (string_compose (X_("Ă˜%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2142 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2143 ++_i_am_the_modifier;
2144 e->set_active (_route->phase_control()->inverted (i));
2145 --_i_am_the_modifier;
2148 _invert_menu->popup (0, ev->time);
2154 RouteUI::invert_menu_toggled (uint32_t c)
2156 if (_i_am_the_modifier) {
2161 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2165 RouteUI::set_invert_sensitive (bool yn)
2167 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2168 (*b)->set_sensitive (yn);
2172 /** The Route's gui_changed signal has been emitted */
2174 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2176 if (what_changed.contains (Properties::color)) {
2177 if (set_color_from_route () == 0) {
2178 route_color_changed ();
2184 RouteUI::track_mode_changed (void)
2187 switch (track()->mode()) {
2188 case ARDOUR::NonLayered:
2189 case ARDOUR::Normal:
2190 rec_enable_button->set_icon (ArdourIcon::RecButton);
2192 case ARDOUR::Destructive:
2193 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2196 rec_enable_button->queue_draw();
2199 /** @return the color that this route should use; it maybe its own,
2200 * or it maybe that of its route group.
2203 RouteUI::route_color () const
2206 RouteGroup* g = _route->route_group ();
2209 if (g && g->is_color()) {
2210 set_color_from_rgba (c, GroupTabs::group_color (g));
2212 set_color_from_rgba (c, _route->presentation_info().color());
2219 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2221 _showing_sends_to = send_to;
2222 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2226 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2228 if (_route == send_to) {
2229 show_sends_button->set_active (true);
2230 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2232 show_sends_button->set_active (false);
2233 send_blink_connection.disconnect ();
2238 RouteUI::route_group() const
2240 return _route->route_group();
2244 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2245 : WM::ProxyBase (name, string())
2246 , _route (boost::weak_ptr<Route> (route))
2248 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2251 RoutePinWindowProxy::~RoutePinWindowProxy()
2256 ARDOUR::SessionHandlePtr*
2257 RoutePinWindowProxy::session_handle ()
2259 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2260 if (aw) { return aw; }
2265 RoutePinWindowProxy::get (bool create)
2267 boost::shared_ptr<Route> r = _route.lock ();
2276 _window = new PluginPinDialog (r);
2277 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2279 aw->set_session (_session);
2281 _window->show_all ();
2287 RoutePinWindowProxy::route_going_away ()
2291 WM::Manager::instance().remove (this);
2292 going_away_connection.disconnect();
2297 RouteUI::maybe_add_route_print_mgr ()
2299 if (_route->pinmgr_proxy ()) {
2302 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2303 string_compose ("RPM-%1", _route->id()), _route);
2304 wp->set_session (_session);
2306 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2308 wp->set_state (*ui_xml, 0);
2312 void* existing_ui = _route->pinmgr_proxy ();
2314 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2317 _route->set_pingmgr_proxy (wp);
2319 WM::Manager::instance().register_window (wp);
2323 RouteUI::manage_pins ()
2325 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2333 RouteUI::fan_out (bool to_busses, bool group)
2335 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
2339 DisplaySuspender ds;
2340 boost::shared_ptr<ARDOUR::Route> route = _route;
2341 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2344 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2345 if (route->n_outputs ().n_audio () != n_outputs) {
2346 MessageDialog msg (string_compose (
2347 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2348 n_outputs, route->n_outputs ().n_audio ()));
2353 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2355 /* count busses and channels/bus */
2356 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2357 std::map<std::string, uint32_t> busnames;
2358 for (uint32_t p = 0; p < n_outputs; ++p) {
2359 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2360 std::string bn = BUSNAME;
2364 if (busnames.size () < 2) {
2365 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2370 uint32_t outputs = 2;
2371 if (_session->master_out ()) {
2372 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2375 route->output ()->disconnect (this);
2376 route->panner_shell ()->set_bypassed (true);
2379 for (uint32_t p = 0; p < n_outputs; ++p) {
2380 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2381 std::string bn = BUSNAME;
2382 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2386 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2390 list<boost::shared_ptr<AudioTrack> > tl =
2391 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2395 boost::shared_ptr<ControlList> cl (new ControlList);
2396 cl->push_back (r->monitoring_control ());
2397 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2400 if (!to_group.empty()) {
2401 boost::shared_ptr<RouteList> rl (&to_group);
2402 _session->remove_routes (rl);
2406 r->input ()->disconnect (this);
2408 to_group.push_back (r);
2409 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2414 RouteGroup* rg = NULL;
2415 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2416 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2417 if ((*i)->name () == pi->name ()) {
2423 rg = new RouteGroup (*_session, pi->name ());
2424 _session->add_route_group (rg);
2425 rg->set_gain (false);
2428 GroupTabs::set_group_color (rg, route->presentation_info().color());
2429 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2436 RouteUI::mark_hidden (bool yn)
2438 if (yn != _route->presentation_info().hidden()) {
2439 _route->presentation_info().set_hidden (yn);
2440 return true; // things changed
2445 boost::shared_ptr<Stripable>
2446 RouteUI::stripable () const
2452 RouteUI::set_disk_io_point (DiskIOPoint diop)
2454 if (_route && is_track()) {
2455 track()->set_disk_io_point (diop);