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/doi.h"
25 #include "gtkmm2ext/gtk_ui.h"
26 #include "gtkmm2ext/utils.h"
28 #include "widgets/ardour_button.h"
29 #include "widgets/binding_proxy.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"
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;
82 using namespace ArdourWidgets;
86 uint32_t RouteUI::_max_invert_buttons = 3;
87 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
88 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
89 std::string RouteUI::program_port_prefix;
91 RouteUI::RouteUI (ARDOUR::Session* sess)
92 : monitor_input_button (0)
93 , monitor_disk_button (0)
101 , output_selector (0)
104 if (program_port_prefix.empty()) {
105 // compare to gtk2_ardour/port_group.cc
106 string lpn (PROGRAM_NAME);
107 boost::to_lower (lpn);
108 program_port_prefix = lpn + ":"; // e.g. "ardour:"
119 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
122 _route.reset (); /* drop reference to route, so that it can be cleaned up */
123 route_connections.drop_connections ();
129 delete comment_window;
130 delete input_selector;
131 delete output_selector;
132 delete monitor_input_button;
133 delete monitor_disk_button;
136 send_blink_connection.disconnect ();
137 rec_blink_connection.disconnect ();
143 self_destruct = true;
149 pre_fader_mute_check = 0;
150 post_fader_mute_check = 0;
151 listen_mute_check = 0;
154 solo_isolated_check = 0;
155 solo_isolated_led = 0;
159 denormal_menu_item = 0;
162 multiple_mute_change = false;
163 multiple_solo_change = false;
164 _i_am_the_modifier = 0;
169 setup_invert_buttons ();
171 mute_button = manage (new ArdourButton);
172 mute_button->set_name ("mute button");
173 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
175 solo_button = manage (new ArdourButton);
176 solo_button->set_name ("solo button");
177 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
178 solo_button->set_no_show_all (true);
180 rec_enable_button = manage (new ArdourButton);
181 rec_enable_button->set_name ("record enable button");
182 rec_enable_button->set_icon (ArdourIcon::RecButton);
183 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
185 if (UIConfiguration::instance().get_blink_rec_arm()) {
186 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
189 show_sends_button = manage (new ArdourButton);
190 show_sends_button->set_name ("send alert button");
191 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
193 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
194 monitor_input_button->set_name ("monitor button");
195 monitor_input_button->set_text (_("In"));
196 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
197 monitor_input_button->set_no_show_all (true);
199 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
200 monitor_disk_button->set_name ("monitor button");
201 monitor_disk_button->set_text (_("Disk"));
202 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
203 monitor_disk_button->set_no_show_all (true);
205 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
206 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
207 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
209 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
211 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
213 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
214 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
216 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
217 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
219 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
220 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
221 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
222 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
224 monitor_input_button->set_distinct_led_click (false);
225 monitor_disk_button->set_distinct_led_click (false);
227 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
228 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
230 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
231 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
233 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
239 route_connections.drop_connections ();
247 _color_picker.reset ();
249 denormal_menu_item = 0;
253 RouteUI::self_delete ()
259 RouteUI::set_route (boost::shared_ptr<Route> rp)
265 if ( !_route->presentation_info().color_set() ) {
266 /* deal with older 4.x color, which was stored in the GUI object state */
268 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
272 /* old v4.x or earlier session. Use this information */
274 int red, green, blue;
279 /* old color format version was:
281 16bit value for red:16 bit value for green:16 bit value for blue
296 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
300 if (set_color_from_route()) {
301 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
305 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
308 delete input_selector;
311 delete output_selector;
314 mute_button->set_controllable (_route->mute_control());
315 solo_button->set_controllable (_route->solo_control());
317 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
319 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
321 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
322 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
323 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
324 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
325 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
326 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
329 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
330 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
331 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
333 track_mode_changed();
337 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
338 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
340 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
342 if (_session->writable() && is_track()) {
343 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
345 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
346 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
348 rec_enable_button->show();
349 rec_enable_button->set_controllable (t->rec_enable_control());
351 if (is_midi_track()) {
352 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
353 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
358 /* this will work for busses and tracks, and needs to be called to
359 set up the name entry/name label display.
363 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
364 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
366 update_monitoring_display ();
369 mute_button->unset_flags (Gtk::CAN_FOCUS);
370 solo_button->unset_flags (Gtk::CAN_FOCUS);
374 if (_route->is_monitor() || _route->is_master()) {
375 solo_button->hide ();
382 setup_invert_buttons ();
383 set_invert_button_state ();
385 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
386 bus_send_display_changed (s);
388 update_mute_display ();
389 update_solo_display ();
391 if (!UIConfiguration::instance().get_blink_rec_arm()) {
392 blink_rec_display(true); // set initial rec-en button state
395 check_rec_enable_sensitivity ();
396 maybe_add_route_print_mgr ();
397 route_color_changed();
398 route_gui_changed (PropertyChange (Properties::selected));
402 RouteUI::polarity_changed ()
408 set_invert_button_state ();
412 RouteUI::mute_press (GdkEventButton* ev)
414 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
418 //if this is a binding action, let the ArdourButton handle it
419 if (BindingProxy::is_bind_action(ev) )
422 multiple_mute_change = false;
424 if (Keyboard::is_context_menu_event (ev)) {
430 mute_menu->popup(0,ev->time);
436 if (Keyboard::is_button2_event (ev)) {
437 // button2-click is "momentary"
439 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
442 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
444 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
446 /* toggle mute on everything (but
447 * exclude the master and monitor)
449 * because we are going to erase
450 * elements of the list we need to work
454 boost::shared_ptr<RouteList> copy (new RouteList);
456 *copy = *_session->get_routes ();
458 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
459 if ((*i)->is_master() || (*i)->is_monitor()) {
467 _mute_release->routes = copy;
470 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
472 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
474 /* Primary-button1 inverts the implication of
475 the group being active. If the group is
476 active (for mute), then this modifier means
477 "do not apply to mute". If the group is
478 inactive (for mute), then this modifier
479 means "apply to route". This is all
480 accomplished by passing just the actual
481 route, along with the InverseGroup group
484 NOTE: Primary-button2 is MIDI learn.
487 boost::shared_ptr<RouteList> rl;
489 if (ev->button == 1) {
491 rl.reset (new RouteList);
492 rl->push_back (_route);
495 _mute_release->routes = rl;
498 boost::shared_ptr<MuteControl> mc = _route->mute_control();
499 mc->start_touch (_session->audible_frame ());
500 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
505 /* plain click applies change to this route */
507 boost::shared_ptr<RouteList> rl (new RouteList);
508 rl->push_back (_route);
511 _mute_release->routes = rl;
514 boost::shared_ptr<MuteControl> mc = _route->mute_control();
515 mc->start_touch (_session->audible_frame ());
516 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
525 RouteUI::mute_release (GdkEventButton* /*ev*/)
528 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
529 delete _mute_release;
533 _route->mute_control()->stop_touch (false, _session->audible_frame ());
539 RouteUI::edit_output_configuration ()
541 if (output_selector == 0) {
543 boost::shared_ptr<Send> send;
544 boost::shared_ptr<IO> output;
546 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
547 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
548 output = send->output();
550 output = _route->output ();
553 output = _route->output ();
556 output_selector = new IOSelectorWindow (_session, output);
559 if (output_selector->is_visible()) {
560 output_selector->get_toplevel()->get_window()->raise();
562 output_selector->present ();
565 //output_selector->set_keep_above (true);
569 RouteUI::edit_input_configuration ()
571 if (input_selector == 0) {
572 input_selector = new IOSelectorWindow (_session, _route->input());
575 if (input_selector->is_visible()) {
576 input_selector->get_toplevel()->get_window()->raise();
578 input_selector->present ();
581 //input_selector->set_keep_above (true);
585 RouteUI::solo_press(GdkEventButton* ev)
587 /* ignore double/triple clicks */
589 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
593 //if this is a binding action, let the ArdourButton handle it
594 if (BindingProxy::is_bind_action(ev) )
597 multiple_solo_change = false;
599 if (Keyboard::is_context_menu_event (ev)) {
601 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
602 ! (solo_safe_led && solo_safe_led->is_visible())) {
604 if (solo_menu == 0) {
608 solo_menu->popup (1, ev->time);
613 if (Keyboard::is_button2_event (ev)) {
615 // button2-click is "momentary"
616 _solo_release = new SoloMuteRelease (_route->self_soloed());
619 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
621 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
623 /* Primary-Tertiary-click applies change to all routes */
626 _solo_release->routes = _session->get_routes ();
629 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
631 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
633 /* Primary-Secondary-click: exclusively solo this track */
636 _solo_release->exclusive = true;
638 _solo_release->routes_on.reset (new RouteList);
639 _solo_release->routes_off.reset (new RouteList);
641 boost::shared_ptr<RouteList> routes = _session->get_routes();
642 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
644 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
648 if ((*i)->soloed ()) {
649 _solo_release->routes_on->push_back (*i);
651 _solo_release->routes_off->push_back (*i);
656 boost::shared_ptr<RouteList> rl (new RouteList);
657 boost::shared_ptr<RouteList> routes = _session->get_routes();
658 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
660 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
664 if ((*i)->soloed ()) {
668 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
670 if (Config->get_solo_control_is_listen_control()) {
671 /* ??? we need a just_one_listen() method */
674 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
677 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
679 // shift-click: toggle solo isolated status
681 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
682 delete _solo_release;
685 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
687 /* Primary-button1: solo mix group.
688 NOTE: Primary-button2 is MIDI learn.
691 /* Primary-button1 applies change to the mix group even if it is not active
692 NOTE: Primary-button2 is MIDI learn.
695 boost::shared_ptr<RouteList> rl;
697 if (ev->button == 1) {
699 /* Primary-button1 inverts the implication of
700 the group being active. If the group is
701 active (for solo), then this modifier means
702 "do not apply to solo". If the group is
703 inactive (for mute), then this modifier
704 means "apply to route". This is all
705 accomplished by passing just the actual
706 route, along with the InverseGroup group
709 NOTE: Primary-button2 is MIDI learn.
712 rl.reset (new RouteList);
713 rl->push_back (_route);
716 _solo_release->routes = rl;
719 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
722 delete _solo_release;
727 /* click: solo this route */
729 boost::shared_ptr<RouteList> rl (new RouteList);
730 rl->push_back (route());
733 _solo_release->routes = rl;
736 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
745 RouteUI::solo_release (GdkEventButton* /*ev*/)
748 if (_solo_release->exclusive) {
749 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
750 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
752 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
755 delete _solo_release;
763 RouteUI::rec_enable_press(GdkEventButton* ev)
765 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
769 //if this is a binding action, let the ArdourButton handle it
770 if (BindingProxy::is_bind_action(ev) )
773 if (!_session->engine().connected()) {
774 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
779 if (is_midi_track()) {
781 /* rec-enable button exits from step editing */
783 if (midi_track()->step_editing()) {
784 midi_track()->set_step_editing (false);
789 if (is_track() && rec_enable_button) {
791 if (Keyboard::is_button2_event (ev)) {
793 //rec arm does not have a momentary mode
796 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
798 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
800 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
802 /* Primary-button1 applies change to the route group (even if it is not active)
803 NOTE: Primary-button2 is MIDI learn.
806 if (ev->button == 1) {
808 boost::shared_ptr<RouteList> rl;
810 rl.reset (new RouteList);
811 rl->push_back (_route);
813 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
816 } else if (Keyboard::is_context_menu_event (ev)) {
818 /* do this on release */
822 boost::shared_ptr<Track> trk = track();
823 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
831 RouteUI::update_monitoring_display ()
837 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
843 MonitorState ms = t->monitoring_state();
845 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
846 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
848 if (ms & MonitoringInput) {
849 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
851 monitor_input_button->unset_active_state ();
855 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
856 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
858 if (ms & MonitoringDisk) {
859 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
861 monitor_disk_button->unset_active_state ();
867 RouteUI::monitor_input_press(GdkEventButton*)
873 RouteUI::monitor_input_release(GdkEventButton* ev)
875 return monitor_release (ev, MonitorInput);
879 RouteUI::monitor_disk_press (GdkEventButton*)
885 RouteUI::monitor_disk_release (GdkEventButton* ev)
887 return monitor_release (ev, MonitorDisk);
891 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
893 if (ev->button != 1) {
897 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
904 boost::shared_ptr<RouteList> rl;
906 /* XXX for now, monitoring choices are orthogonal. cue monitoring
907 will follow in 3.X but requires mixing the input and playback (disk)
908 signal together, which requires yet more buffers.
911 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
912 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
914 /* this line will change when the options are non-orthogonal */
915 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
919 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
920 /* Primary-Tertiary-click applies change to all routes */
921 rl = _session->get_routes ();
922 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
923 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
924 /* Primary-click overrides group */
925 rl.reset (new RouteList);
926 rl->push_back (route());
927 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
929 rl.reset (new RouteList);
930 rl->push_back (route());
931 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
938 RouteUI::build_record_menu ()
941 record_menu = new Menu;
942 record_menu->set_name ("ArdourContextMenu");
943 using namespace Menu_Helpers;
944 MenuList& items = record_menu->items();
946 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
947 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
949 if (is_midi_track()) {
950 items.push_back (SeparatorElem());
951 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
952 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
956 if (step_edit_item) {
957 if (track()->rec_enable_control()->get_value()) {
958 step_edit_item->set_sensitive (false);
960 step_edit_item->set_active (midi_track()->step_editing());
963 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
964 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
969 RouteUI::toggle_step_edit ()
971 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
975 midi_track()->set_step_editing (step_edit_item->get_active());
979 RouteUI::toggle_rec_safe ()
981 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
987 /* This check is made inside the control too, but dong it here can't
991 if (_route->rec_enable_control()->get_value()) {
995 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
999 RouteUI::step_edit_changed (bool yn)
1002 if (rec_enable_button) {
1003 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1006 start_step_editing ();
1008 if (step_edit_item) {
1009 step_edit_item->set_active (true);
1014 if (rec_enable_button) {
1015 rec_enable_button->unset_active_state ();
1018 stop_step_editing ();
1020 if (step_edit_item) {
1021 step_edit_item->set_active (false);
1027 RouteUI::rec_enable_release (GdkEventButton* ev)
1029 if (Keyboard::is_context_menu_event (ev)) {
1030 build_record_menu ();
1032 record_menu->popup (1, ev->time);
1041 RouteUI::build_sends_menu ()
1043 using namespace Menu_Helpers;
1045 sends_menu = new Menu;
1046 sends_menu->set_name ("ArdourContextMenu");
1047 MenuList& items = sends_menu->items();
1050 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1054 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1058 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1062 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1066 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1070 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1073 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1077 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1080 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1081 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1082 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1087 RouteUI::create_sends (Placement p, bool include_buses)
1089 _session->globally_add_internal_sends (_route, p, include_buses);
1093 RouteUI::create_selected_sends (Placement p, bool include_buses)
1095 boost::shared_ptr<RouteList> rlist (new RouteList);
1096 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1098 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1099 RouteTimeAxisView* rtv;
1101 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1102 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1103 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1104 rlist->push_back (rui->route());
1110 _session->add_internal_sends (_route, p, rlist);
1114 RouteUI::set_sends_gain_from_track ()
1116 _session->globally_set_send_gains_from_track (_route);
1120 RouteUI::set_sends_gain_to_zero ()
1122 _session->globally_set_send_gains_to_zero (_route);
1126 RouteUI::set_sends_gain_to_unity ()
1128 _session->globally_set_send_gains_to_unity (_route);
1132 RouteUI::show_sends_press(GdkEventButton* ev)
1134 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1138 if (!is_track() && show_sends_button) {
1140 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1142 // do nothing on midi sigc::bind event
1145 } else if (Keyboard::is_context_menu_event (ev)) {
1147 if (sends_menu == 0) {
1148 build_sends_menu ();
1151 sends_menu->popup (0, ev->time);
1155 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1158 set_showing_sends_to (boost::shared_ptr<Route> ());
1160 set_showing_sends_to (_route);
1169 RouteUI::show_sends_release (GdkEventButton*)
1175 RouteUI::send_blink (bool onoff)
1177 if (!show_sends_button) {
1182 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1184 show_sends_button->unset_active_state ();
1188 Gtkmm2ext::ActiveState
1189 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1191 boost::shared_ptr<SoloControl> sc = s->solo_control();
1194 return Gtkmm2ext::Off;
1197 if (!sc->can_solo()) {
1198 return Gtkmm2ext::Off;
1202 if (sc->self_soloed()) {
1203 return Gtkmm2ext::ExplicitActive;
1204 } else if (sc->soloed_by_others()) {
1205 return Gtkmm2ext::ImplicitActive;
1207 return Gtkmm2ext::Off;
1211 Gtkmm2ext::ActiveState
1212 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1214 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1217 return Gtkmm2ext::Off;
1220 if (s->is_master() || s->is_monitor()) {
1221 return Gtkmm2ext::Off;
1224 if (sc->solo_isolated()) {
1225 return Gtkmm2ext::ExplicitActive;
1227 return Gtkmm2ext::Off;
1231 Gtkmm2ext::ActiveState
1232 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1234 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1237 return Gtkmm2ext::Off;
1240 if (s->is_master() || s->is_monitor()) {
1241 return Gtkmm2ext::Off;
1244 if (sc->solo_safe()) {
1245 return Gtkmm2ext::ExplicitActive;
1247 return Gtkmm2ext::Off;
1252 RouteUI::update_solo_display ()
1254 bool yn = _route->solo_safe_control()->solo_safe ();
1256 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1257 solo_safe_check->set_active (yn);
1260 yn = _route->solo_isolate_control()->solo_isolated ();
1262 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1263 solo_isolated_check->set_active (yn);
1266 set_button_names ();
1268 if (solo_isolated_led) {
1269 if (_route->solo_isolate_control()->solo_isolated()) {
1270 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1272 solo_isolated_led->unset_active_state ();
1276 if (solo_safe_led) {
1277 if (_route->solo_safe_control()->solo_safe()) {
1278 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1280 solo_safe_led->unset_active_state ();
1284 solo_button->set_active_state (solo_active_state (_route));
1286 /* some changes to solo status can affect mute display, so catch up
1289 update_mute_display ();
1293 RouteUI::solo_changed_so_update_mute ()
1295 update_mute_display ();
1299 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1301 boost::shared_ptr<MuteControl> mc = s->mute_control();
1303 if (s->is_monitor()) {
1304 return Gtkmm2ext::Off;
1308 return Gtkmm2ext::Off;
1311 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1313 if (mc->muted_by_self ()) {
1315 return Gtkmm2ext::ExplicitActive;
1316 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1317 /* this will reflect both solo mutes AND master mutes */
1318 return Gtkmm2ext::ImplicitActive;
1320 /* no mute at all */
1321 return Gtkmm2ext::Off;
1326 if (mc->muted_by_self()) {
1328 return Gtkmm2ext::ExplicitActive;
1329 } else if (mc->muted_by_masters ()) {
1330 /* this shows only master mutes, not mute-by-others-soloing */
1331 return Gtkmm2ext::ImplicitActive;
1333 /* no mute at all */
1334 return Gtkmm2ext::Off;
1338 return ActiveState(0);
1342 RouteUI::update_mute_display ()
1348 mute_button->set_active_state (mute_active_state (_session, _route));
1353 RouteUI::route_rec_enable_changed ()
1355 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1359 RouteUI::session_rec_enable_changed ()
1361 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1365 RouteUI::blink_rec_display (bool blinkOn)
1367 if (!rec_enable_button || !_route) {
1371 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1379 if (track()->rec_enable_control()->get_value()) {
1380 switch (_session->record_status ()) {
1381 case Session::Recording:
1382 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1385 case Session::Disabled:
1386 case Session::Enabled:
1387 if (UIConfiguration::instance().get_blink_rec_arm()) {
1388 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1390 rec_enable_button->set_active_state ( ImplicitActive );
1395 if (step_edit_item) {
1396 step_edit_item->set_sensitive (false);
1400 rec_enable_button->unset_active_state ();
1402 if (step_edit_item) {
1403 step_edit_item->set_sensitive (true);
1407 check_rec_enable_sensitivity ();
1411 RouteUI::build_solo_menu (void)
1413 using namespace Menu_Helpers;
1415 solo_menu = new Menu;
1416 solo_menu->set_name ("ArdourContextMenu");
1417 MenuList& items = solo_menu->items();
1418 Gtk::CheckMenuItem* check;
1420 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1421 check->set_active (_route->solo_isolate_control()->solo_isolated());
1422 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1423 items.push_back (CheckMenuElem(*check));
1424 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1427 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1428 check->set_active (_route->solo_safe_control()->solo_safe());
1429 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1430 items.push_back (CheckMenuElem(*check));
1431 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1436 RouteUI::build_mute_menu(void)
1438 using namespace Menu_Helpers;
1440 mute_menu = new Menu;
1441 mute_menu->set_name ("ArdourContextMenu");
1443 MenuList& items = mute_menu->items();
1445 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1446 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1447 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1448 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1449 pre_fader_mute_check->show_all();
1451 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1452 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1453 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1454 items.push_back (CheckMenuElem(*post_fader_mute_check));
1455 post_fader_mute_check->show_all();
1457 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1458 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1459 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1460 items.push_back (CheckMenuElem(*listen_mute_check));
1461 listen_mute_check->show_all();
1463 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1464 init_mute_menu(MuteMaster::Main, main_mute_check);
1465 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1466 items.push_back (CheckMenuElem(*main_mute_check));
1467 main_mute_check->show_all();
1469 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1473 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1475 check->set_active (_route->mute_control()->mute_points() & mp);
1479 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1481 if (check->get_active()) {
1482 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1484 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1489 RouteUI::muting_change ()
1491 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1494 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1496 yn = (current & MuteMaster::PreFader);
1498 if (pre_fader_mute_check->get_active() != yn) {
1499 pre_fader_mute_check->set_active (yn);
1502 yn = (current & MuteMaster::PostFader);
1504 if (post_fader_mute_check->get_active() != yn) {
1505 post_fader_mute_check->set_active (yn);
1508 yn = (current & MuteMaster::Listen);
1510 if (listen_mute_check->get_active() != yn) {
1511 listen_mute_check->set_active (yn);
1514 yn = (current & MuteMaster::Main);
1516 if (main_mute_check->get_active() != yn) {
1517 main_mute_check->set_active (yn);
1522 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1524 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1528 bool view = solo_isolated_led->active_state();
1529 bool model = _route->solo_isolate_control()->solo_isolated();
1531 /* called BEFORE the view has changed */
1533 if (ev->button == 1) {
1534 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1537 /* disable isolate for all routes */
1538 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1540 /* enable isolate for all routes */
1541 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1546 if (model == view) {
1548 /* flip just this route */
1550 boost::shared_ptr<RouteList> rl (new RouteList);
1551 rl->push_back (_route);
1552 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1561 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1563 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1567 bool view = solo_safe_led->active_state();
1568 bool model = _route->solo_safe_control()->solo_safe();
1570 if (ev->button == 1) {
1571 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1572 boost::shared_ptr<RouteList> rl (_session->get_routes());
1574 /* disable solo safe for all routes */
1575 DisplaySuspender ds;
1576 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1577 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1580 /* enable solo safe for all routes */
1581 DisplaySuspender ds;
1582 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1583 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1588 if (model == view) {
1589 /* flip just this route */
1590 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1599 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1601 bool view = check->get_active();
1602 bool model = _route->solo_isolate_control()->solo_isolated();
1604 /* called AFTER the view has changed */
1606 if (model != view) {
1607 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1612 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1614 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1617 /** Ask the user to choose a colour, and then apply that color to my route */
1619 RouteUI::choose_color ()
1621 _color_picker.popup (_route);
1624 /** Set the route's own color. This may not be used for display if
1625 * the route is in a group which shares its color with its routes.
1628 RouteUI::set_color (uint32_t c)
1630 _route->presentation_info().set_color (c);
1633 /** @return GUI state ID for things that are common to the route in all its representations */
1635 RouteUI::route_state_id () const
1637 return string_compose (X_("route %1"), _route->id().to_s());
1641 RouteUI::set_color_from_route ()
1643 if (_route->presentation_info().color_set()) {
1644 return 0; /* nothing to do */
1647 return 1; /* pick a color */
1650 /** @return true if this name should be used for the route, otherwise false */
1652 RouteUI::verify_new_route_name (const std::string& name)
1654 if (name.find (':') == string::npos) {
1658 MessageDialog colon_msg (
1659 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1660 false, MESSAGE_QUESTION, BUTTONS_NONE
1663 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1664 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1666 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1670 RouteUI::route_rename ()
1672 ArdourPrompter name_prompter (true);
1677 name_prompter.set_title (_("Rename Track"));
1679 name_prompter.set_title (_("Rename Bus"));
1681 name_prompter.set_prompt (_("New name:"));
1682 name_prompter.set_initial_text (_route->name());
1683 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1684 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1685 name_prompter.show_all ();
1688 switch (name_prompter.run ()) {
1689 case Gtk::RESPONSE_ACCEPT:
1690 name_prompter.get_result (result);
1691 name_prompter.hide ();
1692 if (result.length()) {
1693 if (verify_new_route_name (result)) {
1694 _route->set_name (result);
1697 /* back to name prompter */
1701 /* nothing entered, just get out of here */
1716 RouteUI::toggle_comment_editor ()
1718 // if (ignore_toggle) {
1722 if (comment_window && comment_window->is_visible ()) {
1723 comment_window->hide ();
1725 open_comment_editor ();
1731 RouteUI::open_comment_editor ()
1733 if (comment_window == 0) {
1734 setup_comment_editor ();
1738 title = _route->name();
1739 title += _(": comment editor");
1741 comment_window->set_title (title);
1742 comment_window->present();
1746 RouteUI::setup_comment_editor ()
1748 comment_window = new ArdourWindow (""); // title will be reset to show route
1749 comment_window->set_skip_taskbar_hint (true);
1750 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1751 comment_window->set_default_size (400, 200);
1753 comment_area = manage (new TextView());
1754 comment_area->set_name ("MixerTrackCommentArea");
1755 comment_area->set_wrap_mode (WRAP_WORD);
1756 comment_area->set_editable (true);
1757 comment_area->get_buffer()->set_text (_route->comment());
1758 comment_area->show ();
1760 comment_window->add (*comment_area);
1764 RouteUI::comment_changed ()
1766 ignore_comment_edit = true;
1768 comment_area->get_buffer()->set_text (_route->comment());
1770 ignore_comment_edit = false;
1774 RouteUI::comment_editor_done_editing ()
1776 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1778 string const str = comment_area->get_buffer()->get_text();
1779 if (str == _route->comment ()) {
1783 _route->set_comment (str, this);
1787 RouteUI::set_route_active (bool a, bool apply_to_selection)
1789 if (apply_to_selection) {
1790 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1792 _route->set_active (a, this);
1797 RouteUI::duplicate_selected_routes ()
1799 ARDOUR_UI::instance()->start_duplicate_routes();
1803 RouteUI::toggle_denormal_protection ()
1805 if (denormal_menu_item) {
1809 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1811 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1812 _route->set_denormal_protection (x);
1818 RouteUI::denormal_protection_changed ()
1820 if (denormal_menu_item) {
1821 denormal_menu_item->set_active (_route->denormal_protection());
1826 RouteUI::disconnect_input ()
1828 _route->input()->disconnect (this);
1832 RouteUI::disconnect_output ()
1834 _route->output()->disconnect (this);
1838 RouteUI::is_track () const
1840 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1843 boost::shared_ptr<Track>
1844 RouteUI::track() const
1846 return boost::dynamic_pointer_cast<Track>(_route);
1850 RouteUI::is_audio_track () const
1852 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1855 boost::shared_ptr<AudioTrack>
1856 RouteUI::audio_track() const
1858 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1862 RouteUI::is_midi_track () const
1864 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1867 boost::shared_ptr<MidiTrack>
1868 RouteUI::midi_track() const
1870 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1874 RouteUI::has_audio_outputs () const
1876 return (_route->n_outputs().n_audio() > 0);
1880 RouteUI::map_frozen ()
1882 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1884 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1887 check_rec_enable_sensitivity ();
1892 RouteUI::adjust_latency ()
1894 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1898 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1901 std::string safe_name;
1904 prompter.get_result (name, true);
1906 safe_name = legalize_for_path (name);
1907 safe_name += template_suffix;
1909 path = Glib::build_filename (dir, safe_name);
1911 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1912 bool overwrite = overwrite_file_dialog (prompter,
1913 _("Confirm Template Overwrite"),
1914 _("A template already exists with that name. Do you want to overwrite it?"));
1921 _route->save_as_template (path, name);
1927 RouteUI::save_as_template ()
1931 dir = ARDOUR::user_route_template_directory ();
1933 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1934 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1938 ArdourPrompter prompter (true); // modal
1940 prompter.set_title (_("Save As Template"));
1941 prompter.set_prompt (_("Template name:"));
1942 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1944 bool finished = false;
1946 switch (prompter.run()) {
1947 case RESPONSE_ACCEPT:
1948 finished = process_save_template_prompter (prompter, dir);
1958 RouteUI::check_rec_enable_sensitivity ()
1960 if (!rec_enable_button) {
1961 assert (0); // This should not happen
1964 if (!_session->writable()) {
1965 rec_enable_button->set_sensitive (false);
1969 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1970 rec_enable_button->set_sensitive (false);
1971 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1972 rec_enable_button->set_sensitive (false);
1974 rec_enable_button->set_sensitive (true);
1976 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1977 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1979 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1981 update_monitoring_display ();
1985 RouteUI::parameter_changed (string const & p)
1987 /* this handles RC and per-session parameter changes */
1989 if (p == "disable-disarm-during-roll") {
1990 check_rec_enable_sensitivity ();
1991 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1992 set_button_names ();
1993 } else if (p == "session-monitoring") {
1994 update_monitoring_display ();
1995 } else if (p == "auto-input") {
1996 update_monitoring_display ();
1997 } else if (p == "blink-rec-arm") {
1998 if (UIConfiguration::instance().get_blink_rec_arm()) {
1999 rec_blink_connection.disconnect ();
2000 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2002 rec_blink_connection.disconnect ();
2003 RouteUI::blink_rec_display(false);
2009 RouteUI::setup_invert_buttons ()
2011 /* remove old invert buttons */
2012 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2013 _invert_button_box.remove (**i);
2016 _invert_buttons.clear ();
2018 if (!_route || !_route->input()) {
2022 uint32_t const N = _route->input()->n_ports().n_audio ();
2024 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2026 for (uint32_t i = 0; i < to_add; ++i) {
2027 ArdourButton* b = manage (new ArdourButton);
2028 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2029 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2031 b->set_name (X_("invert button"));
2034 b->set_text (string_compose (X_("Ø (%1)"), N));
2036 b->set_text (X_("Ø"));
2039 b->set_text (string_compose (X_("Ø%1"), i + 1));
2042 if (N <= _max_invert_buttons) {
2043 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));
2045 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2048 _invert_buttons.push_back (b);
2049 _invert_button_box.pack_start (*b);
2052 _invert_button_box.set_spacing (1);
2053 _invert_button_box.show_all ();
2057 RouteUI::set_invert_button_state ()
2059 uint32_t const N = _route->input()->n_ports().n_audio();
2060 if (N > _max_invert_buttons) {
2062 /* One button for many channels; explicit active if all channels are inverted,
2063 implicit active if some are, off if none are.
2066 ArdourButton* b = _invert_buttons.front ();
2068 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2069 b->set_active_state (Gtkmm2ext::ExplicitActive);
2070 } else if (_route->phase_control()->any()) {
2071 b->set_active_state (Gtkmm2ext::ImplicitActive);
2073 b->set_active_state (Gtkmm2ext::Off);
2078 /* One button per channel; just set active */
2081 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2082 (*i)->set_active (_route->phase_control()->inverted (j));
2089 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2091 if (ev->button == 1 && i < _invert_buttons.size()) {
2092 uint32_t const N = _route->input()->n_ports().n_audio ();
2093 if (N <= _max_invert_buttons) {
2094 /* left-click inverts phase so long as we have a button per channel */
2095 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2104 RouteUI::invert_press (GdkEventButton* ev)
2106 using namespace Menu_Helpers;
2108 uint32_t const N = _route->input()->n_ports().n_audio();
2109 if (N <= _max_invert_buttons && ev->button != 3) {
2110 /* If we have an invert button per channel, we only pop
2111 up a menu on right-click; left click is handled
2117 delete _invert_menu;
2118 _invert_menu = new Menu;
2119 _invert_menu->set_name ("ArdourContextMenu");
2120 MenuList& items = _invert_menu->items ();
2122 for (uint32_t i = 0; i < N; ++i) {
2123 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2124 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2125 ++_i_am_the_modifier;
2126 e->set_active (_route->phase_control()->inverted (i));
2127 --_i_am_the_modifier;
2130 _invert_menu->popup (0, ev->time);
2136 RouteUI::invert_menu_toggled (uint32_t c)
2138 if (_i_am_the_modifier) {
2143 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2147 RouteUI::set_invert_sensitive (bool yn)
2149 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2150 (*b)->set_sensitive (yn);
2154 /** The Route's gui_changed signal has been emitted */
2156 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2158 if (what_changed.contains (Properties::color)) {
2159 if (set_color_from_route () == 0) {
2160 route_color_changed ();
2166 RouteUI::track_mode_changed (void)
2169 switch (track()->mode()) {
2170 case ARDOUR::NonLayered:
2171 case ARDOUR::Normal:
2172 rec_enable_button->set_icon (ArdourIcon::RecButton);
2174 case ARDOUR::Destructive:
2175 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2178 rec_enable_button->queue_draw();
2181 /** @return the color that this route should use; it maybe its own,
2182 * or it maybe that of its route group.
2185 RouteUI::route_color () const
2188 RouteGroup* g = _route->route_group ();
2191 if (g && g->is_color()) {
2192 set_color_from_rgba (c, GroupTabs::group_color (g));
2194 set_color_from_rgba (c, _route->presentation_info().color());
2201 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2203 _showing_sends_to = send_to;
2204 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2208 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2210 if (_route == send_to) {
2211 show_sends_button->set_active (true);
2212 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2214 show_sends_button->set_active (false);
2215 send_blink_connection.disconnect ();
2220 RouteUI::route_group() const
2222 return _route->route_group();
2226 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2227 : WM::ProxyBase (name, string())
2228 , _route (boost::weak_ptr<Route> (route))
2230 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2233 RoutePinWindowProxy::~RoutePinWindowProxy()
2238 ARDOUR::SessionHandlePtr*
2239 RoutePinWindowProxy::session_handle ()
2241 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2242 if (aw) { return aw; }
2247 RoutePinWindowProxy::get (bool create)
2249 boost::shared_ptr<Route> r = _route.lock ();
2258 _window = new PluginPinDialog (r);
2259 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2261 aw->set_session (_session);
2263 _window->show_all ();
2269 RoutePinWindowProxy::route_going_away ()
2273 WM::Manager::instance().remove (this);
2274 going_away_connection.disconnect();
2279 RouteUI::maybe_add_route_print_mgr ()
2281 if (_route->pinmgr_proxy ()) {
2284 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2285 string_compose ("RPM-%1", _route->id()), _route);
2286 wp->set_session (_session);
2288 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2290 wp->set_state (*ui_xml, 0);
2294 void* existing_ui = _route->pinmgr_proxy ();
2296 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2299 _route->set_pingmgr_proxy (wp);
2301 WM::Manager::instance().register_window (wp);
2305 RouteUI::manage_pins ()
2307 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2315 RouteUI::fan_out (bool to_busses, bool group)
2317 DisplaySuspender ds;
2318 boost::shared_ptr<ARDOUR::Route> route = _route;
2319 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2322 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2323 if (route->n_outputs ().n_audio () != n_outputs) {
2324 MessageDialog msg (string_compose (
2325 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2326 n_outputs, route->n_outputs ().n_audio ()));
2331 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2333 /* count busses and channels/bus */
2334 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2335 std::map<std::string, uint32_t> busnames;
2336 for (uint32_t p = 0; p < n_outputs; ++p) {
2337 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2338 std::string bn = BUSNAME;
2342 if (busnames.size () < 2) {
2343 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2348 uint32_t outputs = 2;
2349 if (_session->master_out ()) {
2350 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2353 route->output ()->disconnect (this);
2354 route->panner_shell ()->set_bypassed (true);
2357 for (uint32_t p = 0; p < n_outputs; ++p) {
2358 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2359 std::string bn = BUSNAME;
2360 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2363 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2367 list<boost::shared_ptr<AudioTrack> > tl =
2368 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2372 boost::shared_ptr<ControlList> cl (new ControlList);
2373 cl->push_back (r->monitoring_control ());
2374 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2376 r->input ()->disconnect (this);
2378 to_group.push_back (r);
2379 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2384 RouteGroup* rg = NULL;
2385 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2386 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2387 if ((*i)->name () == pi->name ()) {
2393 rg = new RouteGroup (*_session, pi->name ());
2394 _session->add_route_group (rg);
2395 rg->set_gain (false);
2398 GroupTabs::set_group_color (rg, route->presentation_info().color());
2399 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2406 RouteUI::mark_hidden (bool yn)
2408 if (yn != _route->presentation_info().hidden()) {
2409 _route->presentation_info().set_hidden (yn);
2410 return true; // things changed
2415 boost::shared_ptr<Stripable>
2416 RouteUI::stripable () const