2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <boost/algorithm/string.hpp>
23 #include <gtkmm2ext/gtk_ui.h>
24 #include <gtkmm2ext/choice.h>
25 #include <gtkmm2ext/doi.h>
26 #include <gtkmm2ext/bindable_button.h>
27 #include <gtkmm2ext/barcontroller.h>
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
31 #include "pbd/memento_command.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour/dB.h"
37 #include "ardour/route_group.h"
38 #include "ardour/solo_isolate_control.h"
39 #include "ardour/vca.h"
40 #include "ardour/vca_manager.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/filename_extensions.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/monitor_control.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/profile.h"
50 #include "ardour/phase_control.h"
51 #include "ardour/send.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/template_utils.h"
56 #include "ardour_button.h"
57 #include "ardour_dialog.h"
58 #include "ardour_ui.h"
59 #include "automation_time_axis.h"
61 #include "group_tabs.h"
62 #include "gui_object.h"
63 #include "gui_thread.h"
65 #include "latency_gui.h"
66 #include "mixer_strip.h"
67 #include "plugin_pin_dialog.h"
69 #include "rgb_macros.h"
70 #include "route_time_axis.h"
73 #include "ui_config.h"
79 using namespace Gtkmm2ext;
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
85 uint32_t RouteUI::_max_invert_buttons = 3;
86 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
87 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
88 std::string RouteUI::program_port_prefix;
90 RouteUI::RouteUI (ARDOUR::Session* sess)
91 : monitor_input_button (0)
92 , monitor_disk_button (0)
100 , output_selector (0)
103 if (program_port_prefix.empty()) {
104 // compare to gtk2_ardour/port_group.cc
105 string lpn (PROGRAM_NAME);
106 boost::to_lower (lpn);
107 program_port_prefix = lpn + ":"; // e.g. "ardour:"
118 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
121 _route.reset (); /* drop reference to route, so that it can be cleaned up */
122 route_connections.drop_connections ();
128 delete comment_window;
129 delete input_selector;
130 delete output_selector;
131 delete monitor_input_button;
132 delete monitor_disk_button;
135 send_blink_connection.disconnect ();
136 rec_blink_connection.disconnect ();
142 self_destruct = true;
148 pre_fader_mute_check = 0;
149 post_fader_mute_check = 0;
150 listen_mute_check = 0;
153 solo_isolated_check = 0;
154 solo_isolated_led = 0;
158 denormal_menu_item = 0;
161 multiple_mute_change = false;
162 multiple_solo_change = false;
163 _i_am_the_modifier = 0;
168 setup_invert_buttons ();
170 mute_button = manage (new ArdourButton);
171 mute_button->set_name ("mute button");
172 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
174 solo_button = manage (new ArdourButton);
175 solo_button->set_name ("solo button");
176 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
177 solo_button->set_no_show_all (true);
179 rec_enable_button = manage (new ArdourButton);
180 rec_enable_button->set_name ("record enable button");
181 rec_enable_button->set_icon (ArdourIcon::RecButton);
182 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
184 if (UIConfiguration::instance().get_blink_rec_arm()) {
185 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
188 show_sends_button = manage (new ArdourButton);
189 show_sends_button->set_name ("send alert button");
190 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
192 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
193 monitor_input_button->set_name ("monitor button");
194 monitor_input_button->set_text (_("In"));
195 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
196 monitor_input_button->set_no_show_all (true);
198 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_disk_button->set_name ("monitor button");
200 monitor_disk_button->set_text (_("Disk"));
201 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
202 monitor_disk_button->set_no_show_all (true);
204 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
205 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
206 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
208 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
209 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
212 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
213 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
215 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
216 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
218 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
219 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
220 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
221 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
223 monitor_input_button->set_distinct_led_click (false);
224 monitor_disk_button->set_distinct_led_click (false);
226 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
227 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
229 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
230 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
232 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
238 route_connections.drop_connections ();
246 denormal_menu_item = 0;
250 RouteUI::self_delete ()
256 RouteUI::set_route (boost::shared_ptr<Route> rp)
262 if ( !_route->presentation_info().color_set() ) {
263 /* deal with older 4.x color, which was stored in the GUI object state */
265 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
269 /* old v4.x or earlier session. Use this information */
271 int red, green, blue;
276 /* old color format version was:
278 16bit value for red:16 bit value for green:16 bit value for blue
293 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
297 if (set_color_from_route()) {
298 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
302 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
305 delete input_selector;
308 delete output_selector;
311 mute_button->set_controllable (_route->mute_control());
312 solo_button->set_controllable (_route->solo_control());
314 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
316 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
318 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
319 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
320 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
321 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
322 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
323 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
326 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
327 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
328 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
330 track_mode_changed();
334 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
335 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
337 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
339 if (_session->writable() && is_track()) {
340 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
342 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
343 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
345 rec_enable_button->show();
346 rec_enable_button->set_controllable (t->rec_enable_control());
348 if (is_midi_track()) {
349 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
350 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
355 /* this will work for busses and tracks, and needs to be called to
356 set up the name entry/name label display.
360 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
361 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
363 update_monitoring_display ();
366 mute_button->unset_flags (Gtk::CAN_FOCUS);
367 solo_button->unset_flags (Gtk::CAN_FOCUS);
371 if (_route->is_monitor() || _route->is_master()) {
372 solo_button->hide ();
379 setup_invert_buttons ();
380 set_invert_button_state ();
382 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
383 bus_send_display_changed (s);
385 update_mute_display ();
386 update_solo_display ();
388 if (!UIConfiguration::instance().get_blink_rec_arm()) {
389 blink_rec_display(true); // set initial rec-en button state
392 check_rec_enable_sensitivity ();
393 maybe_add_route_print_mgr ();
394 route_color_changed();
395 route_gui_changed (PropertyChange (Properties::selected));
399 RouteUI::polarity_changed ()
405 set_invert_button_state ();
409 RouteUI::mute_press (GdkEventButton* ev)
411 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
415 //if this is a binding action, let the ArdourButton handle it
416 if ( BindingProxy::is_bind_action(ev) )
419 multiple_mute_change = false;
421 if (Keyboard::is_context_menu_event (ev)) {
427 mute_menu->popup(0,ev->time);
433 if (Keyboard::is_button2_event (ev)) {
434 // button2-click is "momentary"
436 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
439 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
441 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
443 /* toggle mute on everything (but
444 * exclude the master and monitor)
446 * because we are going to erase
447 * elements of the list we need to work
451 boost::shared_ptr<RouteList> copy (new RouteList);
453 *copy = *_session->get_routes ();
455 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
456 if ((*i)->is_master() || (*i)->is_monitor()) {
464 _mute_release->routes = copy;
467 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
469 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
471 /* Primary-button1 inverts the implication of
472 the group being active. If the group is
473 active (for mute), then this modifier means
474 "do not apply to mute". If the group is
475 inactive (for mute), then this modifier
476 means "apply to route". This is all
477 accomplished by passing just the actual
478 route, along with the InverseGroup group
481 NOTE: Primary-button2 is MIDI learn.
484 boost::shared_ptr<RouteList> rl;
486 if (ev->button == 1) {
488 rl.reset (new RouteList);
489 rl->push_back (_route);
492 _mute_release->routes = rl;
495 boost::shared_ptr<MuteControl> mc = _route->mute_control();
496 mc->start_touch (_session->audible_frame ());
497 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
502 /* plain click applies change to this route */
504 boost::shared_ptr<RouteList> rl (new RouteList);
505 rl->push_back (_route);
508 _mute_release->routes = rl;
511 boost::shared_ptr<MuteControl> mc = _route->mute_control();
512 mc->start_touch (_session->audible_frame ());
513 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
522 RouteUI::mute_release (GdkEventButton* /*ev*/)
525 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
526 delete _mute_release;
530 _route->mute_control()->stop_touch (false, _session->audible_frame ());
536 RouteUI::edit_output_configuration ()
538 if (output_selector == 0) {
540 boost::shared_ptr<Send> send;
541 boost::shared_ptr<IO> output;
543 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
544 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
545 output = send->output();
547 output = _route->output ();
550 output = _route->output ();
553 output_selector = new IOSelectorWindow (_session, output);
556 if (output_selector->is_visible()) {
557 output_selector->get_toplevel()->get_window()->raise();
559 output_selector->present ();
562 //output_selector->set_keep_above (true);
566 RouteUI::edit_input_configuration ()
568 if (input_selector == 0) {
569 input_selector = new IOSelectorWindow (_session, _route->input());
572 if (input_selector->is_visible()) {
573 input_selector->get_toplevel()->get_window()->raise();
575 input_selector->present ();
578 //input_selector->set_keep_above (true);
582 RouteUI::solo_press(GdkEventButton* ev)
584 /* ignore double/triple clicks */
586 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
590 //if this is a binding action, let the ArdourButton handle it
591 if ( BindingProxy::is_bind_action(ev) )
594 multiple_solo_change = false;
596 if (Keyboard::is_context_menu_event (ev)) {
598 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
599 ! (solo_safe_led && solo_safe_led->is_visible())) {
601 if (solo_menu == 0) {
605 solo_menu->popup (1, ev->time);
610 if (Keyboard::is_button2_event (ev)) {
612 // button2-click is "momentary"
613 _solo_release = new SoloMuteRelease (_route->self_soloed());
616 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
618 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
620 /* Primary-Tertiary-click applies change to all routes */
623 _solo_release->routes = _session->get_routes ();
626 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
628 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
630 // Primary-Secondary-click: exclusively solo this track
633 _solo_release->exclusive = true;
635 boost::shared_ptr<RouteList> routes = _session->get_routes();
637 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
638 if ((*i)->soloed ()) {
639 _solo_release->routes_on->push_back (*i);
641 _solo_release->routes_off->push_back (*i);
646 if (Config->get_solo_control_is_listen_control()) {
647 /* ??? we need a just_one_listen() method */
650 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
653 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
655 // shift-click: toggle solo isolated status
657 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
658 delete _solo_release;
661 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
663 /* Primary-button1: solo mix group.
664 NOTE: Primary-button2 is MIDI learn.
667 /* Primary-button1 applies change to the mix group even if it is not active
668 NOTE: Primary-button2 is MIDI learn.
671 boost::shared_ptr<RouteList> rl;
673 if (ev->button == 1) {
675 /* Primary-button1 inverts the implication of
676 the group being active. If the group is
677 active (for solo), then this modifier means
678 "do not apply to solo". If the group is
679 inactive (for mute), then this modifier
680 means "apply to route". This is all
681 accomplished by passing just the actual
682 route, along with the InverseGroup group
685 NOTE: Primary-button2 is MIDI learn.
688 rl.reset (new RouteList);
689 rl->push_back (_route);
692 _solo_release->routes = rl;
695 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
698 delete _solo_release;
703 /* click: solo this route */
705 boost::shared_ptr<RouteList> rl (new RouteList);
706 rl->push_back (route());
709 _solo_release->routes = rl;
712 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
721 RouteUI::solo_release (GdkEventButton* /*ev*/)
725 if (_solo_release->exclusive) {
728 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
731 delete _solo_release;
739 RouteUI::rec_enable_press(GdkEventButton* ev)
741 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
745 //if this is a binding action, let the ArdourButton handle it
746 if ( BindingProxy::is_bind_action(ev) )
749 if (!_session->engine().connected()) {
750 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
755 if (is_midi_track()) {
757 /* rec-enable button exits from step editing */
759 if (midi_track()->step_editing()) {
760 midi_track()->set_step_editing (false);
765 if (is_track() && rec_enable_button) {
767 if (Keyboard::is_button2_event (ev)) {
769 //rec arm does not have a momentary mode
772 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
774 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
776 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
778 /* Primary-button1 applies change to the route group (even if it is not active)
779 NOTE: Primary-button2 is MIDI learn.
782 if (ev->button == 1) {
784 boost::shared_ptr<RouteList> rl;
786 rl.reset (new RouteList);
787 rl->push_back (_route);
789 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
792 } else if (Keyboard::is_context_menu_event (ev)) {
794 /* do this on release */
798 boost::shared_ptr<Track> trk = track();
799 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
807 RouteUI::update_monitoring_display ()
813 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
819 MonitorState ms = t->monitoring_state();
821 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
822 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
824 if (ms & MonitoringInput) {
825 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
827 monitor_input_button->unset_active_state ();
831 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
832 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
834 if (ms & MonitoringDisk) {
835 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
837 monitor_disk_button->unset_active_state ();
843 RouteUI::monitor_input_press(GdkEventButton*)
849 RouteUI::monitor_input_release(GdkEventButton* ev)
851 return monitor_release (ev, MonitorInput);
855 RouteUI::monitor_disk_press (GdkEventButton*)
861 RouteUI::monitor_disk_release (GdkEventButton* ev)
863 return monitor_release (ev, MonitorDisk);
867 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
869 if (ev->button != 1) {
873 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
880 boost::shared_ptr<RouteList> rl;
882 /* XXX for now, monitoring choices are orthogonal. cue monitoring
883 will follow in 3.X but requires mixing the input and playback (disk)
884 signal together, which requires yet more buffers.
887 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
888 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
890 /* this line will change when the options are non-orthogonal */
891 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
895 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
896 rl = _session->get_routes ();
898 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
899 if (_route->route_group() && _route->route_group()->is_monitoring()) {
900 rl = _route->route_group()->route_list();
902 rl.reset (new RouteList);
903 rl->push_back (route());
906 rl.reset (new RouteList);
907 rl->push_back (route());
910 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
916 RouteUI::build_record_menu ()
919 record_menu = new Menu;
920 record_menu->set_name ("ArdourContextMenu");
921 using namespace Menu_Helpers;
922 MenuList& items = record_menu->items();
924 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
925 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
927 if (is_midi_track()) {
928 items.push_back (SeparatorElem());
929 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
930 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
934 if (step_edit_item) {
935 if (track()->rec_enable_control()->get_value()) {
936 step_edit_item->set_sensitive (false);
938 step_edit_item->set_active (midi_track()->step_editing());
941 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
942 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
947 RouteUI::toggle_step_edit ()
949 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
953 midi_track()->set_step_editing (step_edit_item->get_active());
957 RouteUI::toggle_rec_safe ()
959 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
965 /* This check is made inside the control too, but dong it here can't
969 if (_route->rec_enable_control()->get_value()) {
973 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
977 RouteUI::step_edit_changed (bool yn)
980 if (rec_enable_button) {
981 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
984 start_step_editing ();
986 if (step_edit_item) {
987 step_edit_item->set_active (true);
992 if (rec_enable_button) {
993 rec_enable_button->unset_active_state ();
996 stop_step_editing ();
998 if (step_edit_item) {
999 step_edit_item->set_active (false);
1005 RouteUI::rec_enable_release (GdkEventButton* ev)
1007 if (Keyboard::is_context_menu_event (ev)) {
1008 build_record_menu ();
1010 record_menu->popup (1, ev->time);
1019 RouteUI::build_sends_menu ()
1021 using namespace Menu_Helpers;
1023 sends_menu = new Menu;
1024 sends_menu->set_name ("ArdourContextMenu");
1025 MenuList& items = sends_menu->items();
1028 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1032 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1036 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1040 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1044 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1048 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1051 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1055 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1058 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1059 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1060 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1065 RouteUI::create_sends (Placement p, bool include_buses)
1067 _session->globally_add_internal_sends (_route, p, include_buses);
1071 RouteUI::create_selected_sends (Placement p, bool include_buses)
1073 boost::shared_ptr<RouteList> rlist (new RouteList);
1074 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1076 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1077 RouteTimeAxisView* rtv;
1079 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1080 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1081 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1082 rlist->push_back (rui->route());
1088 _session->add_internal_sends (_route, p, rlist);
1092 RouteUI::set_sends_gain_from_track ()
1094 _session->globally_set_send_gains_from_track (_route);
1098 RouteUI::set_sends_gain_to_zero ()
1100 _session->globally_set_send_gains_to_zero (_route);
1104 RouteUI::set_sends_gain_to_unity ()
1106 _session->globally_set_send_gains_to_unity (_route);
1110 RouteUI::show_sends_press(GdkEventButton* ev)
1112 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1116 if (!is_track() && show_sends_button) {
1118 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1120 // do nothing on midi sigc::bind event
1123 } else if (Keyboard::is_context_menu_event (ev)) {
1125 if (sends_menu == 0) {
1126 build_sends_menu ();
1129 sends_menu->popup (0, ev->time);
1133 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1136 set_showing_sends_to (boost::shared_ptr<Route> ());
1138 set_showing_sends_to (_route);
1147 RouteUI::show_sends_release (GdkEventButton*)
1153 RouteUI::send_blink (bool onoff)
1155 if (!show_sends_button) {
1160 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1162 show_sends_button->unset_active_state ();
1166 Gtkmm2ext::ActiveState
1167 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1169 boost::shared_ptr<SoloControl> sc = s->solo_control();
1172 return Gtkmm2ext::Off;
1175 if (!sc->can_solo()) {
1176 return Gtkmm2ext::Off;
1180 if (sc->self_soloed()) {
1181 return Gtkmm2ext::ExplicitActive;
1182 } else if (sc->soloed_by_others()) {
1183 return Gtkmm2ext::ImplicitActive;
1185 return Gtkmm2ext::Off;
1189 Gtkmm2ext::ActiveState
1190 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1192 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1195 return Gtkmm2ext::Off;
1198 if (s->is_master() || s->is_monitor()) {
1199 return Gtkmm2ext::Off;
1202 if (sc->solo_isolated()) {
1203 return Gtkmm2ext::ExplicitActive;
1205 return Gtkmm2ext::Off;
1209 Gtkmm2ext::ActiveState
1210 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1212 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1215 return Gtkmm2ext::Off;
1218 if (s->is_master() || s->is_monitor()) {
1219 return Gtkmm2ext::Off;
1222 if (sc->solo_safe()) {
1223 return Gtkmm2ext::ExplicitActive;
1225 return Gtkmm2ext::Off;
1230 RouteUI::update_solo_display ()
1232 bool yn = _route->solo_safe_control()->solo_safe ();
1234 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1235 solo_safe_check->set_active (yn);
1238 yn = _route->solo_isolate_control()->solo_isolated ();
1240 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1241 solo_isolated_check->set_active (yn);
1244 set_button_names ();
1246 if (solo_isolated_led) {
1247 if (_route->solo_isolate_control()->solo_isolated()) {
1248 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1250 solo_isolated_led->unset_active_state ();
1254 if (solo_safe_led) {
1255 if (_route->solo_safe_control()->solo_safe()) {
1256 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1258 solo_safe_led->unset_active_state ();
1262 solo_button->set_active_state (solo_active_state (_route));
1264 /* some changes to solo status can affect mute display, so catch up
1267 update_mute_display ();
1271 RouteUI::solo_changed_so_update_mute ()
1273 update_mute_display ();
1277 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1279 boost::shared_ptr<MuteControl> mc = s->mute_control();
1281 if (s->is_monitor()) {
1282 return Gtkmm2ext::Off;
1286 return Gtkmm2ext::Off;
1289 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1291 if (mc->muted_by_self ()) {
1293 return Gtkmm2ext::ExplicitActive;
1294 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1295 /* this will reflect both solo mutes AND master mutes */
1296 return Gtkmm2ext::ImplicitActive;
1298 /* no mute at all */
1299 return Gtkmm2ext::Off;
1304 if (mc->muted_by_self()) {
1306 return Gtkmm2ext::ExplicitActive;
1307 } else if (mc->muted_by_masters ()) {
1308 /* this shows only master mutes, not mute-by-others-soloing */
1309 return Gtkmm2ext::ImplicitActive;
1311 /* no mute at all */
1312 return Gtkmm2ext::Off;
1316 return ActiveState(0);
1320 RouteUI::update_mute_display ()
1326 mute_button->set_active_state (mute_active_state (_session, _route));
1331 RouteUI::route_rec_enable_changed ()
1333 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1337 RouteUI::session_rec_enable_changed ()
1339 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1343 RouteUI::blink_rec_display (bool blinkOn)
1345 if (!rec_enable_button || !_route) {
1349 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1357 if (track()->rec_enable_control()->get_value()) {
1358 switch (_session->record_status ()) {
1359 case Session::Recording:
1360 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1363 case Session::Disabled:
1364 case Session::Enabled:
1365 if (UIConfiguration::instance().get_blink_rec_arm()) {
1366 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1368 rec_enable_button->set_active_state ( ImplicitActive );
1373 if (step_edit_item) {
1374 step_edit_item->set_sensitive (false);
1378 rec_enable_button->unset_active_state ();
1380 if (step_edit_item) {
1381 step_edit_item->set_sensitive (true);
1385 check_rec_enable_sensitivity ();
1389 RouteUI::build_solo_menu (void)
1391 using namespace Menu_Helpers;
1393 solo_menu = new Menu;
1394 solo_menu->set_name ("ArdourContextMenu");
1395 MenuList& items = solo_menu->items();
1396 Gtk::CheckMenuItem* check;
1398 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1399 check->set_active (_route->solo_isolate_control()->solo_isolated());
1400 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1401 items.push_back (CheckMenuElem(*check));
1402 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1405 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1406 check->set_active (_route->solo_safe_control()->solo_safe());
1407 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1408 items.push_back (CheckMenuElem(*check));
1409 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1412 //items.push_back (SeparatorElem());
1413 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1418 RouteUI::build_mute_menu(void)
1420 using namespace Menu_Helpers;
1422 mute_menu = new Menu;
1423 mute_menu->set_name ("ArdourContextMenu");
1425 MenuList& items = mute_menu->items();
1427 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1428 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1429 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1430 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1431 pre_fader_mute_check->show_all();
1433 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1434 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1435 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1436 items.push_back (CheckMenuElem(*post_fader_mute_check));
1437 post_fader_mute_check->show_all();
1439 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1440 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1441 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1442 items.push_back (CheckMenuElem(*listen_mute_check));
1443 listen_mute_check->show_all();
1445 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1446 init_mute_menu(MuteMaster::Main, main_mute_check);
1447 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1448 items.push_back (CheckMenuElem(*main_mute_check));
1449 main_mute_check->show_all();
1451 //items.push_back (SeparatorElem());
1452 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1454 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1458 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1460 check->set_active (_route->mute_control()->mute_points() & mp);
1464 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1466 if (check->get_active()) {
1467 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1469 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1474 RouteUI::muting_change ()
1476 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1479 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1481 yn = (current & MuteMaster::PreFader);
1483 if (pre_fader_mute_check->get_active() != yn) {
1484 pre_fader_mute_check->set_active (yn);
1487 yn = (current & MuteMaster::PostFader);
1489 if (post_fader_mute_check->get_active() != yn) {
1490 post_fader_mute_check->set_active (yn);
1493 yn = (current & MuteMaster::Listen);
1495 if (listen_mute_check->get_active() != yn) {
1496 listen_mute_check->set_active (yn);
1499 yn = (current & MuteMaster::Main);
1501 if (main_mute_check->get_active() != yn) {
1502 main_mute_check->set_active (yn);
1507 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1509 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1513 bool view = solo_isolated_led->active_state();
1514 bool model = _route->solo_isolate_control()->solo_isolated();
1516 /* called BEFORE the view has changed */
1518 if (ev->button == 1) {
1519 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1522 /* disable isolate for all routes */
1523 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1525 /* enable isolate for all routes */
1526 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1531 if (model == view) {
1533 /* flip just this route */
1535 boost::shared_ptr<RouteList> rl (new RouteList);
1536 rl->push_back (_route);
1537 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1546 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1548 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1552 bool view = solo_safe_led->active_state();
1553 bool model = _route->solo_safe_control()->solo_safe();
1555 if (ev->button == 1) {
1556 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1557 boost::shared_ptr<RouteList> rl (_session->get_routes());
1559 /* disable solo safe for all routes */
1560 DisplaySuspender ds;
1561 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1562 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1565 /* enable solo safe for all routes */
1566 DisplaySuspender ds;
1567 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1568 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1573 if (model == view) {
1574 /* flip just this route */
1575 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1584 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1586 bool view = check->get_active();
1587 bool model = _route->solo_isolate_control()->solo_isolated();
1589 /* called AFTER the view has changed */
1591 if (model != view) {
1592 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1597 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1599 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1602 /** Ask the user to choose a colour, and then apply that color to my route
1605 RouteUI::choose_color ()
1608 Gdk::Color c (gdk_color_from_rgba (_route->presentation_info().color()));
1609 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1612 set_color (gdk_color_to_rgba (color));
1616 /** Set the route's own color. This may not be used for display if
1617 * the route is in a group which shares its color with its routes.
1620 RouteUI::set_color (uint32_t c)
1622 _route->presentation_info().set_color (c);
1625 /** @return GUI state ID for things that are common to the route in all its representations */
1627 RouteUI::route_state_id () const
1629 return string_compose (X_("route %1"), _route->id().to_s());
1633 RouteUI::set_color_from_route ()
1635 if (_route->presentation_info().color_set()) {
1636 return 0; /* nothing to do */
1639 return 1; /* pick a color */
1642 /** @return true if this name should be used for the route, otherwise false */
1644 RouteUI::verify_new_route_name (const std::string& name)
1646 if (name.find (':') == string::npos) {
1650 MessageDialog colon_msg (
1651 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1652 false, MESSAGE_QUESTION, BUTTONS_NONE
1655 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1656 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1658 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1662 RouteUI::route_rename ()
1664 ArdourPrompter name_prompter (true);
1669 name_prompter.set_title (_("Rename Track"));
1671 name_prompter.set_title (_("Rename Bus"));
1673 name_prompter.set_prompt (_("New name:"));
1674 name_prompter.set_initial_text (_route->name());
1675 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1676 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1677 name_prompter.show_all ();
1680 switch (name_prompter.run ()) {
1681 case Gtk::RESPONSE_ACCEPT:
1682 name_prompter.get_result (result);
1683 name_prompter.hide ();
1684 if (result.length()) {
1685 if (verify_new_route_name (result)) {
1686 _route->set_name (result);
1689 /* back to name prompter */
1693 /* nothing entered, just get out of here */
1708 RouteUI::toggle_comment_editor ()
1710 // if (ignore_toggle) {
1714 if (comment_window && comment_window->is_visible ()) {
1715 comment_window->hide ();
1717 open_comment_editor ();
1723 RouteUI::open_comment_editor ()
1725 if (comment_window == 0) {
1726 setup_comment_editor ();
1730 title = _route->name();
1731 title += _(": comment editor");
1733 comment_window->set_title (title);
1734 comment_window->present();
1738 RouteUI::setup_comment_editor ()
1740 comment_window = new ArdourWindow (""); // title will be reset to show route
1741 comment_window->set_skip_taskbar_hint (true);
1742 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1743 comment_window->set_default_size (400, 200);
1745 comment_area = manage (new TextView());
1746 comment_area->set_name ("MixerTrackCommentArea");
1747 comment_area->set_wrap_mode (WRAP_WORD);
1748 comment_area->set_editable (true);
1749 comment_area->get_buffer()->set_text (_route->comment());
1750 comment_area->show ();
1752 comment_window->add (*comment_area);
1756 RouteUI::comment_changed ()
1758 ignore_comment_edit = true;
1760 comment_area->get_buffer()->set_text (_route->comment());
1762 ignore_comment_edit = false;
1766 RouteUI::comment_editor_done_editing ()
1768 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1770 string const str = comment_area->get_buffer()->get_text();
1771 if (str == _route->comment ()) {
1775 _route->set_comment (str, this);
1779 RouteUI::set_route_active (bool a, bool apply_to_selection)
1781 if (apply_to_selection) {
1782 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1784 _route->set_active (a, this);
1789 RouteUI::duplicate_selected_routes ()
1791 ARDOUR_UI::instance()->start_duplicate_routes();
1795 RouteUI::toggle_denormal_protection ()
1797 if (denormal_menu_item) {
1801 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1803 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1804 _route->set_denormal_protection (x);
1810 RouteUI::denormal_protection_changed ()
1812 if (denormal_menu_item) {
1813 denormal_menu_item->set_active (_route->denormal_protection());
1818 RouteUI::disconnect_input ()
1820 _route->input()->disconnect (this);
1824 RouteUI::disconnect_output ()
1826 _route->output()->disconnect (this);
1830 RouteUI::is_track () const
1832 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1835 boost::shared_ptr<Track>
1836 RouteUI::track() const
1838 return boost::dynamic_pointer_cast<Track>(_route);
1842 RouteUI::is_audio_track () const
1844 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1847 boost::shared_ptr<AudioTrack>
1848 RouteUI::audio_track() const
1850 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1854 RouteUI::is_midi_track () const
1856 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1859 boost::shared_ptr<MidiTrack>
1860 RouteUI::midi_track() const
1862 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1866 RouteUI::has_audio_outputs () const
1868 return (_route->n_outputs().n_audio() > 0);
1872 RouteUI::map_frozen ()
1874 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1876 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1879 check_rec_enable_sensitivity ();
1884 RouteUI::adjust_latency ()
1886 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1890 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1893 std::string safe_name;
1896 prompter.get_result (name, true);
1898 safe_name = legalize_for_path (name);
1899 safe_name += template_suffix;
1901 path = Glib::build_filename (dir, safe_name);
1903 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1904 bool overwrite = overwrite_file_dialog (prompter,
1905 _("Confirm Template Overwrite"),
1906 _("A template already exists with that name. Do you want to overwrite it?"));
1913 _route->save_as_template (path, name);
1919 RouteUI::save_as_template ()
1923 dir = ARDOUR::user_route_template_directory ();
1925 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1926 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1930 ArdourPrompter prompter (true); // modal
1932 prompter.set_title (_("Save As Template"));
1933 prompter.set_prompt (_("Template name:"));
1934 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1936 bool finished = false;
1938 switch (prompter.run()) {
1939 case RESPONSE_ACCEPT:
1940 finished = process_save_template_prompter (prompter, dir);
1950 RouteUI::check_rec_enable_sensitivity ()
1952 if (!rec_enable_button) {
1953 assert (0); // This should not happen
1956 if (!_session->writable()) {
1957 rec_enable_button->set_sensitive (false);
1961 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1962 rec_enable_button->set_sensitive (false);
1963 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1964 rec_enable_button->set_sensitive (false);
1966 rec_enable_button->set_sensitive (true);
1968 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1969 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1971 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1973 update_monitoring_display ();
1977 RouteUI::parameter_changed (string const & p)
1979 /* this handles RC and per-session parameter changes */
1981 if (p == "disable-disarm-during-roll") {
1982 check_rec_enable_sensitivity ();
1983 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1984 set_button_names ();
1985 } else if (p == "session-monitoring") {
1986 update_monitoring_display ();
1987 } else if (p == "auto-input") {
1988 update_monitoring_display ();
1989 } else if (p == "blink-rec-arm") {
1990 if (UIConfiguration::instance().get_blink_rec_arm()) {
1991 rec_blink_connection.disconnect ();
1992 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1994 rec_blink_connection.disconnect ();
1995 RouteUI::blink_rec_display(false);
2001 RouteUI::step_gain_up ()
2003 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2007 RouteUI::page_gain_up ()
2009 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2013 RouteUI::step_gain_down ()
2015 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2019 RouteUI::page_gain_down ()
2021 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2025 RouteUI::setup_invert_buttons ()
2027 /* remove old invert buttons */
2028 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2029 _invert_button_box.remove (**i);
2032 _invert_buttons.clear ();
2034 if (!_route || !_route->input()) {
2038 uint32_t const N = _route->input()->n_ports().n_audio ();
2040 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2042 for (uint32_t i = 0; i < to_add; ++i) {
2043 ArdourButton* b = manage (new ArdourButton);
2044 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2045 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2047 b->set_name (X_("invert button"));
2050 b->set_text (string_compose (X_("Ø (%1)"), N));
2052 b->set_text (X_("Ø"));
2055 b->set_text (string_compose (X_("Ø%1"), i + 1));
2058 if (N <= _max_invert_buttons) {
2059 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));
2061 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2064 _invert_buttons.push_back (b);
2065 _invert_button_box.pack_start (*b);
2068 _invert_button_box.set_spacing (1);
2069 _invert_button_box.show_all ();
2073 RouteUI::set_invert_button_state ()
2075 uint32_t const N = _route->input()->n_ports().n_audio();
2076 if (N > _max_invert_buttons) {
2078 /* One button for many channels; explicit active if all channels are inverted,
2079 implicit active if some are, off if none are.
2082 ArdourButton* b = _invert_buttons.front ();
2084 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2085 b->set_active_state (Gtkmm2ext::ExplicitActive);
2086 } else if (_route->phase_control()->any()) {
2087 b->set_active_state (Gtkmm2ext::ImplicitActive);
2089 b->set_active_state (Gtkmm2ext::Off);
2094 /* One button per channel; just set active */
2097 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2098 (*i)->set_active (_route->phase_control()->inverted (j));
2105 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2107 if (ev->button == 1 && i < _invert_buttons.size()) {
2108 uint32_t const N = _route->input()->n_ports().n_audio ();
2109 if (N <= _max_invert_buttons) {
2110 /* left-click inverts phase so long as we have a button per channel */
2111 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2120 RouteUI::invert_press (GdkEventButton* ev)
2122 using namespace Menu_Helpers;
2124 uint32_t const N = _route->input()->n_ports().n_audio();
2125 if (N <= _max_invert_buttons && ev->button != 3) {
2126 /* If we have an invert button per channel, we only pop
2127 up a menu on right-click; left click is handled
2133 delete _invert_menu;
2134 _invert_menu = new Menu;
2135 _invert_menu->set_name ("ArdourContextMenu");
2136 MenuList& items = _invert_menu->items ();
2138 for (uint32_t i = 0; i < N; ++i) {
2139 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2140 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2141 ++_i_am_the_modifier;
2142 e->set_active (_route->phase_control()->inverted (i));
2143 --_i_am_the_modifier;
2146 _invert_menu->popup (0, ev->time);
2152 RouteUI::invert_menu_toggled (uint32_t c)
2154 if (_i_am_the_modifier) {
2159 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2163 RouteUI::set_invert_sensitive (bool yn)
2165 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2166 (*b)->set_sensitive (yn);
2171 RouteUI::request_redraw ()
2174 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2178 /** The Route's gui_changed signal has been emitted */
2180 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2182 if (what_changed.contains (Properties::color)) {
2183 if (set_color_from_route () == 0) {
2184 route_color_changed ();
2190 RouteUI::track_mode_changed (void)
2193 switch (track()->mode()) {
2194 case ARDOUR::NonLayered:
2195 case ARDOUR::Normal:
2196 rec_enable_button->set_icon (ArdourIcon::RecButton);
2198 case ARDOUR::Destructive:
2199 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2202 rec_enable_button->queue_draw();
2205 /** @return the color that this route should use; it maybe its own,
2206 or it maybe that of its route group.
2210 RouteUI::route_color () const
2213 RouteGroup* g = _route->route_group ();
2216 if (g && g->is_color()) {
2217 set_color_from_rgba (c, GroupTabs::group_color (g));
2219 set_color_from_rgba (c, _route->presentation_info().color());
2226 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2228 _showing_sends_to = send_to;
2229 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2233 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2235 if (_route == send_to) {
2236 show_sends_button->set_active (true);
2237 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2239 show_sends_button->set_active (false);
2240 send_blink_connection.disconnect ();
2245 RouteUI::route_group() const
2247 return _route->route_group();
2251 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2252 : WM::ProxyBase (name, string())
2253 , _route (boost::weak_ptr<Route> (route))
2255 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2258 RoutePinWindowProxy::~RoutePinWindowProxy()
2263 ARDOUR::SessionHandlePtr*
2264 RoutePinWindowProxy::session_handle ()
2266 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2267 if (aw) { return aw; }
2272 RoutePinWindowProxy::get (bool create)
2274 boost::shared_ptr<Route> r = _route.lock ();
2283 _window = new PluginPinDialog (r);
2284 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2286 aw->set_session (_session);
2288 _window->show_all ();
2294 RoutePinWindowProxy::route_going_away ()
2298 WM::Manager::instance().remove (this);
2299 going_away_connection.disconnect();
2304 RouteUI::maybe_add_route_print_mgr ()
2306 if (_route->pinmgr_proxy ()) {
2309 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2310 string_compose ("RPM-%1", _route->id()), _route);
2311 wp->set_session (_session);
2313 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2315 wp->set_state (*ui_xml, 0);
2319 void* existing_ui = _route->pinmgr_proxy ();
2321 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2324 _route->set_pingmgr_proxy (wp);
2326 WM::Manager::instance().register_window (wp);
2330 RouteUI::manage_pins ()
2332 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2340 RouteUI::fan_out (bool to_busses, bool group)
2342 DisplaySuspender ds;
2343 boost::shared_ptr<ARDOUR::Route> route = _route;
2344 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2347 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2348 if (route->n_outputs ().n_audio () != n_outputs) {
2349 MessageDialog msg (string_compose (
2350 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2351 n_outputs, route->n_outputs ().n_audio ()));
2356 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2358 /* count busses and channels/bus */
2359 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2360 std::map<std::string, uint32_t> busnames;
2361 for (uint32_t p = 0; p < n_outputs; ++p) {
2362 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2363 std::string bn = BUSNAME;
2367 if (busnames.size () < 2) {
2368 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2373 uint32_t outputs = 2;
2374 if (_session->master_out ()) {
2375 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2378 route->output ()->disconnect (this);
2379 route->panner_shell ()->set_bypassed (true);
2382 for (uint32_t p = 0; p < n_outputs; ++p) {
2383 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2384 std::string bn = BUSNAME;
2385 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2388 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2392 list<boost::shared_ptr<AudioTrack> > tl =
2393 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2397 boost::shared_ptr<ControlList> cl (new ControlList);
2398 cl->push_back (r->monitoring_control ());
2399 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2401 r->input ()->disconnect (this);
2403 to_group.push_back (r);
2404 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2409 RouteGroup* rg = NULL;
2410 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2411 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2412 if ((*i)->name () == pi->name ()) {
2418 rg = new RouteGroup (*_session, pi->name ());
2419 _session->add_route_group (rg);
2420 rg->set_gain (false);
2423 GroupTabs::set_group_color (rg, route->presentation_info().color());
2424 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2431 RouteUI::mark_hidden (bool yn)
2433 if (yn != _route->presentation_info().hidden()) {
2434 _route->presentation_info().set_hidden (yn);
2435 return true; // things changed
2440 boost::shared_ptr<Stripable>
2441 RouteUI::stripable () const