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 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
332 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
334 track_mode_changed();
338 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
339 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
341 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
343 if (_session->writable() && is_track()) {
344 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
346 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
347 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
349 rec_enable_button->show();
350 rec_enable_button->set_controllable (t->rec_enable_control());
352 if (is_midi_track()) {
353 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
354 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
359 /* this will work for busses and tracks, and needs to be called to
360 set up the name entry/name label display.
364 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
365 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
367 update_monitoring_display ();
370 mute_button->unset_flags (Gtk::CAN_FOCUS);
371 solo_button->unset_flags (Gtk::CAN_FOCUS);
375 if (_route->is_monitor() || _route->is_master()) {
376 solo_button->hide ();
383 setup_invert_buttons ();
384 set_invert_button_state ();
386 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
387 bus_send_display_changed (s);
389 update_mute_display ();
390 update_solo_display ();
392 if (!UIConfiguration::instance().get_blink_rec_arm()) {
393 blink_rec_display(true); // set initial rec-en button state
396 check_rec_enable_sensitivity ();
397 maybe_add_route_print_mgr ();
398 route_color_changed();
399 route_gui_changed (PropertyChange (Properties::selected));
403 RouteUI::polarity_changed ()
409 set_invert_button_state ();
413 RouteUI::mute_press (GdkEventButton* ev)
415 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
419 //if this is a binding action, let the ArdourButton handle it
420 if (BindingProxy::is_bind_action(ev) )
423 multiple_mute_change = false;
425 if (Keyboard::is_context_menu_event (ev)) {
431 mute_menu->popup(0,ev->time);
437 if (Keyboard::is_button2_event (ev)) {
438 // button2-click is "momentary"
440 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
443 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
445 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
447 /* toggle mute on everything (but
448 * exclude the master and monitor)
450 * because we are going to erase
451 * elements of the list we need to work
455 boost::shared_ptr<RouteList> copy (new RouteList);
457 *copy = *_session->get_routes ();
459 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
460 if ((*i)->is_master() || (*i)->is_monitor()) {
468 _mute_release->routes = copy;
471 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
473 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
475 /* Primary-button1 inverts the implication of
476 the group being active. If the group is
477 active (for mute), then this modifier means
478 "do not apply to mute". If the group is
479 inactive (for mute), then this modifier
480 means "apply to route". This is all
481 accomplished by passing just the actual
482 route, along with the InverseGroup group
485 NOTE: Primary-button2 is MIDI learn.
488 boost::shared_ptr<RouteList> rl;
490 if (ev->button == 1) {
492 rl.reset (new RouteList);
493 rl->push_back (_route);
496 _mute_release->routes = rl;
499 boost::shared_ptr<MuteControl> mc = _route->mute_control();
500 mc->start_touch (_session->audible_frame ());
501 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
506 /* plain click applies change to this route */
508 boost::shared_ptr<RouteList> rl (new RouteList);
509 rl->push_back (_route);
512 _mute_release->routes = rl;
515 boost::shared_ptr<MuteControl> mc = _route->mute_control();
516 mc->start_touch (_session->audible_frame ());
517 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
526 RouteUI::mute_release (GdkEventButton* /*ev*/)
529 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
530 delete _mute_release;
534 _route->mute_control()->stop_touch (false, _session->audible_frame ());
540 RouteUI::edit_output_configuration ()
542 if (output_selector == 0) {
544 boost::shared_ptr<Send> send;
545 boost::shared_ptr<IO> output;
547 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
548 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
549 output = send->output();
551 output = _route->output ();
554 output = _route->output ();
557 output_selector = new IOSelectorWindow (_session, output);
560 if (output_selector->is_visible()) {
561 output_selector->get_toplevel()->get_window()->raise();
563 output_selector->present ();
566 //output_selector->set_keep_above (true);
570 RouteUI::edit_input_configuration ()
572 if (input_selector == 0) {
573 input_selector = new IOSelectorWindow (_session, _route->input());
576 if (input_selector->is_visible()) {
577 input_selector->get_toplevel()->get_window()->raise();
579 input_selector->present ();
582 //input_selector->set_keep_above (true);
586 RouteUI::solo_press(GdkEventButton* ev)
588 /* ignore double/triple clicks */
590 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
594 //if this is a binding action, let the ArdourButton handle it
595 if (BindingProxy::is_bind_action(ev) )
598 multiple_solo_change = false;
600 if (Keyboard::is_context_menu_event (ev)) {
602 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
603 ! (solo_safe_led && solo_safe_led->is_visible())) {
605 if (solo_menu == 0) {
609 solo_menu->popup (1, ev->time);
614 if (Keyboard::is_button2_event (ev)) {
616 // button2-click is "momentary"
617 _solo_release = new SoloMuteRelease (_route->self_soloed());
620 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
622 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
624 /* Primary-Tertiary-click applies change to all routes */
627 _solo_release->routes = _session->get_routes ();
630 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
632 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
634 /* Primary-Secondary-click: exclusively solo this track */
637 _solo_release->exclusive = true;
639 _solo_release->routes_on.reset (new RouteList);
640 _solo_release->routes_off.reset (new RouteList);
642 boost::shared_ptr<RouteList> routes = _session->get_routes();
643 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
645 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
649 if ((*i)->soloed ()) {
650 _solo_release->routes_on->push_back (*i);
652 _solo_release->routes_off->push_back (*i);
657 boost::shared_ptr<RouteList> rl (new RouteList);
658 boost::shared_ptr<RouteList> routes = _session->get_routes();
659 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
661 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
665 if ((*i)->soloed ()) {
669 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
671 if (Config->get_solo_control_is_listen_control()) {
672 /* ??? we need a just_one_listen() method */
675 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
678 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
680 // shift-click: toggle solo isolated status
682 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
683 delete _solo_release;
686 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
688 /* Primary-button1: solo mix group.
689 NOTE: Primary-button2 is MIDI learn.
692 /* Primary-button1 applies change to the mix group even if it is not active
693 NOTE: Primary-button2 is MIDI learn.
696 boost::shared_ptr<RouteList> rl;
698 if (ev->button == 1) {
700 /* Primary-button1 inverts the implication of
701 the group being active. If the group is
702 active (for solo), then this modifier means
703 "do not apply to solo". If the group is
704 inactive (for mute), then this modifier
705 means "apply to route". This is all
706 accomplished by passing just the actual
707 route, along with the InverseGroup group
710 NOTE: Primary-button2 is MIDI learn.
713 rl.reset (new RouteList);
714 rl->push_back (_route);
717 _solo_release->routes = rl;
720 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
723 delete _solo_release;
728 /* click: solo this route */
730 boost::shared_ptr<RouteList> rl (new RouteList);
731 rl->push_back (route());
734 _solo_release->routes = rl;
737 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
746 RouteUI::solo_release (GdkEventButton* /*ev*/)
749 if (_solo_release->exclusive) {
750 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
751 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
753 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
756 delete _solo_release;
764 RouteUI::rec_enable_press(GdkEventButton* ev)
766 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
770 //if this is a binding action, let the ArdourButton handle it
771 if (BindingProxy::is_bind_action(ev) )
774 if (!_session->engine().connected()) {
775 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
780 if (is_midi_track()) {
782 /* rec-enable button exits from step editing */
784 if (midi_track()->step_editing()) {
785 midi_track()->set_step_editing (false);
790 if (is_track() && rec_enable_button) {
792 if (Keyboard::is_button2_event (ev)) {
794 //rec arm does not have a momentary mode
797 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
799 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
801 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
803 /* Primary-button1 applies change to the route group (even if it is not active)
804 NOTE: Primary-button2 is MIDI learn.
807 if (ev->button == 1) {
809 boost::shared_ptr<RouteList> rl;
811 rl.reset (new RouteList);
812 rl->push_back (_route);
814 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
817 } else if (Keyboard::is_context_menu_event (ev)) {
819 /* do this on release */
823 boost::shared_ptr<Track> trk = track();
824 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
832 RouteUI::update_monitoring_display ()
838 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
844 MonitorState ms = t->monitoring_state();
846 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
847 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
849 if (ms & MonitoringInput) {
850 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
852 monitor_input_button->unset_active_state ();
856 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
857 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
859 if (ms & MonitoringDisk) {
860 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
862 monitor_disk_button->unset_active_state ();
868 RouteUI::monitor_input_press(GdkEventButton*)
874 RouteUI::monitor_input_release(GdkEventButton* ev)
876 return monitor_release (ev, MonitorInput);
880 RouteUI::monitor_disk_press (GdkEventButton*)
886 RouteUI::monitor_disk_release (GdkEventButton* ev)
888 return monitor_release (ev, MonitorDisk);
892 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
894 if (ev->button != 1) {
898 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
905 boost::shared_ptr<RouteList> rl;
907 /* XXX for now, monitoring choices are orthogonal. cue monitoring
908 will follow in 3.X but requires mixing the input and playback (disk)
909 signal together, which requires yet more buffers.
912 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
913 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
915 /* this line will change when the options are non-orthogonal */
916 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
920 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
921 /* Primary-Tertiary-click applies change to all routes */
922 rl = _session->get_routes ();
923 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
924 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
925 /* Primary-click overrides group */
926 rl.reset (new RouteList);
927 rl->push_back (route());
928 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
930 rl.reset (new RouteList);
931 rl->push_back (route());
932 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
939 RouteUI::build_record_menu ()
942 record_menu = new Menu;
943 record_menu->set_name ("ArdourContextMenu");
944 using namespace Menu_Helpers;
945 MenuList& items = record_menu->items();
947 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
948 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
950 if (is_midi_track()) {
951 items.push_back (SeparatorElem());
952 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
953 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
957 if (step_edit_item) {
958 if (track()->rec_enable_control()->get_value()) {
959 step_edit_item->set_sensitive (false);
961 step_edit_item->set_active (midi_track()->step_editing());
964 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
965 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
970 RouteUI::toggle_step_edit ()
972 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
976 midi_track()->set_step_editing (step_edit_item->get_active());
980 RouteUI::toggle_rec_safe ()
982 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
988 /* This check is made inside the control too, but dong it here can't
992 if (_route->rec_enable_control()->get_value()) {
996 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
1000 RouteUI::step_edit_changed (bool yn)
1003 if (rec_enable_button) {
1004 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1007 start_step_editing ();
1009 if (step_edit_item) {
1010 step_edit_item->set_active (true);
1015 if (rec_enable_button) {
1016 rec_enable_button->unset_active_state ();
1019 stop_step_editing ();
1021 if (step_edit_item) {
1022 step_edit_item->set_active (false);
1028 RouteUI::rec_enable_release (GdkEventButton* ev)
1030 if (Keyboard::is_context_menu_event (ev)) {
1031 build_record_menu ();
1033 record_menu->popup (1, ev->time);
1042 RouteUI::build_sends_menu ()
1044 using namespace Menu_Helpers;
1046 sends_menu = new Menu;
1047 sends_menu->set_name ("ArdourContextMenu");
1048 MenuList& items = sends_menu->items();
1051 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1055 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1059 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1063 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1067 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1071 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1074 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1078 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1081 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1082 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1083 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1088 RouteUI::create_sends (Placement p, bool include_buses)
1090 _session->globally_add_internal_sends (_route, p, include_buses);
1094 RouteUI::create_selected_sends (Placement p, bool include_buses)
1096 boost::shared_ptr<RouteList> rlist (new RouteList);
1097 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1099 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1100 RouteTimeAxisView* rtv;
1102 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1103 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1104 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1105 rlist->push_back (rui->route());
1111 _session->add_internal_sends (_route, p, rlist);
1115 RouteUI::set_sends_gain_from_track ()
1117 _session->globally_set_send_gains_from_track (_route);
1121 RouteUI::set_sends_gain_to_zero ()
1123 _session->globally_set_send_gains_to_zero (_route);
1127 RouteUI::set_sends_gain_to_unity ()
1129 _session->globally_set_send_gains_to_unity (_route);
1133 RouteUI::show_sends_press(GdkEventButton* ev)
1135 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1139 if (!is_track() && show_sends_button) {
1141 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1143 // do nothing on midi sigc::bind event
1146 } else if (Keyboard::is_context_menu_event (ev)) {
1148 if (sends_menu == 0) {
1149 build_sends_menu ();
1152 sends_menu->popup (0, ev->time);
1156 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1159 set_showing_sends_to (boost::shared_ptr<Route> ());
1161 set_showing_sends_to (_route);
1170 RouteUI::show_sends_release (GdkEventButton*)
1176 RouteUI::send_blink (bool onoff)
1178 if (!show_sends_button) {
1183 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1185 show_sends_button->unset_active_state ();
1189 Gtkmm2ext::ActiveState
1190 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1192 boost::shared_ptr<SoloControl> sc = s->solo_control();
1195 return Gtkmm2ext::Off;
1198 if (!sc->can_solo()) {
1199 return Gtkmm2ext::Off;
1203 if (sc->self_soloed()) {
1204 return Gtkmm2ext::ExplicitActive;
1205 } else if (sc->soloed_by_others()) {
1206 return Gtkmm2ext::ImplicitActive;
1208 return Gtkmm2ext::Off;
1212 Gtkmm2ext::ActiveState
1213 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1215 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1218 return Gtkmm2ext::Off;
1221 if (s->is_master() || s->is_monitor()) {
1222 return Gtkmm2ext::Off;
1225 if (sc->solo_isolated()) {
1226 return Gtkmm2ext::ExplicitActive;
1228 return Gtkmm2ext::Off;
1232 Gtkmm2ext::ActiveState
1233 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1235 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1238 return Gtkmm2ext::Off;
1241 if (s->is_master() || s->is_monitor()) {
1242 return Gtkmm2ext::Off;
1245 if (sc->solo_safe()) {
1246 return Gtkmm2ext::ExplicitActive;
1248 return Gtkmm2ext::Off;
1253 RouteUI::update_solo_display ()
1255 bool yn = _route->solo_safe_control()->solo_safe ();
1257 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1258 solo_safe_check->set_active (yn);
1261 yn = _route->solo_isolate_control()->solo_isolated ();
1263 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1264 solo_isolated_check->set_active (yn);
1267 set_button_names ();
1269 if (solo_isolated_led) {
1270 if (_route->solo_isolate_control()->solo_isolated()) {
1271 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1273 solo_isolated_led->unset_active_state ();
1277 if (solo_safe_led) {
1278 if (_route->solo_safe_control()->solo_safe()) {
1279 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1281 solo_safe_led->unset_active_state ();
1285 solo_button->set_active_state (solo_active_state (_route));
1287 /* some changes to solo status can affect mute display, so catch up
1290 update_mute_display ();
1294 RouteUI::solo_changed_so_update_mute ()
1296 update_mute_display ();
1300 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1302 boost::shared_ptr<MuteControl> mc = s->mute_control();
1304 if (s->is_monitor()) {
1305 return Gtkmm2ext::Off;
1309 return Gtkmm2ext::Off;
1312 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1314 if (mc->muted_by_self ()) {
1316 return Gtkmm2ext::ExplicitActive;
1317 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1318 /* this will reflect both solo mutes AND master mutes */
1319 return Gtkmm2ext::ImplicitActive;
1321 /* no mute at all */
1322 return Gtkmm2ext::Off;
1327 if (mc->muted_by_self()) {
1329 return Gtkmm2ext::ExplicitActive;
1330 } else if (mc->muted_by_masters ()) {
1331 /* this shows only master mutes, not mute-by-others-soloing */
1332 return Gtkmm2ext::ImplicitActive;
1334 /* no mute at all */
1335 return Gtkmm2ext::Off;
1339 return ActiveState(0);
1343 RouteUI::update_mute_display ()
1349 mute_button->set_active_state (mute_active_state (_session, _route));
1354 RouteUI::route_rec_enable_changed ()
1356 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1360 RouteUI::session_rec_enable_changed ()
1362 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1366 RouteUI::blink_rec_display (bool blinkOn)
1368 if (!rec_enable_button || !_route) {
1372 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1380 if (track()->rec_enable_control()->get_value()) {
1381 switch (_session->record_status ()) {
1382 case Session::Recording:
1383 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1386 case Session::Disabled:
1387 case Session::Enabled:
1388 if (UIConfiguration::instance().get_blink_rec_arm()) {
1389 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1391 rec_enable_button->set_active_state ( ImplicitActive );
1396 if (step_edit_item) {
1397 step_edit_item->set_sensitive (false);
1401 rec_enable_button->unset_active_state ();
1403 if (step_edit_item) {
1404 step_edit_item->set_sensitive (true);
1408 check_rec_enable_sensitivity ();
1412 RouteUI::build_solo_menu (void)
1414 using namespace Menu_Helpers;
1416 solo_menu = new Menu;
1417 solo_menu->set_name ("ArdourContextMenu");
1418 MenuList& items = solo_menu->items();
1419 Gtk::CheckMenuItem* check;
1421 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1422 check->set_active (_route->solo_isolate_control()->solo_isolated());
1423 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1424 items.push_back (CheckMenuElem(*check));
1425 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1428 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1429 check->set_active (_route->solo_safe_control()->solo_safe());
1430 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1431 items.push_back (CheckMenuElem(*check));
1432 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1437 RouteUI::build_mute_menu(void)
1439 using namespace Menu_Helpers;
1441 mute_menu = new Menu;
1442 mute_menu->set_name ("ArdourContextMenu");
1444 MenuList& items = mute_menu->items();
1446 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1447 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1448 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1449 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1450 pre_fader_mute_check->show_all();
1452 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1453 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1454 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1455 items.push_back (CheckMenuElem(*post_fader_mute_check));
1456 post_fader_mute_check->show_all();
1458 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1459 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1460 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1461 items.push_back (CheckMenuElem(*listen_mute_check));
1462 listen_mute_check->show_all();
1464 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1465 init_mute_menu(MuteMaster::Main, main_mute_check);
1466 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1467 items.push_back (CheckMenuElem(*main_mute_check));
1468 main_mute_check->show_all();
1470 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1474 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1476 check->set_active (_route->mute_control()->mute_points() & mp);
1480 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1482 if (check->get_active()) {
1483 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1485 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1490 RouteUI::muting_change ()
1492 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1495 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1497 yn = (current & MuteMaster::PreFader);
1499 if (pre_fader_mute_check->get_active() != yn) {
1500 pre_fader_mute_check->set_active (yn);
1503 yn = (current & MuteMaster::PostFader);
1505 if (post_fader_mute_check->get_active() != yn) {
1506 post_fader_mute_check->set_active (yn);
1509 yn = (current & MuteMaster::Listen);
1511 if (listen_mute_check->get_active() != yn) {
1512 listen_mute_check->set_active (yn);
1515 yn = (current & MuteMaster::Main);
1517 if (main_mute_check->get_active() != yn) {
1518 main_mute_check->set_active (yn);
1523 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1525 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1529 bool view = solo_isolated_led->active_state();
1530 bool model = _route->solo_isolate_control()->solo_isolated();
1532 /* called BEFORE the view has changed */
1534 if (ev->button == 1) {
1535 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1538 /* disable isolate for all routes */
1539 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1541 /* enable isolate for all routes */
1542 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1547 if (model == view) {
1549 /* flip just this route */
1551 boost::shared_ptr<RouteList> rl (new RouteList);
1552 rl->push_back (_route);
1553 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1562 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1564 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1568 bool view = solo_safe_led->active_state();
1569 bool model = _route->solo_safe_control()->solo_safe();
1571 if (ev->button == 1) {
1572 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1573 boost::shared_ptr<RouteList> rl (_session->get_routes());
1575 /* disable solo safe for all routes */
1576 DisplaySuspender ds;
1577 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1578 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1581 /* enable solo safe for all routes */
1582 DisplaySuspender ds;
1583 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1584 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1589 if (model == view) {
1590 /* flip just this route */
1591 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1600 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1602 bool view = check->get_active();
1603 bool model = _route->solo_isolate_control()->solo_isolated();
1605 /* called AFTER the view has changed */
1607 if (model != view) {
1608 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1613 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1615 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1618 /** Ask the user to choose a colour, and then apply that color to my route */
1620 RouteUI::choose_color ()
1622 _color_picker.popup (_route);
1625 /** Set the route's own color. This may not be used for display if
1626 * the route is in a group which shares its color with its routes.
1629 RouteUI::set_color (uint32_t c)
1631 _route->presentation_info().set_color (c);
1634 /** @return GUI state ID for things that are common to the route in all its representations */
1636 RouteUI::route_state_id () const
1638 return string_compose (X_("route %1"), _route->id().to_s());
1642 RouteUI::set_color_from_route ()
1644 if (_route->presentation_info().color_set()) {
1645 return 0; /* nothing to do */
1648 return 1; /* pick a color */
1651 /** @return true if this name should be used for the route, otherwise false */
1653 RouteUI::verify_new_route_name (const std::string& name)
1655 if (name.find (':') == string::npos) {
1659 MessageDialog colon_msg (
1660 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1661 false, MESSAGE_QUESTION, BUTTONS_NONE
1664 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1665 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1667 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1671 RouteUI::route_rename ()
1673 ArdourWidgets::Prompter name_prompter (true);
1678 name_prompter.set_title (_("Rename Track"));
1680 name_prompter.set_title (_("Rename Bus"));
1682 name_prompter.set_prompt (_("New name:"));
1683 name_prompter.set_initial_text (_route->name());
1684 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1685 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1686 name_prompter.show_all ();
1689 switch (name_prompter.run ()) {
1690 case Gtk::RESPONSE_ACCEPT:
1691 name_prompter.get_result (result);
1692 name_prompter.hide ();
1693 if (result.length()) {
1694 if (verify_new_route_name (result)) {
1695 _route->set_name (result);
1698 /* back to name prompter */
1702 /* nothing entered, just get out of here */
1717 RouteUI::toggle_comment_editor ()
1719 // if (ignore_toggle) {
1723 if (comment_window && comment_window->is_visible ()) {
1724 comment_window->hide ();
1726 open_comment_editor ();
1732 RouteUI::open_comment_editor ()
1734 if (comment_window == 0) {
1735 setup_comment_editor ();
1739 title = _route->name();
1740 title += _(": comment editor");
1742 comment_window->set_title (title);
1743 comment_window->present();
1747 RouteUI::setup_comment_editor ()
1749 comment_window = new ArdourWindow (""); // title will be reset to show route
1750 comment_window->set_skip_taskbar_hint (true);
1751 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1752 comment_window->set_default_size (400, 200);
1754 comment_area = manage (new TextView());
1755 comment_area->set_name ("MixerTrackCommentArea");
1756 comment_area->set_wrap_mode (WRAP_WORD);
1757 comment_area->set_editable (true);
1758 comment_area->get_buffer()->set_text (_route->comment());
1759 comment_area->show ();
1761 comment_window->add (*comment_area);
1765 RouteUI::comment_changed ()
1767 ignore_comment_edit = true;
1769 comment_area->get_buffer()->set_text (_route->comment());
1771 ignore_comment_edit = false;
1775 RouteUI::comment_editor_done_editing ()
1777 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1779 string const str = comment_area->get_buffer()->get_text();
1780 if (str == _route->comment ()) {
1784 _route->set_comment (str, this);
1788 RouteUI::set_route_active (bool a, bool apply_to_selection)
1790 if (apply_to_selection) {
1791 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1793 _route->set_active (a, this);
1798 RouteUI::duplicate_selected_routes ()
1800 ARDOUR_UI::instance()->start_duplicate_routes();
1804 RouteUI::toggle_denormal_protection ()
1806 if (denormal_menu_item) {
1810 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1812 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1813 _route->set_denormal_protection (x);
1819 RouteUI::denormal_protection_changed ()
1821 if (denormal_menu_item) {
1822 denormal_menu_item->set_active (_route->denormal_protection());
1827 RouteUI::disconnect_input ()
1829 _route->input()->disconnect (this);
1833 RouteUI::disconnect_output ()
1835 _route->output()->disconnect (this);
1839 RouteUI::is_track () const
1841 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1844 boost::shared_ptr<Track>
1845 RouteUI::track() const
1847 return boost::dynamic_pointer_cast<Track>(_route);
1851 RouteUI::is_audio_track () const
1853 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1856 boost::shared_ptr<AudioTrack>
1857 RouteUI::audio_track() const
1859 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1863 RouteUI::is_midi_track () const
1865 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1868 boost::shared_ptr<MidiTrack>
1869 RouteUI::midi_track() const
1871 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1875 RouteUI::has_audio_outputs () const
1877 return (_route->n_outputs().n_audio() > 0);
1881 RouteUI::map_frozen ()
1883 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1885 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1888 check_rec_enable_sensitivity ();
1893 RouteUI::adjust_latency ()
1895 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1899 RouteUI::process_save_template_prompter (Prompter& prompter, const std::string& dir)
1902 std::string safe_name;
1905 prompter.get_result (name, true);
1907 safe_name = legalize_for_path (name);
1908 safe_name += template_suffix;
1910 path = Glib::build_filename (dir, safe_name);
1912 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1913 bool overwrite = overwrite_file_dialog (prompter,
1914 _("Confirm Template Overwrite"),
1915 _("A template already exists with that name. Do you want to overwrite it?"));
1922 _route->save_as_template (path, name);
1928 RouteUI::save_as_template ()
1932 dir = ARDOUR::user_route_template_directory ();
1934 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1935 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1939 Prompter prompter (true); // modal
1941 prompter.set_title (_("Save As Template"));
1942 prompter.set_prompt (_("Template name:"));
1943 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1945 bool finished = false;
1947 switch (prompter.run()) {
1948 case RESPONSE_ACCEPT:
1949 finished = process_save_template_prompter (prompter, dir);
1959 RouteUI::check_rec_enable_sensitivity ()
1961 if (!rec_enable_button) {
1962 assert (0); // This should not happen
1965 if (!_session->writable()) {
1966 rec_enable_button->set_sensitive (false);
1970 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1971 rec_enable_button->set_sensitive (false);
1972 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1973 rec_enable_button->set_sensitive (false);
1975 rec_enable_button->set_sensitive (true);
1977 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1978 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1980 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1982 update_monitoring_display ();
1986 RouteUI::parameter_changed (string const & p)
1988 /* this handles RC and per-session parameter changes */
1990 if (p == "disable-disarm-during-roll") {
1991 check_rec_enable_sensitivity ();
1992 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1993 set_button_names ();
1994 } else if (p == "session-monitoring") {
1995 update_monitoring_display ();
1996 } else if (p == "auto-input") {
1997 update_monitoring_display ();
1998 } else if (p == "blink-rec-arm") {
1999 if (UIConfiguration::instance().get_blink_rec_arm()) {
2000 rec_blink_connection.disconnect ();
2001 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2003 rec_blink_connection.disconnect ();
2004 RouteUI::blink_rec_display(false);
2010 RouteUI::setup_invert_buttons ()
2012 /* remove old invert buttons */
2013 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2014 _invert_button_box.remove (**i);
2017 _invert_buttons.clear ();
2019 if (!_route || !_route->input()) {
2023 uint32_t const N = _route->input()->n_ports().n_audio ();
2025 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2027 for (uint32_t i = 0; i < to_add; ++i) {
2028 ArdourButton* b = manage (new ArdourButton);
2029 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2030 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2032 b->set_name (X_("invert button"));
2035 b->set_text (string_compose (X_("Ø (%1)"), N));
2037 b->set_text (X_("Ø"));
2040 b->set_text (string_compose (X_("Ø%1"), i + 1));
2043 if (N <= _max_invert_buttons) {
2044 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));
2046 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2049 _invert_buttons.push_back (b);
2050 _invert_button_box.pack_start (*b);
2053 _invert_button_box.set_spacing (1);
2054 _invert_button_box.show_all ();
2058 RouteUI::set_invert_button_state ()
2060 uint32_t const N = _route->input()->n_ports().n_audio();
2061 if (N > _max_invert_buttons) {
2063 /* One button for many channels; explicit active if all channels are inverted,
2064 implicit active if some are, off if none are.
2067 ArdourButton* b = _invert_buttons.front ();
2069 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2070 b->set_active_state (Gtkmm2ext::ExplicitActive);
2071 } else if (_route->phase_control()->any()) {
2072 b->set_active_state (Gtkmm2ext::ImplicitActive);
2074 b->set_active_state (Gtkmm2ext::Off);
2079 /* One button per channel; just set active */
2082 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2083 (*i)->set_active (_route->phase_control()->inverted (j));
2090 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2092 if (ev->button == 1 && i < _invert_buttons.size()) {
2093 uint32_t const N = _route->input()->n_ports().n_audio ();
2094 if (N <= _max_invert_buttons) {
2095 /* left-click inverts phase so long as we have a button per channel */
2096 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2105 RouteUI::invert_press (GdkEventButton* ev)
2107 using namespace Menu_Helpers;
2109 uint32_t const N = _route->input()->n_ports().n_audio();
2110 if (N <= _max_invert_buttons && ev->button != 3) {
2111 /* If we have an invert button per channel, we only pop
2112 up a menu on right-click; left click is handled
2118 delete _invert_menu;
2119 _invert_menu = new Menu;
2120 _invert_menu->set_name ("ArdourContextMenu");
2121 MenuList& items = _invert_menu->items ();
2123 for (uint32_t i = 0; i < N; ++i) {
2124 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2125 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2126 ++_i_am_the_modifier;
2127 e->set_active (_route->phase_control()->inverted (i));
2128 --_i_am_the_modifier;
2131 _invert_menu->popup (0, ev->time);
2137 RouteUI::invert_menu_toggled (uint32_t c)
2139 if (_i_am_the_modifier) {
2144 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2148 RouteUI::set_invert_sensitive (bool yn)
2150 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2151 (*b)->set_sensitive (yn);
2155 /** The Route's gui_changed signal has been emitted */
2157 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2159 if (what_changed.contains (Properties::color)) {
2160 if (set_color_from_route () == 0) {
2161 route_color_changed ();
2167 RouteUI::track_mode_changed (void)
2170 switch (track()->mode()) {
2171 case ARDOUR::NonLayered:
2172 case ARDOUR::Normal:
2173 rec_enable_button->set_icon (ArdourIcon::RecButton);
2175 case ARDOUR::Destructive:
2176 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2179 rec_enable_button->queue_draw();
2182 /** @return the color that this route should use; it maybe its own,
2183 * or it maybe that of its route group.
2186 RouteUI::route_color () const
2189 RouteGroup* g = _route->route_group ();
2192 if (g && g->is_color()) {
2193 set_color_from_rgba (c, GroupTabs::group_color (g));
2195 set_color_from_rgba (c, _route->presentation_info().color());
2202 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2204 _showing_sends_to = send_to;
2205 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2209 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2211 if (_route == send_to) {
2212 show_sends_button->set_active (true);
2213 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2215 show_sends_button->set_active (false);
2216 send_blink_connection.disconnect ();
2221 RouteUI::route_group() const
2223 return _route->route_group();
2227 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2228 : WM::ProxyBase (name, string())
2229 , _route (boost::weak_ptr<Route> (route))
2231 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2234 RoutePinWindowProxy::~RoutePinWindowProxy()
2239 ARDOUR::SessionHandlePtr*
2240 RoutePinWindowProxy::session_handle ()
2242 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2243 if (aw) { return aw; }
2248 RoutePinWindowProxy::get (bool create)
2250 boost::shared_ptr<Route> r = _route.lock ();
2259 _window = new PluginPinDialog (r);
2260 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2262 aw->set_session (_session);
2264 _window->show_all ();
2270 RoutePinWindowProxy::route_going_away ()
2274 WM::Manager::instance().remove (this);
2275 going_away_connection.disconnect();
2280 RouteUI::maybe_add_route_print_mgr ()
2282 if (_route->pinmgr_proxy ()) {
2285 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2286 string_compose ("RPM-%1", _route->id()), _route);
2287 wp->set_session (_session);
2289 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2291 wp->set_state (*ui_xml, 0);
2295 void* existing_ui = _route->pinmgr_proxy ();
2297 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2300 _route->set_pingmgr_proxy (wp);
2302 WM::Manager::instance().register_window (wp);
2306 RouteUI::manage_pins ()
2308 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2316 RouteUI::fan_out (bool to_busses, bool group)
2318 DisplaySuspender ds;
2319 boost::shared_ptr<ARDOUR::Route> route = _route;
2320 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2323 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2324 if (route->n_outputs ().n_audio () != n_outputs) {
2325 MessageDialog msg (string_compose (
2326 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2327 n_outputs, route->n_outputs ().n_audio ()));
2332 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2334 /* count busses and channels/bus */
2335 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2336 std::map<std::string, uint32_t> busnames;
2337 for (uint32_t p = 0; p < n_outputs; ++p) {
2338 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2339 std::string bn = BUSNAME;
2343 if (busnames.size () < 2) {
2344 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2349 uint32_t outputs = 2;
2350 if (_session->master_out ()) {
2351 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2354 route->output ()->disconnect (this);
2355 route->panner_shell ()->set_bypassed (true);
2358 for (uint32_t p = 0; p < n_outputs; ++p) {
2359 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2360 std::string bn = BUSNAME;
2361 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2364 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2368 list<boost::shared_ptr<AudioTrack> > tl =
2369 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2373 boost::shared_ptr<ControlList> cl (new ControlList);
2374 cl->push_back (r->monitoring_control ());
2375 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2377 r->input ()->disconnect (this);
2379 to_group.push_back (r);
2380 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2385 RouteGroup* rg = NULL;
2386 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2387 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2388 if ((*i)->name () == pi->name ()) {
2394 rg = new RouteGroup (*_session, pi->name ());
2395 _session->add_route_group (rg);
2396 rg->set_gain (false);
2399 GroupTabs::set_group_color (rg, route->presentation_info().color());
2400 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2407 RouteUI::mark_hidden (bool yn)
2409 if (yn != _route->presentation_info().hidden()) {
2410 _route->presentation_info().set_hidden (yn);
2411 return true; // things changed
2416 boost::shared_ptr<Stripable>
2417 RouteUI::stripable () const