2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <boost/algorithm/string.hpp>
23 #include <gtkmm/stock.h>
25 #include "pbd/memento_command.h"
26 #include "pbd/stacktrace.h"
27 #include "pbd/controllable.h"
28 #include "pbd/enumwriter.h"
30 #include "ardour/dB.h"
31 #include "ardour/route_group.h"
32 #include "ardour/solo_isolate_control.h"
33 #include "ardour/vca.h"
34 #include "ardour/vca_manager.h"
35 #include "ardour/audio_track.h"
36 #include "ardour/audio_port.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/filename_extensions.h"
39 #include "ardour/midi_track.h"
40 #include "ardour/monitor_control.h"
41 #include "ardour/internal_send.h"
42 #include "ardour/panner_shell.h"
43 #include "ardour/profile.h"
44 #include "ardour/phase_control.h"
45 #include "ardour/send.h"
46 #include "ardour/route.h"
47 #include "ardour/session.h"
48 #include "ardour/template_utils.h"
50 #include "gtkmm2ext/gtk_ui.h"
51 #include "gtkmm2ext/doi.h"
52 #include "gtkmm2ext/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
55 #include "widgets/ardour_button.h"
56 #include "widgets/binding_proxy.h"
57 #include "widgets/prompter.h"
59 #include "ardour_dialog.h"
60 #include "ardour_ui.h"
61 #include "automation_time_axis.h"
63 #include "group_tabs.h"
64 #include "gui_object.h"
65 #include "gui_thread.h"
67 #include "latency_gui.h"
68 #include "mixer_strip.h"
69 #include "plugin_pin_dialog.h"
70 #include "rgb_macros.h"
71 #include "route_time_axis.h"
74 #include "ui_config.h"
80 using namespace Gtkmm2ext;
81 using namespace ARDOUR;
82 using namespace ARDOUR_UI_UTILS;
83 using namespace ArdourWidgets;
87 uint32_t RouteUI::_max_invert_buttons = 3;
88 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
89 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
90 std::string RouteUI::program_port_prefix;
92 RouteUI::RouteUI (ARDOUR::Session* sess)
93 : monitor_input_button (0)
94 , monitor_disk_button (0)
102 , output_selector (0)
105 if (program_port_prefix.empty()) {
106 // compare to gtk2_ardour/port_group.cc
107 string lpn (PROGRAM_NAME);
108 boost::to_lower (lpn);
109 program_port_prefix = lpn + ":"; // e.g. "ardour:"
120 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
123 _route.reset (); /* drop reference to route, so that it can be cleaned up */
124 route_connections.drop_connections ();
130 delete comment_window;
131 delete input_selector;
132 delete output_selector;
133 delete monitor_input_button;
134 delete monitor_disk_button;
137 send_blink_connection.disconnect ();
138 rec_blink_connection.disconnect ();
144 self_destruct = true;
150 pre_fader_mute_check = 0;
151 post_fader_mute_check = 0;
152 listen_mute_check = 0;
155 solo_isolated_check = 0;
156 solo_isolated_led = 0;
160 denormal_menu_item = 0;
163 multiple_mute_change = false;
164 multiple_solo_change = false;
165 _i_am_the_modifier = 0;
170 setup_invert_buttons ();
172 mute_button = manage (new ArdourButton);
173 mute_button->set_name ("mute button");
174 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
176 solo_button = manage (new ArdourButton);
177 solo_button->set_name ("solo button");
178 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
179 solo_button->set_no_show_all (true);
181 rec_enable_button = manage (new ArdourButton);
182 rec_enable_button->set_name ("record enable button");
183 rec_enable_button->set_icon (ArdourIcon::RecButton);
184 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
186 if (UIConfiguration::instance().get_blink_rec_arm()) {
187 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
190 show_sends_button = manage (new ArdourButton);
191 show_sends_button->set_name ("send alert button");
192 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
194 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
195 monitor_input_button->set_name ("monitor button");
196 monitor_input_button->set_text (_("In"));
197 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
198 monitor_input_button->set_no_show_all (true);
200 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
201 monitor_disk_button->set_name ("monitor button");
202 monitor_disk_button->set_text (_("Disk"));
203 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
204 monitor_disk_button->set_no_show_all (true);
206 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
207 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
208 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
210 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
211 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
212 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
214 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
215 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
217 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
218 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
220 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
221 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
222 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
223 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
225 monitor_input_button->set_distinct_led_click (false);
226 monitor_disk_button->set_distinct_led_click (false);
228 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
229 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
231 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
232 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
234 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
240 route_connections.drop_connections ();
248 _color_picker.reset ();
250 denormal_menu_item = 0;
254 RouteUI::self_delete ()
260 RouteUI::set_route (boost::shared_ptr<Route> rp)
266 if ( !_route->presentation_info().color_set() ) {
267 /* deal with older 4.x color, which was stored in the GUI object state */
269 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
273 /* old v4.x or earlier session. Use this information */
275 int red, green, blue;
280 /* old color format version was:
282 16bit value for red:16 bit value for green:16 bit value for blue
297 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
301 if (set_color_from_route()) {
302 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
306 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
309 delete input_selector;
312 delete output_selector;
315 mute_button->set_controllable (_route->mute_control());
316 solo_button->set_controllable (_route->solo_control());
318 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
320 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
322 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
323 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
324 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
325 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
326 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
327 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
330 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
331 track_mode_changed();
335 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
336 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
338 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
340 if (_session->writable() && is_track()) {
341 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
343 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
344 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
346 rec_enable_button->show();
347 rec_enable_button->set_controllable (t->rec_enable_control());
349 if (is_midi_track()) {
350 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
351 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
356 /* this will work for busses and tracks, and needs to be called to
357 set up the name entry/name label display.
361 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
362 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
364 update_monitoring_display ();
367 mute_button->unset_flags (Gtk::CAN_FOCUS);
368 solo_button->unset_flags (Gtk::CAN_FOCUS);
372 if (_route->is_monitor() || _route->is_master()) {
373 solo_button->hide ();
380 setup_invert_buttons ();
381 set_invert_button_state ();
383 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
384 bus_send_display_changed (s);
386 update_mute_display ();
387 update_solo_display ();
389 if (!UIConfiguration::instance().get_blink_rec_arm()) {
390 blink_rec_display(true); // set initial rec-en button state
393 check_rec_enable_sensitivity ();
394 maybe_add_route_print_mgr ();
395 route_color_changed();
396 route_gui_changed (PropertyChange (Properties::selected));
400 RouteUI::polarity_changed ()
406 set_invert_button_state ();
410 RouteUI::mute_press (GdkEventButton* ev)
412 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
416 //if this is a binding action, let the ArdourButton handle it
417 if (BindingProxy::is_bind_action(ev) )
420 multiple_mute_change = false;
422 if (Keyboard::is_context_menu_event (ev)) {
428 mute_menu->popup(0,ev->time);
434 if (Keyboard::is_button2_event (ev)) {
435 // button2-click is "momentary"
437 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
440 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
442 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
444 /* toggle mute on everything (but
445 * exclude the master and monitor)
447 * because we are going to erase
448 * elements of the list we need to work
452 boost::shared_ptr<RouteList> copy (new RouteList);
454 *copy = *_session->get_routes ();
456 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
457 if ((*i)->is_master() || (*i)->is_monitor()) {
465 _mute_release->routes = copy;
468 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
470 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
472 /* Primary-button1 inverts the implication of
473 the group being active. If the group is
474 active (for mute), then this modifier means
475 "do not apply to mute". If the group is
476 inactive (for mute), then this modifier
477 means "apply to route". This is all
478 accomplished by passing just the actual
479 route, along with the InverseGroup group
482 NOTE: Primary-button2 is MIDI learn.
485 boost::shared_ptr<RouteList> rl;
487 if (ev->button == 1) {
489 rl.reset (new RouteList);
490 rl->push_back (_route);
493 _mute_release->routes = rl;
496 boost::shared_ptr<MuteControl> mc = _route->mute_control();
497 mc->start_touch (_session->audible_frame ());
498 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
503 /* plain click applies change to this route */
505 boost::shared_ptr<RouteList> rl (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_frame ());
514 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
523 RouteUI::mute_release (GdkEventButton* /*ev*/)
526 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
527 delete _mute_release;
531 _route->mute_control()->stop_touch (_session->audible_frame ());
537 RouteUI::edit_output_configuration ()
539 if (output_selector == 0) {
541 boost::shared_ptr<Send> send;
542 boost::shared_ptr<IO> output;
544 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
545 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
546 output = send->output();
548 output = _route->output ();
551 output = _route->output ();
554 output_selector = new IOSelectorWindow (_session, output);
557 if (output_selector->is_visible()) {
558 output_selector->get_toplevel()->get_window()->raise();
560 output_selector->present ();
563 //output_selector->set_keep_above (true);
567 RouteUI::edit_input_configuration ()
569 if (input_selector == 0) {
570 input_selector = new IOSelectorWindow (_session, _route->input());
573 if (input_selector->is_visible()) {
574 input_selector->get_toplevel()->get_window()->raise();
576 input_selector->present ();
579 //input_selector->set_keep_above (true);
583 RouteUI::solo_press(GdkEventButton* ev)
585 /* ignore double/triple clicks */
587 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
591 //if this is a binding action, let the ArdourButton handle it
592 if (BindingProxy::is_bind_action(ev) )
595 multiple_solo_change = false;
597 if (Keyboard::is_context_menu_event (ev)) {
599 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
600 ! (solo_safe_led && solo_safe_led->is_visible())) {
602 if (solo_menu == 0) {
606 solo_menu->popup (1, ev->time);
611 if (Keyboard::is_button2_event (ev)) {
613 // button2-click is "momentary"
614 _solo_release = new SoloMuteRelease (_route->self_soloed());
617 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
619 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
621 /* Primary-Tertiary-click applies change to all routes */
624 _solo_release->routes = _session->get_routes ();
627 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
629 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
631 /* Primary-Secondary-click: exclusively solo this track */
634 _solo_release->exclusive = true;
636 _solo_release->routes_on.reset (new RouteList);
637 _solo_release->routes_off.reset (new RouteList);
639 boost::shared_ptr<RouteList> routes = _session->get_routes();
640 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
642 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
646 if ((*i)->soloed ()) {
647 _solo_release->routes_on->push_back (*i);
649 _solo_release->routes_off->push_back (*i);
654 boost::shared_ptr<RouteList> rl (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 ()) {
666 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
668 if (Config->get_solo_control_is_listen_control()) {
669 /* ??? we need a just_one_listen() method */
672 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
675 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
677 // shift-click: toggle solo isolated status
679 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
680 delete _solo_release;
683 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
685 /* Primary-button1: solo mix group.
686 NOTE: Primary-button2 is MIDI learn.
689 /* Primary-button1 applies change to the mix group even if it is not active
690 NOTE: Primary-button2 is MIDI learn.
693 boost::shared_ptr<RouteList> rl;
695 if (ev->button == 1) {
697 /* Primary-button1 inverts the implication of
698 the group being active. If the group is
699 active (for solo), then this modifier means
700 "do not apply to solo". If the group is
701 inactive (for mute), then this modifier
702 means "apply to route". This is all
703 accomplished by passing just the actual
704 route, along with the InverseGroup group
707 NOTE: Primary-button2 is MIDI learn.
710 rl.reset (new RouteList);
711 rl->push_back (_route);
714 _solo_release->routes = rl;
717 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
720 delete _solo_release;
725 /* click: solo this route */
727 boost::shared_ptr<RouteList> rl (new RouteList);
728 rl->push_back (route());
731 _solo_release->routes = rl;
734 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
743 RouteUI::solo_release (GdkEventButton* /*ev*/)
746 if (_solo_release->exclusive) {
747 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
748 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
750 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
753 delete _solo_release;
761 RouteUI::rec_enable_press(GdkEventButton* ev)
763 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
767 //if this is a binding action, let the ArdourButton handle it
768 if (BindingProxy::is_bind_action(ev) )
771 if (!_session->engine().connected()) {
772 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
777 if (is_midi_track()) {
779 /* rec-enable button exits from step editing */
781 if (midi_track()->step_editing()) {
782 midi_track()->set_step_editing (false);
787 if (is_track() && rec_enable_button) {
789 if (Keyboard::is_button2_event (ev)) {
791 //rec arm does not have a momentary mode
794 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
796 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
798 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
800 /* Primary-button1 applies change to the route group (even if it is not active)
801 NOTE: Primary-button2 is MIDI learn.
804 if (ev->button == 1) {
806 boost::shared_ptr<RouteList> rl;
808 rl.reset (new RouteList);
809 rl->push_back (_route);
811 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
814 } else if (Keyboard::is_context_menu_event (ev)) {
816 /* do this on release */
820 boost::shared_ptr<Track> trk = track();
821 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
829 RouteUI::update_monitoring_display ()
835 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
841 MonitorState ms = t->monitoring_state();
843 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
844 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
846 if (ms & MonitoringInput) {
847 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
849 monitor_input_button->unset_active_state ();
853 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
854 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
856 if (ms & MonitoringDisk) {
857 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
859 monitor_disk_button->unset_active_state ();
865 RouteUI::monitor_input_press(GdkEventButton*)
871 RouteUI::monitor_input_release(GdkEventButton* ev)
873 return monitor_release (ev, MonitorInput);
877 RouteUI::monitor_disk_press (GdkEventButton*)
883 RouteUI::monitor_disk_release (GdkEventButton* ev)
885 return monitor_release (ev, MonitorDisk);
889 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
891 if (ev->button != 1) {
895 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
902 boost::shared_ptr<RouteList> rl;
904 /* XXX for now, monitoring choices are orthogonal. cue monitoring
905 will follow in 3.X but requires mixing the input and playback (disk)
906 signal together, which requires yet more buffers.
909 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
910 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
912 /* this line will change when the options are non-orthogonal */
913 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
917 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
918 /* Primary-Tertiary-click applies change to all routes */
919 rl = _session->get_routes ();
920 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
921 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
922 /* Primary-click overrides group */
923 rl.reset (new RouteList);
924 rl->push_back (route());
925 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
927 rl.reset (new RouteList);
928 rl->push_back (route());
929 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
936 RouteUI::build_record_menu ()
939 record_menu = new Menu;
940 record_menu->set_name ("ArdourContextMenu");
941 using namespace Menu_Helpers;
942 MenuList& items = record_menu->items();
944 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
945 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
947 if (is_midi_track()) {
948 items.push_back (SeparatorElem());
949 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
950 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
954 if (step_edit_item) {
955 if (track()->rec_enable_control()->get_value()) {
956 step_edit_item->set_sensitive (false);
958 step_edit_item->set_active (midi_track()->step_editing());
961 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
962 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
967 RouteUI::toggle_step_edit ()
969 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
973 midi_track()->set_step_editing (step_edit_item->get_active());
977 RouteUI::toggle_rec_safe ()
979 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
985 /* This check is made inside the control too, but dong it here can't
989 if (_route->rec_enable_control()->get_value()) {
993 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
997 RouteUI::step_edit_changed (bool yn)
1000 if (rec_enable_button) {
1001 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1004 start_step_editing ();
1006 if (step_edit_item) {
1007 step_edit_item->set_active (true);
1012 if (rec_enable_button) {
1013 rec_enable_button->unset_active_state ();
1016 stop_step_editing ();
1018 if (step_edit_item) {
1019 step_edit_item->set_active (false);
1025 RouteUI::rec_enable_release (GdkEventButton* ev)
1027 if (Keyboard::is_context_menu_event (ev)) {
1028 build_record_menu ();
1030 record_menu->popup (1, ev->time);
1039 RouteUI::build_sends_menu ()
1041 using namespace Menu_Helpers;
1043 sends_menu = new Menu;
1044 sends_menu->set_name ("ArdourContextMenu");
1045 MenuList& items = sends_menu->items();
1048 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1052 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1056 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1060 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1064 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1068 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1071 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1075 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1078 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1079 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1080 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1085 RouteUI::create_sends (Placement p, bool include_buses)
1087 _session->globally_add_internal_sends (_route, p, include_buses);
1091 RouteUI::create_selected_sends (Placement p, bool include_buses)
1093 boost::shared_ptr<RouteList> rlist (new RouteList);
1094 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1096 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1097 RouteTimeAxisView* rtv;
1099 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1100 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1101 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1102 rlist->push_back (rui->route());
1108 _session->add_internal_sends (_route, p, rlist);
1112 RouteUI::set_sends_gain_from_track ()
1114 _session->globally_set_send_gains_from_track (_route);
1118 RouteUI::set_sends_gain_to_zero ()
1120 _session->globally_set_send_gains_to_zero (_route);
1124 RouteUI::set_sends_gain_to_unity ()
1126 _session->globally_set_send_gains_to_unity (_route);
1130 RouteUI::show_sends_press(GdkEventButton* ev)
1132 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1136 if (!is_track() && show_sends_button) {
1138 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1140 // do nothing on midi sigc::bind event
1143 } else if (Keyboard::is_context_menu_event (ev)) {
1145 if (sends_menu == 0) {
1146 build_sends_menu ();
1149 sends_menu->popup (0, ev->time);
1153 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1156 set_showing_sends_to (boost::shared_ptr<Route> ());
1158 set_showing_sends_to (_route);
1167 RouteUI::show_sends_release (GdkEventButton*)
1173 RouteUI::send_blink (bool onoff)
1175 if (!show_sends_button) {
1180 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1182 show_sends_button->unset_active_state ();
1186 Gtkmm2ext::ActiveState
1187 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1189 boost::shared_ptr<SoloControl> sc = s->solo_control();
1192 return Gtkmm2ext::Off;
1195 if (!sc->can_solo()) {
1196 return Gtkmm2ext::Off;
1200 if (sc->self_soloed()) {
1201 return Gtkmm2ext::ExplicitActive;
1202 } else if (sc->soloed_by_others()) {
1203 return Gtkmm2ext::ImplicitActive;
1205 return Gtkmm2ext::Off;
1209 Gtkmm2ext::ActiveState
1210 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1212 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1215 return Gtkmm2ext::Off;
1218 if (s->is_master() || s->is_monitor()) {
1219 return Gtkmm2ext::Off;
1222 if (sc->solo_isolated()) {
1223 return Gtkmm2ext::ExplicitActive;
1225 return Gtkmm2ext::Off;
1229 Gtkmm2ext::ActiveState
1230 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1232 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1235 return Gtkmm2ext::Off;
1238 if (s->is_master() || s->is_monitor()) {
1239 return Gtkmm2ext::Off;
1242 if (sc->solo_safe()) {
1243 return Gtkmm2ext::ExplicitActive;
1245 return Gtkmm2ext::Off;
1250 RouteUI::update_solo_display ()
1252 bool yn = _route->solo_safe_control()->solo_safe ();
1254 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1255 solo_safe_check->set_active (yn);
1258 yn = _route->solo_isolate_control()->solo_isolated ();
1260 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1261 solo_isolated_check->set_active (yn);
1264 set_button_names ();
1266 if (solo_isolated_led) {
1267 if (_route->solo_isolate_control()->solo_isolated()) {
1268 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1270 solo_isolated_led->unset_active_state ();
1274 if (solo_safe_led) {
1275 if (_route->solo_safe_control()->solo_safe()) {
1276 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1278 solo_safe_led->unset_active_state ();
1282 solo_button->set_active_state (solo_active_state (_route));
1284 /* some changes to solo status can affect mute display, so catch up
1287 update_mute_display ();
1291 RouteUI::solo_changed_so_update_mute ()
1293 update_mute_display ();
1297 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1299 boost::shared_ptr<MuteControl> mc = s->mute_control();
1301 if (s->is_monitor()) {
1302 return Gtkmm2ext::Off;
1306 return Gtkmm2ext::Off;
1309 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1311 if (mc->muted_by_self ()) {
1313 return Gtkmm2ext::ExplicitActive;
1314 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1315 /* this will reflect both solo mutes AND master mutes */
1316 return Gtkmm2ext::ImplicitActive;
1318 /* no mute at all */
1319 return Gtkmm2ext::Off;
1324 if (mc->muted_by_self()) {
1326 return Gtkmm2ext::ExplicitActive;
1327 } else if (mc->muted_by_masters ()) {
1328 /* this shows only master mutes, not mute-by-others-soloing */
1329 return Gtkmm2ext::ImplicitActive;
1331 /* no mute at all */
1332 return Gtkmm2ext::Off;
1336 return ActiveState(0);
1340 RouteUI::update_mute_display ()
1346 mute_button->set_active_state (mute_active_state (_session, _route));
1351 RouteUI::route_rec_enable_changed ()
1353 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1357 RouteUI::session_rec_enable_changed ()
1359 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1363 RouteUI::blink_rec_display (bool blinkOn)
1365 if (!rec_enable_button || !_route) {
1369 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1377 if (track()->rec_enable_control()->get_value()) {
1378 switch (_session->record_status ()) {
1379 case Session::Recording:
1380 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1383 case Session::Disabled:
1384 case Session::Enabled:
1385 if (UIConfiguration::instance().get_blink_rec_arm()) {
1386 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1388 rec_enable_button->set_active_state ( ImplicitActive );
1393 if (step_edit_item) {
1394 step_edit_item->set_sensitive (false);
1398 rec_enable_button->unset_active_state ();
1400 if (step_edit_item) {
1401 step_edit_item->set_sensitive (true);
1405 check_rec_enable_sensitivity ();
1409 RouteUI::build_solo_menu (void)
1411 using namespace Menu_Helpers;
1413 solo_menu = new Menu;
1414 solo_menu->set_name ("ArdourContextMenu");
1415 MenuList& items = solo_menu->items();
1416 Gtk::CheckMenuItem* check;
1418 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1419 check->set_active (_route->solo_isolate_control()->solo_isolated());
1420 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1421 items.push_back (CheckMenuElem(*check));
1422 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1425 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1426 check->set_active (_route->solo_safe_control()->solo_safe());
1427 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1428 items.push_back (CheckMenuElem(*check));
1429 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1434 RouteUI::build_mute_menu(void)
1436 using namespace Menu_Helpers;
1438 mute_menu = new Menu;
1439 mute_menu->set_name ("ArdourContextMenu");
1441 MenuList& items = mute_menu->items();
1443 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1444 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1445 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1446 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1447 pre_fader_mute_check->show_all();
1449 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1450 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1451 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1452 items.push_back (CheckMenuElem(*post_fader_mute_check));
1453 post_fader_mute_check->show_all();
1455 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1456 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1457 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1458 items.push_back (CheckMenuElem(*listen_mute_check));
1459 listen_mute_check->show_all();
1461 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1462 init_mute_menu(MuteMaster::Main, main_mute_check);
1463 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1464 items.push_back (CheckMenuElem(*main_mute_check));
1465 main_mute_check->show_all();
1467 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1471 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1473 check->set_active (_route->mute_control()->mute_points() & mp);
1477 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1479 if (check->get_active()) {
1480 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1482 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1487 RouteUI::muting_change ()
1489 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1492 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1494 yn = (current & MuteMaster::PreFader);
1496 if (pre_fader_mute_check->get_active() != yn) {
1497 pre_fader_mute_check->set_active (yn);
1500 yn = (current & MuteMaster::PostFader);
1502 if (post_fader_mute_check->get_active() != yn) {
1503 post_fader_mute_check->set_active (yn);
1506 yn = (current & MuteMaster::Listen);
1508 if (listen_mute_check->get_active() != yn) {
1509 listen_mute_check->set_active (yn);
1512 yn = (current & MuteMaster::Main);
1514 if (main_mute_check->get_active() != yn) {
1515 main_mute_check->set_active (yn);
1520 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1522 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1526 bool view = solo_isolated_led->active_state();
1527 bool model = _route->solo_isolate_control()->solo_isolated();
1529 /* called BEFORE the view has changed */
1531 if (ev->button == 1) {
1532 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1535 /* disable isolate for all routes */
1536 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1538 /* enable isolate for all routes */
1539 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1544 if (model == view) {
1546 /* flip just this route */
1548 boost::shared_ptr<RouteList> rl (new RouteList);
1549 rl->push_back (_route);
1550 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1559 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1561 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1565 bool view = solo_safe_led->active_state();
1566 bool model = _route->solo_safe_control()->solo_safe();
1568 if (ev->button == 1) {
1569 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1570 boost::shared_ptr<RouteList> rl (_session->get_routes());
1572 /* disable solo safe for all routes */
1573 DisplaySuspender ds;
1574 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1575 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1578 /* enable solo safe for all routes */
1579 DisplaySuspender ds;
1580 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1581 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1586 if (model == view) {
1587 /* flip just this route */
1588 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1597 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1599 bool view = check->get_active();
1600 bool model = _route->solo_isolate_control()->solo_isolated();
1602 /* called AFTER the view has changed */
1604 if (model != view) {
1605 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1610 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1612 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1615 /** Ask the user to choose a colour, and then apply that color to my route */
1617 RouteUI::choose_color ()
1619 _color_picker.popup (_route);
1622 /** Set the route's own color. This may not be used for display if
1623 * the route is in a group which shares its color with its routes.
1626 RouteUI::set_color (uint32_t c)
1628 _route->presentation_info().set_color (c);
1631 /** @return GUI state ID for things that are common to the route in all its representations */
1633 RouteUI::route_state_id () const
1635 return string_compose (X_("route %1"), _route->id().to_s());
1639 RouteUI::set_color_from_route ()
1641 if (_route->presentation_info().color_set()) {
1642 return 0; /* nothing to do */
1645 return 1; /* pick a color */
1648 /** @return true if this name should be used for the route, otherwise false */
1650 RouteUI::verify_new_route_name (const std::string& name)
1652 if (name.find (':') == string::npos) {
1656 MessageDialog colon_msg (
1657 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1658 false, MESSAGE_QUESTION, BUTTONS_NONE
1661 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1662 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1664 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1668 RouteUI::route_rename ()
1670 ArdourWidgets::Prompter name_prompter (true);
1675 name_prompter.set_title (_("Rename Track"));
1677 name_prompter.set_title (_("Rename Bus"));
1679 name_prompter.set_prompt (_("New name:"));
1680 name_prompter.set_initial_text (_route->name());
1681 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1682 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1683 name_prompter.show_all ();
1686 switch (name_prompter.run ()) {
1687 case Gtk::RESPONSE_ACCEPT:
1688 name_prompter.get_result (result);
1689 name_prompter.hide ();
1690 if (result.length()) {
1691 if (verify_new_route_name (result)) {
1692 _route->set_name (result);
1695 /* back to name prompter */
1699 /* nothing entered, just get out of here */
1714 RouteUI::toggle_comment_editor ()
1716 // if (ignore_toggle) {
1720 if (comment_window && comment_window->is_visible ()) {
1721 comment_window->hide ();
1723 open_comment_editor ();
1729 RouteUI::open_comment_editor ()
1731 if (comment_window == 0) {
1732 setup_comment_editor ();
1736 title = _route->name();
1737 title += _(": comment editor");
1739 comment_window->set_title (title);
1740 comment_window->present();
1744 RouteUI::setup_comment_editor ()
1746 comment_window = new ArdourWindow (""); // title will be reset to show route
1747 comment_window->set_skip_taskbar_hint (true);
1748 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1749 comment_window->set_default_size (400, 200);
1751 comment_area = manage (new TextView());
1752 comment_area->set_name ("MixerTrackCommentArea");
1753 comment_area->set_wrap_mode (WRAP_WORD);
1754 comment_area->set_editable (true);
1755 comment_area->get_buffer()->set_text (_route->comment());
1756 comment_area->show ();
1758 comment_window->add (*comment_area);
1762 RouteUI::comment_changed ()
1764 ignore_comment_edit = true;
1766 comment_area->get_buffer()->set_text (_route->comment());
1768 ignore_comment_edit = false;
1772 RouteUI::comment_editor_done_editing ()
1774 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1776 string const str = comment_area->get_buffer()->get_text();
1777 if (str == _route->comment ()) {
1781 _route->set_comment (str, this);
1785 RouteUI::set_route_active (bool a, bool apply_to_selection)
1787 if (apply_to_selection) {
1788 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1790 _route->set_active (a, this);
1795 RouteUI::duplicate_selected_routes ()
1797 ARDOUR_UI::instance()->start_duplicate_routes();
1801 RouteUI::toggle_denormal_protection ()
1803 if (denormal_menu_item) {
1807 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1809 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1810 _route->set_denormal_protection (x);
1816 RouteUI::denormal_protection_changed ()
1818 if (denormal_menu_item) {
1819 denormal_menu_item->set_active (_route->denormal_protection());
1824 RouteUI::disconnect_input ()
1826 _route->input()->disconnect (this);
1830 RouteUI::disconnect_output ()
1832 _route->output()->disconnect (this);
1836 RouteUI::is_track () const
1838 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1841 boost::shared_ptr<Track>
1842 RouteUI::track() const
1844 return boost::dynamic_pointer_cast<Track>(_route);
1848 RouteUI::is_audio_track () const
1850 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1853 boost::shared_ptr<AudioTrack>
1854 RouteUI::audio_track() const
1856 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1860 RouteUI::is_midi_track () const
1862 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1865 boost::shared_ptr<MidiTrack>
1866 RouteUI::midi_track() const
1868 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1872 RouteUI::has_audio_outputs () const
1874 return (_route->n_outputs().n_audio() > 0);
1878 RouteUI::map_frozen ()
1880 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1882 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1885 check_rec_enable_sensitivity ();
1890 RouteUI::adjust_latency ()
1892 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1896 RouteUI::process_save_template_prompter (Prompter& prompter, const std::string& dir)
1899 std::string safe_name;
1902 prompter.get_result (name, true);
1904 safe_name = legalize_for_path (name);
1905 safe_name += template_suffix;
1907 path = Glib::build_filename (dir, safe_name);
1909 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1910 bool overwrite = overwrite_file_dialog (prompter,
1911 _("Confirm Template Overwrite"),
1912 _("A template already exists with that name. Do you want to overwrite it?"));
1919 _route->save_as_template (path, name);
1925 RouteUI::save_as_template ()
1929 dir = ARDOUR::user_route_template_directory ();
1931 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1932 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1936 Prompter prompter (true); // modal
1938 prompter.set_title (_("Save As Template"));
1939 prompter.set_prompt (_("Template name:"));
1940 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1942 bool finished = false;
1944 switch (prompter.run()) {
1945 case RESPONSE_ACCEPT:
1946 finished = process_save_template_prompter (prompter, dir);
1956 RouteUI::check_rec_enable_sensitivity ()
1958 if (!rec_enable_button) {
1959 assert (0); // This should not happen
1962 if (!_session->writable()) {
1963 rec_enable_button->set_sensitive (false);
1967 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1968 rec_enable_button->set_sensitive (false);
1969 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1970 rec_enable_button->set_sensitive (false);
1972 rec_enable_button->set_sensitive (true);
1974 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1975 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1977 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1979 update_monitoring_display ();
1983 RouteUI::parameter_changed (string const & p)
1985 /* this handles RC and per-session parameter changes */
1987 if (p == "disable-disarm-during-roll") {
1988 check_rec_enable_sensitivity ();
1989 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1990 set_button_names ();
1991 } else if (p == "session-monitoring") {
1992 update_monitoring_display ();
1993 } else if (p == "auto-input") {
1994 update_monitoring_display ();
1995 } else if (p == "blink-rec-arm") {
1996 if (UIConfiguration::instance().get_blink_rec_arm()) {
1997 rec_blink_connection.disconnect ();
1998 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2000 rec_blink_connection.disconnect ();
2001 RouteUI::blink_rec_display(false);
2007 RouteUI::setup_invert_buttons ()
2009 /* remove old invert buttons */
2010 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2011 _invert_button_box.remove (**i);
2014 _invert_buttons.clear ();
2016 if (!_route || !_route->input()) {
2020 uint32_t const N = _route->input()->n_ports().n_audio ();
2022 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2024 for (uint32_t i = 0; i < to_add; ++i) {
2025 ArdourButton* b = manage (new ArdourButton);
2026 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2027 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2029 b->set_name (X_("invert button"));
2032 b->set_text (string_compose (X_("Ø (%1)"), N));
2034 b->set_text (X_("Ø"));
2037 b->set_text (string_compose (X_("Ø%1"), i + 1));
2040 if (N <= _max_invert_buttons) {
2041 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));
2043 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2046 _invert_buttons.push_back (b);
2047 _invert_button_box.pack_start (*b);
2050 _invert_button_box.set_spacing (1);
2051 _invert_button_box.show_all ();
2055 RouteUI::set_invert_button_state ()
2057 uint32_t const N = _route->input()->n_ports().n_audio();
2058 if (N > _max_invert_buttons) {
2060 /* One button for many channels; explicit active if all channels are inverted,
2061 implicit active if some are, off if none are.
2064 ArdourButton* b = _invert_buttons.front ();
2066 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2067 b->set_active_state (Gtkmm2ext::ExplicitActive);
2068 } else if (_route->phase_control()->any()) {
2069 b->set_active_state (Gtkmm2ext::ImplicitActive);
2071 b->set_active_state (Gtkmm2ext::Off);
2076 /* One button per channel; just set active */
2079 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2080 (*i)->set_active (_route->phase_control()->inverted (j));
2087 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2089 if (ev->button == 1 && i < _invert_buttons.size()) {
2090 uint32_t const N = _route->input()->n_ports().n_audio ();
2091 if (N <= _max_invert_buttons) {
2092 /* left-click inverts phase so long as we have a button per channel */
2093 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2102 RouteUI::invert_press (GdkEventButton* ev)
2104 using namespace Menu_Helpers;
2106 uint32_t const N = _route->input()->n_ports().n_audio();
2107 if (N <= _max_invert_buttons && ev->button != 3) {
2108 /* If we have an invert button per channel, we only pop
2109 up a menu on right-click; left click is handled
2115 delete _invert_menu;
2116 _invert_menu = new Menu;
2117 _invert_menu->set_name ("ArdourContextMenu");
2118 MenuList& items = _invert_menu->items ();
2120 for (uint32_t i = 0; i < N; ++i) {
2121 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2122 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2123 ++_i_am_the_modifier;
2124 e->set_active (_route->phase_control()->inverted (i));
2125 --_i_am_the_modifier;
2128 _invert_menu->popup (0, ev->time);
2134 RouteUI::invert_menu_toggled (uint32_t c)
2136 if (_i_am_the_modifier) {
2141 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2145 RouteUI::set_invert_sensitive (bool yn)
2147 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2148 (*b)->set_sensitive (yn);
2152 /** The Route's gui_changed signal has been emitted */
2154 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2156 if (what_changed.contains (Properties::color)) {
2157 if (set_color_from_route () == 0) {
2158 route_color_changed ();
2164 RouteUI::track_mode_changed (void)
2167 switch (track()->mode()) {
2168 case ARDOUR::NonLayered:
2169 case ARDOUR::Normal:
2170 rec_enable_button->set_icon (ArdourIcon::RecButton);
2172 case ARDOUR::Destructive:
2173 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2176 rec_enable_button->queue_draw();
2179 /** @return the color that this route should use; it maybe its own,
2180 * or it maybe that of its route group.
2183 RouteUI::route_color () const
2186 RouteGroup* g = _route->route_group ();
2189 if (g && g->is_color()) {
2190 set_color_from_rgba (c, GroupTabs::group_color (g));
2192 set_color_from_rgba (c, _route->presentation_info().color());
2199 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2201 _showing_sends_to = send_to;
2202 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2206 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2208 if (_route == send_to) {
2209 show_sends_button->set_active (true);
2210 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2212 show_sends_button->set_active (false);
2213 send_blink_connection.disconnect ();
2218 RouteUI::route_group() const
2220 return _route->route_group();
2224 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2225 : WM::ProxyBase (name, string())
2226 , _route (boost::weak_ptr<Route> (route))
2228 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2231 RoutePinWindowProxy::~RoutePinWindowProxy()
2236 ARDOUR::SessionHandlePtr*
2237 RoutePinWindowProxy::session_handle ()
2239 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2240 if (aw) { return aw; }
2245 RoutePinWindowProxy::get (bool create)
2247 boost::shared_ptr<Route> r = _route.lock ();
2256 _window = new PluginPinDialog (r);
2257 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2259 aw->set_session (_session);
2261 _window->show_all ();
2267 RoutePinWindowProxy::route_going_away ()
2271 WM::Manager::instance().remove (this);
2272 going_away_connection.disconnect();
2277 RouteUI::maybe_add_route_print_mgr ()
2279 if (_route->pinmgr_proxy ()) {
2282 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2283 string_compose ("RPM-%1", _route->id()), _route);
2284 wp->set_session (_session);
2286 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2288 wp->set_state (*ui_xml, 0);
2292 void* existing_ui = _route->pinmgr_proxy ();
2294 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2297 _route->set_pingmgr_proxy (wp);
2299 WM::Manager::instance().register_window (wp);
2303 RouteUI::manage_pins ()
2305 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2313 RouteUI::fan_out (bool to_busses, bool group)
2315 DisplaySuspender ds;
2316 boost::shared_ptr<ARDOUR::Route> route = _route;
2317 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2320 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2321 if (route->n_outputs ().n_audio () != n_outputs) {
2322 MessageDialog msg (string_compose (
2323 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2324 n_outputs, route->n_outputs ().n_audio ()));
2329 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2331 /* count busses and channels/bus */
2332 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2333 std::map<std::string, uint32_t> busnames;
2334 for (uint32_t p = 0; p < n_outputs; ++p) {
2335 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2336 std::string bn = BUSNAME;
2340 if (busnames.size () < 2) {
2341 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2346 uint32_t outputs = 2;
2347 if (_session->master_out ()) {
2348 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2351 route->output ()->disconnect (this);
2352 route->panner_shell ()->set_bypassed (true);
2355 for (uint32_t p = 0; p < n_outputs; ++p) {
2356 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2357 std::string bn = BUSNAME;
2358 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2361 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2365 list<boost::shared_ptr<AudioTrack> > tl =
2366 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2370 boost::shared_ptr<ControlList> cl (new ControlList);
2371 cl->push_back (r->monitoring_control ());
2372 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2374 r->input ()->disconnect (this);
2376 to_group.push_back (r);
2377 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2382 RouteGroup* rg = NULL;
2383 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2384 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2385 if ((*i)->name () == pi->name ()) {
2391 rg = new RouteGroup (*_session, pi->name ());
2392 _session->add_route_group (rg);
2393 rg->set_gain (false);
2396 GroupTabs::set_group_color (rg, route->presentation_info().color());
2397 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2404 RouteUI::mark_hidden (bool yn)
2406 if (yn != _route->presentation_info().hidden()) {
2407 _route->presentation_info().set_hidden (yn);
2408 return true; // things changed
2413 boost::shared_ptr<Stripable>
2414 RouteUI::stripable () const