2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <boost/algorithm/string.hpp>
23 #include <gtkmm2ext/gtk_ui.h>
24 #include <gtkmm2ext/choice.h>
25 #include <gtkmm2ext/doi.h>
26 #include <gtkmm2ext/bindable_button.h>
27 #include <gtkmm2ext/barcontroller.h>
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
31 #include "pbd/memento_command.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour/dB.h"
37 #include "ardour/route_group.h"
38 #include "ardour/solo_isolate_control.h"
39 #include "ardour/vca.h"
40 #include "ardour/vca_manager.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/filename_extensions.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/monitor_control.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/profile.h"
50 #include "ardour/phase_control.h"
51 #include "ardour/send.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/template_utils.h"
56 #include "ardour_button.h"
57 #include "ardour_dialog.h"
58 #include "ardour_ui.h"
59 #include "automation_time_axis.h"
61 #include "group_tabs.h"
62 #include "gui_object.h"
63 #include "gui_thread.h"
65 #include "latency_gui.h"
66 #include "mixer_strip.h"
67 #include "plugin_pin_dialog.h"
69 #include "rgb_macros.h"
70 #include "route_time_axis.h"
73 #include "ui_config.h"
79 using namespace Gtkmm2ext;
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
85 uint32_t RouteUI::_max_invert_buttons = 3;
86 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
87 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
88 std::string RouteUI::program_port_prefix;
90 RouteUI::RouteUI (ARDOUR::Session* sess)
91 : monitor_input_button (0)
92 , monitor_disk_button (0)
100 , output_selector (0)
103 if (program_port_prefix.empty()) {
104 // compare to gtk2_ardour/port_group.cc
105 string lpn (PROGRAM_NAME);
106 boost::to_lower (lpn);
107 program_port_prefix = lpn + ":"; // e.g. "ardour:"
118 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
121 _route.reset (); /* drop reference to route, so that it can be cleaned up */
122 route_connections.drop_connections ();
128 delete comment_window;
129 delete input_selector;
130 delete output_selector;
131 delete monitor_input_button;
132 delete monitor_disk_button;
135 send_blink_connection.disconnect ();
136 rec_blink_connection.disconnect ();
142 self_destruct = true;
148 pre_fader_mute_check = 0;
149 post_fader_mute_check = 0;
150 listen_mute_check = 0;
153 solo_isolated_check = 0;
154 solo_isolated_led = 0;
158 denormal_menu_item = 0;
161 multiple_mute_change = false;
162 multiple_solo_change = false;
163 _i_am_the_modifier = 0;
168 setup_invert_buttons ();
170 mute_button = manage (new ArdourButton);
171 mute_button->set_name ("mute button");
172 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
174 solo_button = manage (new ArdourButton);
175 solo_button->set_name ("solo button");
176 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
177 solo_button->set_no_show_all (true);
179 rec_enable_button = manage (new ArdourButton);
180 rec_enable_button->set_name ("record enable button");
181 rec_enable_button->set_icon (ArdourIcon::RecButton);
182 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
184 if (UIConfiguration::instance().get_blink_rec_arm()) {
185 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
188 show_sends_button = manage (new ArdourButton);
189 show_sends_button->set_name ("send alert button");
190 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
192 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
193 monitor_input_button->set_name ("monitor button");
194 monitor_input_button->set_text (_("In"));
195 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
196 monitor_input_button->set_no_show_all (true);
198 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_disk_button->set_name ("monitor button");
200 monitor_disk_button->set_text (_("Disk"));
201 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
202 monitor_disk_button->set_no_show_all (true);
204 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
205 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
206 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
208 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
209 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
212 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
213 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
215 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
216 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
218 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
219 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
220 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
221 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
223 monitor_input_button->set_distinct_led_click (false);
224 monitor_disk_button->set_distinct_led_click (false);
226 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
227 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
229 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
230 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
232 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
238 route_connections.drop_connections ();
246 denormal_menu_item = 0;
250 RouteUI::self_delete ()
256 RouteUI::set_route (boost::shared_ptr<Route> rp)
262 if (set_color_from_route()) {
263 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
267 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
270 delete input_selector;
273 delete output_selector;
276 mute_button->set_controllable (_route->mute_control());
277 solo_button->set_controllable (_route->solo_control());
279 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
281 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
283 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
284 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
285 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
286 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
287 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
288 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
291 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
292 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
293 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
295 track_mode_changed();
299 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
300 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
302 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
304 if (_session->writable() && is_track()) {
305 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
307 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
308 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
310 rec_enable_button->show();
311 rec_enable_button->set_controllable (t->rec_enable_control());
313 if (is_midi_track()) {
314 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
315 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
320 /* this will work for busses and tracks, and needs to be called to
321 set up the name entry/name label display.
325 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
326 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
328 update_monitoring_display ();
331 mute_button->unset_flags (Gtk::CAN_FOCUS);
332 solo_button->unset_flags (Gtk::CAN_FOCUS);
336 if (_route->is_monitor() || _route->is_master()) {
337 solo_button->hide ();
344 setup_invert_buttons ();
345 set_invert_button_state ();
347 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
348 bus_send_display_changed (s);
350 update_mute_display ();
351 update_solo_display ();
353 if (!UIConfiguration::instance().get_blink_rec_arm()) {
354 blink_rec_display(true); // set initial rec-en button state
357 check_rec_enable_sensitivity ();
358 maybe_add_route_print_mgr ();
359 route_color_changed();
360 route_gui_changed (PropertyChange (Properties::selected));
364 RouteUI::polarity_changed ()
370 set_invert_button_state ();
374 RouteUI::mute_press (GdkEventButton* ev)
376 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
380 //if this is a binding action, let the ArdourButton handle it
381 if ( BindingProxy::is_bind_action(ev) )
384 multiple_mute_change = false;
386 if (Keyboard::is_context_menu_event (ev)) {
392 mute_menu->popup(0,ev->time);
398 if (Keyboard::is_button2_event (ev)) {
399 // button2-click is "momentary"
401 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
404 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
406 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
408 /* toggle mute on everything (but
409 * exclude the master and monitor)
411 * because we are going to erase
412 * elements of the list we need to work
416 boost::shared_ptr<RouteList> copy (new RouteList);
418 *copy = *_session->get_routes ();
420 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
421 if ((*i)->is_master() || (*i)->is_monitor()) {
429 _mute_release->routes = copy;
432 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
434 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
436 /* Primary-button1 inverts the implication of
437 the group being active. If the group is
438 active (for mute), then this modifier means
439 "do not apply to mute". If the group is
440 inactive (for mute), then this modifier
441 means "apply to route". This is all
442 accomplished by passing just the actual
443 route, along with the InverseGroup group
446 NOTE: Primary-button2 is MIDI learn.
449 boost::shared_ptr<RouteList> rl;
451 if (ev->button == 1) {
453 rl.reset (new RouteList);
454 rl->push_back (_route);
457 _mute_release->routes = rl;
460 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
465 /* plain click applies change to this route */
467 boost::shared_ptr<RouteList> rl (new RouteList);
468 rl->push_back (_route);
471 _mute_release->routes = rl;
474 _route->mute_control()->set_value (!_route->muted_by_self(), Controllable::UseGroup);
483 RouteUI::mute_release (GdkEventButton* /*ev*/)
486 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
487 delete _mute_release;
495 RouteUI::edit_output_configuration ()
497 if (output_selector == 0) {
499 boost::shared_ptr<Send> send;
500 boost::shared_ptr<IO> output;
502 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
503 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
504 output = send->output();
506 output = _route->output ();
509 output = _route->output ();
512 output_selector = new IOSelectorWindow (_session, output);
515 if (output_selector->is_visible()) {
516 output_selector->get_toplevel()->get_window()->raise();
518 output_selector->present ();
521 //output_selector->set_keep_above (true);
525 RouteUI::edit_input_configuration ()
527 if (input_selector == 0) {
528 input_selector = new IOSelectorWindow (_session, _route->input());
531 if (input_selector->is_visible()) {
532 input_selector->get_toplevel()->get_window()->raise();
534 input_selector->present ();
537 //input_selector->set_keep_above (true);
541 RouteUI::solo_press(GdkEventButton* ev)
543 /* ignore double/triple clicks */
545 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
549 //if this is a binding action, let the ArdourButton handle it
550 if ( BindingProxy::is_bind_action(ev) )
553 multiple_solo_change = false;
555 if (Keyboard::is_context_menu_event (ev)) {
557 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
558 ! (solo_safe_led && solo_safe_led->is_visible())) {
560 if (solo_menu == 0) {
564 solo_menu->popup (1, ev->time);
569 if (Keyboard::is_button2_event (ev)) {
571 // button2-click is "momentary"
572 _solo_release = new SoloMuteRelease (_route->self_soloed());
575 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
577 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
579 /* Primary-Tertiary-click applies change to all routes */
582 _solo_release->routes = _session->get_routes ();
585 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
587 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
589 // Primary-Secondary-click: exclusively solo this track
592 _solo_release->exclusive = true;
594 boost::shared_ptr<RouteList> routes = _session->get_routes();
596 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
597 if ((*i)->soloed ()) {
598 _solo_release->routes_on->push_back (*i);
600 _solo_release->routes_off->push_back (*i);
605 if (Config->get_solo_control_is_listen_control()) {
606 /* ??? we need a just_one_listen() method */
609 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
612 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
614 // shift-click: toggle solo isolated status
616 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
617 delete _solo_release;
620 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
622 /* Primary-button1: solo mix group.
623 NOTE: Primary-button2 is MIDI learn.
626 /* Primary-button1 applies change to the mix group even if it is not active
627 NOTE: Primary-button2 is MIDI learn.
630 boost::shared_ptr<RouteList> rl;
632 if (ev->button == 1) {
634 /* Primary-button1 inverts the implication of
635 the group being active. If the group is
636 active (for solo), then this modifier means
637 "do not apply to solo". If the group is
638 inactive (for mute), then this modifier
639 means "apply to route". This is all
640 accomplished by passing just the actual
641 route, along with the InverseGroup group
644 NOTE: Primary-button2 is MIDI learn.
647 rl.reset (new RouteList);
648 rl->push_back (_route);
651 _solo_release->routes = rl;
654 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
657 delete _solo_release;
662 /* click: solo this route */
664 boost::shared_ptr<RouteList> rl (new RouteList);
665 rl->push_back (route());
668 _solo_release->routes = rl;
671 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
680 RouteUI::solo_release (GdkEventButton* /*ev*/)
684 if (_solo_release->exclusive) {
687 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
690 delete _solo_release;
698 RouteUI::rec_enable_press(GdkEventButton* ev)
700 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
704 //if this is a binding action, let the ArdourButton handle it
705 if ( BindingProxy::is_bind_action(ev) )
708 if (!_session->engine().connected()) {
709 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
714 if (is_midi_track()) {
716 /* rec-enable button exits from step editing */
718 if (midi_track()->step_editing()) {
719 midi_track()->set_step_editing (false);
724 if (is_track() && rec_enable_button) {
726 if (Keyboard::is_button2_event (ev)) {
728 //rec arm does not have a momentary mode
731 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
733 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
735 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
737 /* Primary-button1 applies change to the route group (even if it is not active)
738 NOTE: Primary-button2 is MIDI learn.
741 if (ev->button == 1) {
743 boost::shared_ptr<RouteList> rl;
745 rl.reset (new RouteList);
746 rl->push_back (_route);
748 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
751 } else if (Keyboard::is_context_menu_event (ev)) {
753 /* do this on release */
757 boost::shared_ptr<Track> trk = track();
758 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
766 RouteUI::update_monitoring_display ()
772 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
778 MonitorState ms = t->monitoring_state();
780 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
781 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
783 if (ms & MonitoringInput) {
784 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
786 monitor_input_button->unset_active_state ();
790 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
791 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
793 if (ms & MonitoringDisk) {
794 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
796 monitor_disk_button->unset_active_state ();
802 RouteUI::monitor_input_press(GdkEventButton*)
808 RouteUI::monitor_input_release(GdkEventButton* ev)
810 return monitor_release (ev, MonitorInput);
814 RouteUI::monitor_disk_press (GdkEventButton*)
820 RouteUI::monitor_disk_release (GdkEventButton* ev)
822 return monitor_release (ev, MonitorDisk);
826 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
828 if (ev->button != 1) {
832 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
839 boost::shared_ptr<RouteList> rl;
841 /* XXX for now, monitoring choices are orthogonal. cue monitoring
842 will follow in 3.X but requires mixing the input and playback (disk)
843 signal together, which requires yet more buffers.
846 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
847 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
849 /* this line will change when the options are non-orthogonal */
850 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
854 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
855 rl = _session->get_routes ();
857 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
858 if (_route->route_group() && _route->route_group()->is_monitoring()) {
859 rl = _route->route_group()->route_list();
861 rl.reset (new RouteList);
862 rl->push_back (route());
865 rl.reset (new RouteList);
866 rl->push_back (route());
869 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
875 RouteUI::build_record_menu ()
878 record_menu = new Menu;
879 record_menu->set_name ("ArdourContextMenu");
880 using namespace Menu_Helpers;
881 MenuList& items = record_menu->items();
883 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
884 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
886 if (is_midi_track()) {
887 items.push_back (SeparatorElem());
888 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
889 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
893 if (step_edit_item) {
894 if (track()->rec_enable_control()->get_value()) {
895 step_edit_item->set_sensitive (false);
897 step_edit_item->set_active (midi_track()->step_editing());
900 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
901 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
906 RouteUI::toggle_step_edit ()
908 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
912 midi_track()->set_step_editing (step_edit_item->get_active());
916 RouteUI::toggle_rec_safe ()
918 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
924 /* This check is made inside the control too, but dong it here can't
928 if (_route->rec_enable_control()->get_value()) {
932 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
936 RouteUI::step_edit_changed (bool yn)
939 if (rec_enable_button) {
940 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
943 start_step_editing ();
945 if (step_edit_item) {
946 step_edit_item->set_active (true);
951 if (rec_enable_button) {
952 rec_enable_button->unset_active_state ();
955 stop_step_editing ();
957 if (step_edit_item) {
958 step_edit_item->set_active (false);
964 RouteUI::rec_enable_release (GdkEventButton* ev)
966 if (Keyboard::is_context_menu_event (ev)) {
967 build_record_menu ();
969 record_menu->popup (1, ev->time);
978 RouteUI::build_sends_menu ()
980 using namespace Menu_Helpers;
982 sends_menu = new Menu;
983 sends_menu->set_name ("ArdourContextMenu");
984 MenuList& items = sends_menu->items();
987 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
991 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
995 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
999 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1003 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1007 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1010 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1014 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1017 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1018 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1019 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1024 RouteUI::create_sends (Placement p, bool include_buses)
1026 _session->globally_add_internal_sends (_route, p, include_buses);
1030 RouteUI::create_selected_sends (Placement p, bool include_buses)
1032 boost::shared_ptr<RouteList> rlist (new RouteList);
1033 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1035 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1036 RouteTimeAxisView* rtv;
1038 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1039 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1040 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1041 rlist->push_back (rui->route());
1047 _session->add_internal_sends (_route, p, rlist);
1051 RouteUI::set_sends_gain_from_track ()
1053 _session->globally_set_send_gains_from_track (_route);
1057 RouteUI::set_sends_gain_to_zero ()
1059 _session->globally_set_send_gains_to_zero (_route);
1063 RouteUI::set_sends_gain_to_unity ()
1065 _session->globally_set_send_gains_to_unity (_route);
1069 RouteUI::show_sends_press(GdkEventButton* ev)
1071 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1075 if (!is_track() && show_sends_button) {
1077 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1079 // do nothing on midi sigc::bind event
1082 } else if (Keyboard::is_context_menu_event (ev)) {
1084 if (sends_menu == 0) {
1085 build_sends_menu ();
1088 sends_menu->popup (0, ev->time);
1092 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1095 set_showing_sends_to (boost::shared_ptr<Route> ());
1097 set_showing_sends_to (_route);
1106 RouteUI::show_sends_release (GdkEventButton*)
1112 RouteUI::send_blink (bool onoff)
1114 if (!show_sends_button) {
1119 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1121 show_sends_button->unset_active_state ();
1125 Gtkmm2ext::ActiveState
1126 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1128 boost::shared_ptr<SoloControl> sc = s->solo_control();
1131 return Gtkmm2ext::Off;
1134 if (!sc->can_solo()) {
1135 return Gtkmm2ext::Off;
1139 if (sc->self_soloed()) {
1140 return Gtkmm2ext::ExplicitActive;
1141 } else if (sc->soloed_by_others()) {
1142 return Gtkmm2ext::ImplicitActive;
1144 return Gtkmm2ext::Off;
1148 Gtkmm2ext::ActiveState
1149 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1151 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1154 return Gtkmm2ext::Off;
1157 if (s->is_master() || s->is_monitor()) {
1158 return Gtkmm2ext::Off;
1161 if (sc->solo_isolated()) {
1162 return Gtkmm2ext::ExplicitActive;
1164 return Gtkmm2ext::Off;
1168 Gtkmm2ext::ActiveState
1169 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1171 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1174 return Gtkmm2ext::Off;
1177 if (s->is_master() || s->is_monitor()) {
1178 return Gtkmm2ext::Off;
1181 if (sc->solo_safe()) {
1182 return Gtkmm2ext::ExplicitActive;
1184 return Gtkmm2ext::Off;
1189 RouteUI::update_solo_display ()
1191 bool yn = _route->solo_safe_control()->solo_safe ();
1193 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1194 solo_safe_check->set_active (yn);
1197 yn = _route->solo_isolate_control()->solo_isolated ();
1199 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1200 solo_isolated_check->set_active (yn);
1203 set_button_names ();
1205 if (solo_isolated_led) {
1206 if (_route->solo_isolate_control()->solo_isolated()) {
1207 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1209 solo_isolated_led->unset_active_state ();
1213 if (solo_safe_led) {
1214 if (_route->solo_safe_control()->solo_safe()) {
1215 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1217 solo_safe_led->unset_active_state ();
1221 solo_button->set_active_state (solo_active_state (_route));
1223 /* some changes to solo status can affect mute display, so catch up
1226 update_mute_display ();
1230 RouteUI::solo_changed_so_update_mute ()
1232 update_mute_display ();
1236 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1238 boost::shared_ptr<MuteControl> mc = s->mute_control();
1240 if (s->is_monitor()) {
1241 return Gtkmm2ext::Off;
1245 return Gtkmm2ext::Off;
1248 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1250 if (mc->muted_by_self ()) {
1252 return Gtkmm2ext::ExplicitActive;
1253 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1254 /* this will reflect both solo mutes AND master mutes */
1255 return Gtkmm2ext::ImplicitActive;
1257 /* no mute at all */
1258 return Gtkmm2ext::Off;
1263 if (mc->muted_by_self()) {
1265 return Gtkmm2ext::ExplicitActive;
1266 } else if (mc->muted_by_masters ()) {
1267 /* this shows only master mutes, not mute-by-others-soloing */
1268 return Gtkmm2ext::ImplicitActive;
1270 /* no mute at all */
1271 return Gtkmm2ext::Off;
1275 return ActiveState(0);
1279 RouteUI::update_mute_display ()
1285 mute_button->set_active_state (mute_active_state (_session, _route));
1290 RouteUI::route_rec_enable_changed ()
1292 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1296 RouteUI::session_rec_enable_changed ()
1298 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1302 RouteUI::blink_rec_display (bool blinkOn)
1304 if (!rec_enable_button || !_route) {
1308 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1316 if (track()->rec_enable_control()->get_value()) {
1317 switch (_session->record_status ()) {
1318 case Session::Recording:
1319 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1322 case Session::Disabled:
1323 case Session::Enabled:
1324 if (UIConfiguration::instance().get_blink_rec_arm()) {
1325 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1327 rec_enable_button->set_active_state ( ImplicitActive );
1332 if (step_edit_item) {
1333 step_edit_item->set_sensitive (false);
1337 rec_enable_button->unset_active_state ();
1339 if (step_edit_item) {
1340 step_edit_item->set_sensitive (true);
1344 check_rec_enable_sensitivity ();
1348 RouteUI::build_solo_menu (void)
1350 using namespace Menu_Helpers;
1352 solo_menu = new Menu;
1353 solo_menu->set_name ("ArdourContextMenu");
1354 MenuList& items = solo_menu->items();
1355 Gtk::CheckMenuItem* check;
1357 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1358 check->set_active (_route->solo_isolate_control()->solo_isolated());
1359 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1360 items.push_back (CheckMenuElem(*check));
1361 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1364 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1365 check->set_active (_route->solo_safe_control()->solo_safe());
1366 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1367 items.push_back (CheckMenuElem(*check));
1368 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1371 //items.push_back (SeparatorElem());
1372 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1377 RouteUI::build_mute_menu(void)
1379 using namespace Menu_Helpers;
1381 mute_menu = new Menu;
1382 mute_menu->set_name ("ArdourContextMenu");
1384 MenuList& items = mute_menu->items();
1386 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1387 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1388 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1389 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1390 pre_fader_mute_check->show_all();
1392 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1393 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1394 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1395 items.push_back (CheckMenuElem(*post_fader_mute_check));
1396 post_fader_mute_check->show_all();
1398 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1399 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1400 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1401 items.push_back (CheckMenuElem(*listen_mute_check));
1402 listen_mute_check->show_all();
1404 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1405 init_mute_menu(MuteMaster::Main, main_mute_check);
1406 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1407 items.push_back (CheckMenuElem(*main_mute_check));
1408 main_mute_check->show_all();
1410 //items.push_back (SeparatorElem());
1411 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1413 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1417 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1419 check->set_active (_route->mute_control()->mute_points() & mp);
1423 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1425 if (check->get_active()) {
1426 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1428 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1433 RouteUI::muting_change ()
1435 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1438 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1440 yn = (current & MuteMaster::PreFader);
1442 if (pre_fader_mute_check->get_active() != yn) {
1443 pre_fader_mute_check->set_active (yn);
1446 yn = (current & MuteMaster::PostFader);
1448 if (post_fader_mute_check->get_active() != yn) {
1449 post_fader_mute_check->set_active (yn);
1452 yn = (current & MuteMaster::Listen);
1454 if (listen_mute_check->get_active() != yn) {
1455 listen_mute_check->set_active (yn);
1458 yn = (current & MuteMaster::Main);
1460 if (main_mute_check->get_active() != yn) {
1461 main_mute_check->set_active (yn);
1466 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1468 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1472 bool view = solo_isolated_led->active_state();
1473 bool model = _route->solo_isolate_control()->solo_isolated();
1475 /* called BEFORE the view has changed */
1477 if (ev->button == 1) {
1478 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1481 /* disable isolate for all routes */
1482 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1484 /* enable isolate for all routes */
1485 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1490 if (model == view) {
1492 /* flip just this route */
1494 boost::shared_ptr<RouteList> rl (new RouteList);
1495 rl->push_back (_route);
1496 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1505 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1507 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1511 bool view = solo_safe_led->active_state();
1512 bool model = _route->solo_safe_control()->solo_safe();
1514 if (ev->button == 1) {
1515 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1516 boost::shared_ptr<RouteList> rl (_session->get_routes());
1518 /* disable solo safe for all routes */
1519 DisplaySuspender ds;
1520 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1521 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1524 /* enable solo safe for all routes */
1525 DisplaySuspender ds;
1526 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1527 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1532 if (model == view) {
1533 /* flip just this route */
1534 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1543 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1545 bool view = check->get_active();
1546 bool model = _route->solo_isolate_control()->solo_isolated();
1548 /* called AFTER the view has changed */
1550 if (model != view) {
1551 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1556 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1558 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1561 /** Ask the user to choose a colour, and then apply that color to my route
1564 RouteUI::choose_color ()
1567 Gdk::Color c (gdk_color_from_rgba (_route->presentation_info().color()));
1568 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1571 set_color (gdk_color_to_rgba (color));
1575 /** Set the route's own color. This may not be used for display if
1576 * the route is in a group which shares its color with its routes.
1579 RouteUI::set_color (uint32_t c)
1581 _route->presentation_info().set_color (c);
1584 /** @return GUI state ID for things that are common to the route in all its representations */
1586 RouteUI::route_state_id () const
1588 return string_compose (X_("route %1"), _route->id().to_s());
1592 RouteUI::set_color_from_route ()
1594 if (_route->presentation_info().color_set()) {
1595 return 0; /* nothing to do */
1598 return 1; /* pick a color */
1601 /** @return true if this name should be used for the route, otherwise false */
1603 RouteUI::verify_new_route_name (const std::string& name)
1605 if (name.find (':') == string::npos) {
1609 MessageDialog colon_msg (
1610 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1611 false, MESSAGE_QUESTION, BUTTONS_NONE
1614 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1615 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1617 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1621 RouteUI::route_rename ()
1623 ArdourPrompter name_prompter (true);
1628 name_prompter.set_title (_("Rename Track"));
1630 name_prompter.set_title (_("Rename Bus"));
1632 name_prompter.set_prompt (_("New name:"));
1633 name_prompter.set_initial_text (_route->name());
1634 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1635 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1636 name_prompter.show_all ();
1639 switch (name_prompter.run ()) {
1640 case Gtk::RESPONSE_ACCEPT:
1641 name_prompter.get_result (result);
1642 name_prompter.hide ();
1643 if (result.length()) {
1644 if (verify_new_route_name (result)) {
1645 _route->set_name (result);
1648 /* back to name prompter */
1652 /* nothing entered, just get out of here */
1667 RouteUI::toggle_comment_editor ()
1669 // if (ignore_toggle) {
1673 if (comment_window && comment_window->is_visible ()) {
1674 comment_window->hide ();
1676 open_comment_editor ();
1682 RouteUI::open_comment_editor ()
1684 if (comment_window == 0) {
1685 setup_comment_editor ();
1689 title = _route->name();
1690 title += _(": comment editor");
1692 comment_window->set_title (title);
1693 comment_window->present();
1697 RouteUI::setup_comment_editor ()
1699 comment_window = new ArdourWindow (""); // title will be reset to show route
1700 comment_window->set_skip_taskbar_hint (true);
1701 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1702 comment_window->set_default_size (400, 200);
1704 comment_area = manage (new TextView());
1705 comment_area->set_name ("MixerTrackCommentArea");
1706 comment_area->set_wrap_mode (WRAP_WORD);
1707 comment_area->set_editable (true);
1708 comment_area->get_buffer()->set_text (_route->comment());
1709 comment_area->show ();
1711 comment_window->add (*comment_area);
1715 RouteUI::comment_changed ()
1717 ignore_comment_edit = true;
1719 comment_area->get_buffer()->set_text (_route->comment());
1721 ignore_comment_edit = false;
1725 RouteUI::comment_editor_done_editing ()
1727 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1729 string const str = comment_area->get_buffer()->get_text();
1730 if (str == _route->comment ()) {
1734 _route->set_comment (str, this);
1738 RouteUI::set_route_active (bool a, bool apply_to_selection)
1740 if (apply_to_selection) {
1741 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1743 _route->set_active (a, this);
1748 RouteUI::duplicate_selected_routes ()
1750 ARDOUR_UI::instance()->start_duplicate_routes();
1754 RouteUI::toggle_denormal_protection ()
1756 if (denormal_menu_item) {
1760 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1762 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1763 _route->set_denormal_protection (x);
1769 RouteUI::denormal_protection_changed ()
1771 if (denormal_menu_item) {
1772 denormal_menu_item->set_active (_route->denormal_protection());
1777 RouteUI::disconnect_input ()
1779 _route->input()->disconnect (this);
1783 RouteUI::disconnect_output ()
1785 _route->output()->disconnect (this);
1789 RouteUI::is_track () const
1791 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1794 boost::shared_ptr<Track>
1795 RouteUI::track() const
1797 return boost::dynamic_pointer_cast<Track>(_route);
1801 RouteUI::is_audio_track () const
1803 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1806 boost::shared_ptr<AudioTrack>
1807 RouteUI::audio_track() const
1809 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1813 RouteUI::is_midi_track () const
1815 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1818 boost::shared_ptr<MidiTrack>
1819 RouteUI::midi_track() const
1821 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1825 RouteUI::has_audio_outputs () const
1827 return (_route->n_outputs().n_audio() > 0);
1831 RouteUI::map_frozen ()
1833 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1835 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1838 check_rec_enable_sensitivity ();
1843 RouteUI::adjust_latency ()
1845 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1849 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1852 std::string safe_name;
1855 prompter.get_result (name, true);
1857 safe_name = legalize_for_path (name);
1858 safe_name += template_suffix;
1860 path = Glib::build_filename (dir, safe_name);
1862 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1863 bool overwrite = overwrite_file_dialog (prompter,
1864 _("Confirm Template Overwrite"),
1865 _("A template already exists with that name. Do you want to overwrite it?"));
1872 _route->save_as_template (path, name);
1878 RouteUI::save_as_template ()
1882 dir = ARDOUR::user_route_template_directory ();
1884 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1885 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1889 ArdourPrompter prompter (true); // modal
1891 prompter.set_title (_("Save As Template"));
1892 prompter.set_prompt (_("Template name:"));
1893 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1895 bool finished = false;
1897 switch (prompter.run()) {
1898 case RESPONSE_ACCEPT:
1899 finished = process_save_template_prompter (prompter, dir);
1909 RouteUI::check_rec_enable_sensitivity ()
1911 if (!rec_enable_button) {
1912 assert (0); // This should not happen
1915 if (!_session->writable()) {
1916 rec_enable_button->set_sensitive (false);
1920 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1921 rec_enable_button->set_sensitive (false);
1922 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1923 rec_enable_button->set_sensitive (false);
1925 rec_enable_button->set_sensitive (true);
1927 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1928 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1930 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1932 update_monitoring_display ();
1936 RouteUI::parameter_changed (string const & p)
1938 /* this handles RC and per-session parameter changes */
1940 if (p == "disable-disarm-during-roll") {
1941 check_rec_enable_sensitivity ();
1942 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1943 set_button_names ();
1944 } else if (p == "session-monitoring") {
1945 update_monitoring_display ();
1946 } else if (p == "auto-input") {
1947 update_monitoring_display ();
1948 } else if (p == "blink-rec-arm") {
1949 if (UIConfiguration::instance().get_blink_rec_arm()) {
1950 rec_blink_connection.disconnect ();
1951 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1953 rec_blink_connection.disconnect ();
1954 RouteUI::blink_rec_display(false);
1960 RouteUI::step_gain_up ()
1962 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1966 RouteUI::page_gain_up ()
1968 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1972 RouteUI::step_gain_down ()
1974 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1978 RouteUI::page_gain_down ()
1980 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1984 RouteUI::setup_invert_buttons ()
1986 /* remove old invert buttons */
1987 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1988 _invert_button_box.remove (**i);
1991 _invert_buttons.clear ();
1993 if (!_route || !_route->input()) {
1997 uint32_t const N = _route->input()->n_ports().n_audio ();
1999 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2001 for (uint32_t i = 0; i < to_add; ++i) {
2002 ArdourButton* b = manage (new ArdourButton);
2003 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2004 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2006 b->set_name (X_("invert button"));
2009 b->set_text (string_compose (X_("Ø (%1)"), N));
2011 b->set_text (X_("Ø"));
2014 b->set_text (string_compose (X_("Ø%1"), i + 1));
2017 if (N <= _max_invert_buttons) {
2018 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));
2020 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2023 _invert_buttons.push_back (b);
2024 _invert_button_box.pack_start (*b);
2027 _invert_button_box.set_spacing (1);
2028 _invert_button_box.show_all ();
2032 RouteUI::set_invert_button_state ()
2034 uint32_t const N = _route->input()->n_ports().n_audio();
2035 if (N > _max_invert_buttons) {
2037 /* One button for many channels; explicit active if all channels are inverted,
2038 implicit active if some are, off if none are.
2041 ArdourButton* b = _invert_buttons.front ();
2043 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2044 b->set_active_state (Gtkmm2ext::ExplicitActive);
2045 } else if (_route->phase_control()->any()) {
2046 b->set_active_state (Gtkmm2ext::ImplicitActive);
2048 b->set_active_state (Gtkmm2ext::Off);
2053 /* One button per channel; just set active */
2056 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2057 (*i)->set_active (_route->phase_control()->inverted (j));
2064 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2066 if (ev->button == 1 && i < _invert_buttons.size()) {
2067 uint32_t const N = _route->input()->n_ports().n_audio ();
2068 if (N <= _max_invert_buttons) {
2069 /* left-click inverts phase so long as we have a button per channel */
2070 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2079 RouteUI::invert_press (GdkEventButton* ev)
2081 using namespace Menu_Helpers;
2083 uint32_t const N = _route->input()->n_ports().n_audio();
2084 if (N <= _max_invert_buttons && ev->button != 3) {
2085 /* If we have an invert button per channel, we only pop
2086 up a menu on right-click; left click is handled
2092 delete _invert_menu;
2093 _invert_menu = new Menu;
2094 _invert_menu->set_name ("ArdourContextMenu");
2095 MenuList& items = _invert_menu->items ();
2097 for (uint32_t i = 0; i < N; ++i) {
2098 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2099 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2100 ++_i_am_the_modifier;
2101 e->set_active (_route->phase_control()->inverted (i));
2102 --_i_am_the_modifier;
2105 _invert_menu->popup (0, ev->time);
2111 RouteUI::invert_menu_toggled (uint32_t c)
2113 if (_i_am_the_modifier) {
2118 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2122 RouteUI::set_invert_sensitive (bool yn)
2124 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2125 (*b)->set_sensitive (yn);
2130 RouteUI::request_redraw ()
2133 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2137 /** The Route's gui_changed signal has been emitted */
2139 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2141 if (what_changed.contains (Properties::color)) {
2142 if (set_color_from_route () == 0) {
2143 route_color_changed ();
2149 RouteUI::track_mode_changed (void)
2152 switch (track()->mode()) {
2153 case ARDOUR::NonLayered:
2154 case ARDOUR::Normal:
2155 rec_enable_button->set_icon (ArdourIcon::RecButton);
2157 case ARDOUR::Destructive:
2158 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2161 rec_enable_button->queue_draw();
2164 /** @return the color that this route should use; it maybe its own,
2165 or it maybe that of its route group.
2169 RouteUI::route_color () const
2172 RouteGroup* g = _route->route_group ();
2175 if (g && g->is_color()) {
2176 set_color_from_rgba (c, GroupTabs::group_color (g));
2179 /* deal with older 4.x color, which was stored in the GUI object state */
2181 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2185 /* old v4.x or earlier session. Use this information */
2187 int red, green, blue;
2190 stringstream ss (p);
2192 /* old color format version was:
2194 16bit value for red:16 bit value for green:16 bit value for blue
2209 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
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 DisplaySuspender ds;
2336 boost::shared_ptr<ARDOUR::Route> route = _route;
2337 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2340 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2341 if (route->n_outputs ().n_audio () != n_outputs) {
2342 MessageDialog msg (string_compose (
2343 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2344 n_outputs, route->n_outputs ().n_audio ()));
2349 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2351 /* count busses and channels/bus */
2352 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2353 std::map<std::string, uint32_t> busnames;
2354 for (uint32_t p = 0; p < n_outputs; ++p) {
2355 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2356 std::string bn = BUSNAME;
2360 if (busnames.size () < 2) {
2361 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2366 uint32_t outputs = 2;
2367 if (_session->master_out ()) {
2368 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2371 route->output ()->disconnect (this);
2372 route->panner_shell ()->set_bypassed (true);
2375 for (uint32_t p = 0; p < n_outputs; ++p) {
2376 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2377 std::string bn = BUSNAME;
2378 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2381 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2385 list<boost::shared_ptr<AudioTrack> > tl =
2386 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2390 boost::shared_ptr<ControlList> cl (new ControlList);
2391 cl->push_back (r->monitoring_control ());
2392 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2394 r->input ()->disconnect (this);
2396 to_group.push_back (r);
2397 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2402 RouteGroup* rg = NULL;
2403 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2404 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2405 if ((*i)->name () == pi->name ()) {
2411 rg = new RouteGroup (*_session, pi->name ());
2412 _session->add_route_group (rg);
2413 rg->set_gain (false);
2416 GroupTabs::set_group_color (rg, route->presentation_info().color());
2417 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2424 RouteUI::mark_hidden (bool yn)
2426 if (yn != _route->presentation_info().hidden()) {
2427 _route->presentation_info().set_hidden (yn);
2428 return true; // things changed
2433 boost::shared_ptr<Stripable>
2434 RouteUI::stripable () const