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 _color_picker.reset ();
248 denormal_menu_item = 0;
252 RouteUI::self_delete ()
258 RouteUI::set_route (boost::shared_ptr<Route> rp)
264 if ( !_route->presentation_info().color_set() ) {
265 /* deal with older 4.x color, which was stored in the GUI object state */
267 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
271 /* old v4.x or earlier session. Use this information */
273 int red, green, blue;
278 /* old color format version was:
280 16bit value for red:16 bit value for green:16 bit value for blue
295 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
299 if (set_color_from_route()) {
300 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
304 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
307 delete input_selector;
310 delete output_selector;
313 mute_button->set_controllable (_route->mute_control());
314 solo_button->set_controllable (_route->solo_control());
316 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
318 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
320 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
321 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
322 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
323 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
324 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
325 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
328 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
329 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
330 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
332 track_mode_changed();
336 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
337 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
339 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
341 if (_session->writable() && is_track()) {
342 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
344 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
345 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
347 rec_enable_button->show();
348 rec_enable_button->set_controllable (t->rec_enable_control());
350 if (is_midi_track()) {
351 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
352 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
357 /* this will work for busses and tracks, and needs to be called to
358 set up the name entry/name label display.
362 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
363 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
365 update_monitoring_display ();
368 mute_button->unset_flags (Gtk::CAN_FOCUS);
369 solo_button->unset_flags (Gtk::CAN_FOCUS);
373 if (_route->is_monitor() || _route->is_master()) {
374 solo_button->hide ();
381 setup_invert_buttons ();
382 set_invert_button_state ();
384 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
385 bus_send_display_changed (s);
387 update_mute_display ();
388 update_solo_display ();
390 if (!UIConfiguration::instance().get_blink_rec_arm()) {
391 blink_rec_display(true); // set initial rec-en button state
394 check_rec_enable_sensitivity ();
395 maybe_add_route_print_mgr ();
396 route_color_changed();
397 route_gui_changed (PropertyChange (Properties::selected));
401 RouteUI::polarity_changed ()
407 set_invert_button_state ();
411 RouteUI::mute_press (GdkEventButton* ev)
413 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
417 //if this is a binding action, let the ArdourButton handle it
418 if ( BindingProxy::is_bind_action(ev) )
421 multiple_mute_change = false;
423 if (Keyboard::is_context_menu_event (ev)) {
429 mute_menu->popup(ev->button, ev->time);
435 if (Keyboard::is_button2_event (ev)) {
436 // button2-click is "momentary"
438 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
441 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
443 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
445 /* toggle mute on everything (but
446 * exclude the master and monitor)
448 * because we are going to erase
449 * elements of the list we need to work
453 boost::shared_ptr<RouteList> copy (new RouteList);
455 *copy = *_session->get_routes ();
457 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
458 if ((*i)->is_master() || (*i)->is_monitor()) {
466 _mute_release->routes = copy;
469 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
471 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
473 /* Primary-button1 inverts the implication of
474 the group being active. If the group is
475 active (for mute), then this modifier means
476 "do not apply to mute". If the group is
477 inactive (for mute), then this modifier
478 means "apply to route". This is all
479 accomplished by passing just the actual
480 route, along with the InverseGroup group
483 NOTE: Primary-button2 is MIDI learn.
486 boost::shared_ptr<RouteList> rl;
488 if (ev->button == 1) {
490 rl.reset (new RouteList);
491 rl->push_back (_route);
494 _mute_release->routes = rl;
497 boost::shared_ptr<MuteControl> mc = _route->mute_control();
498 mc->start_touch (_session->audible_frame ());
499 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
504 /* plain click applies change to this route */
506 boost::shared_ptr<RouteList> rl (new RouteList);
507 rl->push_back (_route);
510 _mute_release->routes = rl;
513 boost::shared_ptr<MuteControl> mc = _route->mute_control();
514 mc->start_touch (_session->audible_frame ());
515 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
524 RouteUI::mute_release (GdkEventButton* /*ev*/)
527 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
528 delete _mute_release;
532 _route->mute_control()->stop_touch (false, _session->audible_frame ());
538 RouteUI::edit_output_configuration ()
540 if (output_selector == 0) {
542 boost::shared_ptr<Send> send;
543 boost::shared_ptr<IO> output;
545 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
546 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
547 output = send->output();
549 output = _route->output ();
552 output = _route->output ();
555 output_selector = new IOSelectorWindow (_session, output);
558 if (output_selector->is_visible()) {
559 output_selector->get_toplevel()->get_window()->raise();
561 output_selector->present ();
564 //output_selector->set_keep_above (true);
568 RouteUI::edit_input_configuration ()
570 if (input_selector == 0) {
571 input_selector = new IOSelectorWindow (_session, _route->input());
574 if (input_selector->is_visible()) {
575 input_selector->get_toplevel()->get_window()->raise();
577 input_selector->present ();
580 //input_selector->set_keep_above (true);
584 RouteUI::solo_press(GdkEventButton* ev)
586 /* ignore double/triple clicks */
588 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
592 //if this is a binding action, let the ArdourButton handle it
593 if ( BindingProxy::is_bind_action(ev) )
596 multiple_solo_change = false;
598 if (Keyboard::is_context_menu_event (ev)) {
600 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
601 ! (solo_safe_led && solo_safe_led->is_visible())) {
603 if (solo_menu == 0) {
607 solo_menu->popup (ev->button, ev->time);
612 if (Keyboard::is_button2_event (ev)) {
614 // button2-click is "momentary"
615 _solo_release = new SoloMuteRelease (_route->self_soloed());
618 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
620 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
622 /* Primary-Tertiary-click applies change to all routes */
625 _solo_release->routes = _session->get_routes ();
628 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
630 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
632 // Primary-Secondary-click: exclusively solo this track
635 _solo_release->exclusive = true;
637 boost::shared_ptr<RouteList> routes = _session->get_routes();
639 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
640 if ((*i)->soloed ()) {
641 _solo_release->routes_on->push_back (*i);
643 _solo_release->routes_off->push_back (*i);
648 if (Config->get_solo_control_is_listen_control()) {
649 /* ??? we need a just_one_listen() method */
652 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
655 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
657 // shift-click: toggle solo isolated status
659 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
660 delete _solo_release;
663 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
665 /* Primary-button1: solo mix group.
666 NOTE: Primary-button2 is MIDI learn.
669 /* Primary-button1 applies change to the mix group even if it is not active
670 NOTE: Primary-button2 is MIDI learn.
673 boost::shared_ptr<RouteList> rl;
675 if (ev->button == 1) {
677 /* Primary-button1 inverts the implication of
678 the group being active. If the group is
679 active (for solo), then this modifier means
680 "do not apply to solo". If the group is
681 inactive (for mute), then this modifier
682 means "apply to route". This is all
683 accomplished by passing just the actual
684 route, along with the InverseGroup group
687 NOTE: Primary-button2 is MIDI learn.
690 rl.reset (new RouteList);
691 rl->push_back (_route);
694 _solo_release->routes = rl;
697 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
700 delete _solo_release;
705 /* click: solo this route */
707 boost::shared_ptr<RouteList> rl (new RouteList);
708 rl->push_back (route());
711 _solo_release->routes = rl;
714 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
723 RouteUI::solo_release (GdkEventButton* /*ev*/)
727 if (_solo_release->exclusive) {
730 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
733 delete _solo_release;
741 RouteUI::rec_enable_press(GdkEventButton* ev)
743 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
747 //if this is a binding action, let the ArdourButton handle it
748 if ( BindingProxy::is_bind_action(ev) )
751 if (!_session->engine().connected()) {
752 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
757 if (is_midi_track()) {
759 /* rec-enable button exits from step editing */
761 if (midi_track()->step_editing()) {
762 midi_track()->set_step_editing (false);
767 if (is_track() && rec_enable_button) {
769 if (Keyboard::is_button2_event (ev)) {
771 //rec arm does not have a momentary mode
774 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
776 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
778 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
780 /* Primary-button1 applies change to the route group (even if it is not active)
781 NOTE: Primary-button2 is MIDI learn.
784 if (ev->button == 1) {
786 boost::shared_ptr<RouteList> rl;
788 rl.reset (new RouteList);
789 rl->push_back (_route);
791 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
794 } else if (Keyboard::is_context_menu_event (ev)) {
796 /* do this on release */
800 boost::shared_ptr<Track> trk = track();
801 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
809 RouteUI::update_monitoring_display ()
815 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
821 MonitorState ms = t->monitoring_state();
823 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
824 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
826 if (ms & MonitoringInput) {
827 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
829 monitor_input_button->unset_active_state ();
833 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
834 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
836 if (ms & MonitoringDisk) {
837 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
839 monitor_disk_button->unset_active_state ();
845 RouteUI::monitor_input_press(GdkEventButton*)
851 RouteUI::monitor_input_release(GdkEventButton* ev)
853 return monitor_release (ev, MonitorInput);
857 RouteUI::monitor_disk_press (GdkEventButton*)
863 RouteUI::monitor_disk_release (GdkEventButton* ev)
865 return monitor_release (ev, MonitorDisk);
869 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
871 if (ev->button != 1) {
875 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
882 boost::shared_ptr<RouteList> rl;
884 /* XXX for now, monitoring choices are orthogonal. cue monitoring
885 will follow in 3.X but requires mixing the input and playback (disk)
886 signal together, which requires yet more buffers.
889 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
890 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
892 /* this line will change when the options are non-orthogonal */
893 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
897 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
898 rl = _session->get_routes ();
900 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
901 if (_route->route_group() && _route->route_group()->is_monitoring()) {
902 rl = _route->route_group()->route_list();
904 rl.reset (new RouteList);
905 rl->push_back (route());
908 rl.reset (new RouteList);
909 rl->push_back (route());
912 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
918 RouteUI::build_record_menu ()
921 record_menu = new Menu;
922 record_menu->set_name ("ArdourContextMenu");
923 using namespace Menu_Helpers;
924 MenuList& items = record_menu->items();
926 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
927 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
929 if (is_midi_track()) {
930 items.push_back (SeparatorElem());
931 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
932 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
936 if (step_edit_item) {
937 if (track()->rec_enable_control()->get_value()) {
938 step_edit_item->set_sensitive (false);
940 step_edit_item->set_active (midi_track()->step_editing());
943 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
944 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
949 RouteUI::toggle_step_edit ()
951 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
955 midi_track()->set_step_editing (step_edit_item->get_active());
959 RouteUI::toggle_rec_safe ()
961 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
967 /* This check is made inside the control too, but dong it here can't
971 if (_route->rec_enable_control()->get_value()) {
975 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
979 RouteUI::step_edit_changed (bool yn)
982 if (rec_enable_button) {
983 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
986 start_step_editing ();
988 if (step_edit_item) {
989 step_edit_item->set_active (true);
994 if (rec_enable_button) {
995 rec_enable_button->unset_active_state ();
998 stop_step_editing ();
1000 if (step_edit_item) {
1001 step_edit_item->set_active (false);
1007 RouteUI::rec_enable_release (GdkEventButton* ev)
1009 if (Keyboard::is_context_menu_event (ev)) {
1010 build_record_menu ();
1012 record_menu->popup (ev->button, ev->time);
1021 RouteUI::build_sends_menu ()
1023 using namespace Menu_Helpers;
1025 sends_menu = new Menu;
1026 sends_menu->set_name ("ArdourContextMenu");
1027 MenuList& items = sends_menu->items();
1030 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1034 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1038 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1042 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1046 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1050 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1053 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1057 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1060 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1061 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1062 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1067 RouteUI::create_sends (Placement p, bool include_buses)
1069 _session->globally_add_internal_sends (_route, p, include_buses);
1073 RouteUI::create_selected_sends (Placement p, bool include_buses)
1075 boost::shared_ptr<RouteList> rlist (new RouteList);
1076 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1078 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1079 RouteTimeAxisView* rtv;
1081 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1082 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1083 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1084 rlist->push_back (rui->route());
1090 _session->add_internal_sends (_route, p, rlist);
1094 RouteUI::set_sends_gain_from_track ()
1096 _session->globally_set_send_gains_from_track (_route);
1100 RouteUI::set_sends_gain_to_zero ()
1102 _session->globally_set_send_gains_to_zero (_route);
1106 RouteUI::set_sends_gain_to_unity ()
1108 _session->globally_set_send_gains_to_unity (_route);
1112 RouteUI::show_sends_press(GdkEventButton* ev)
1114 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1118 if (!is_track() && show_sends_button) {
1120 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1122 // do nothing on midi sigc::bind event
1125 } else if (Keyboard::is_context_menu_event (ev)) {
1127 if (sends_menu == 0) {
1128 build_sends_menu ();
1131 sends_menu->popup (ev->button, ev->time);
1135 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1138 set_showing_sends_to (boost::shared_ptr<Route> ());
1140 set_showing_sends_to (_route);
1149 RouteUI::show_sends_release (GdkEventButton*)
1155 RouteUI::send_blink (bool onoff)
1157 if (!show_sends_button) {
1162 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1164 show_sends_button->unset_active_state ();
1168 Gtkmm2ext::ActiveState
1169 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1171 boost::shared_ptr<SoloControl> sc = s->solo_control();
1174 return Gtkmm2ext::Off;
1177 if (!sc->can_solo()) {
1178 return Gtkmm2ext::Off;
1182 if (sc->self_soloed()) {
1183 return Gtkmm2ext::ExplicitActive;
1184 } else if (sc->soloed_by_others()) {
1185 return Gtkmm2ext::ImplicitActive;
1187 return Gtkmm2ext::Off;
1191 Gtkmm2ext::ActiveState
1192 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1194 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1197 return Gtkmm2ext::Off;
1200 if (s->is_master() || s->is_monitor()) {
1201 return Gtkmm2ext::Off;
1204 if (sc->solo_isolated()) {
1205 return Gtkmm2ext::ExplicitActive;
1207 return Gtkmm2ext::Off;
1211 Gtkmm2ext::ActiveState
1212 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1214 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1217 return Gtkmm2ext::Off;
1220 if (s->is_master() || s->is_monitor()) {
1221 return Gtkmm2ext::Off;
1224 if (sc->solo_safe()) {
1225 return Gtkmm2ext::ExplicitActive;
1227 return Gtkmm2ext::Off;
1232 RouteUI::update_solo_display ()
1234 bool yn = _route->solo_safe_control()->solo_safe ();
1236 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1237 solo_safe_check->set_active (yn);
1240 yn = _route->solo_isolate_control()->solo_isolated ();
1242 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1243 solo_isolated_check->set_active (yn);
1246 set_button_names ();
1248 if (solo_isolated_led) {
1249 if (_route->solo_isolate_control()->solo_isolated()) {
1250 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1252 solo_isolated_led->unset_active_state ();
1256 if (solo_safe_led) {
1257 if (_route->solo_safe_control()->solo_safe()) {
1258 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1260 solo_safe_led->unset_active_state ();
1264 solo_button->set_active_state (solo_active_state (_route));
1266 /* some changes to solo status can affect mute display, so catch up
1269 update_mute_display ();
1273 RouteUI::solo_changed_so_update_mute ()
1275 update_mute_display ();
1279 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1281 boost::shared_ptr<MuteControl> mc = s->mute_control();
1283 if (s->is_monitor()) {
1284 return Gtkmm2ext::Off;
1288 return Gtkmm2ext::Off;
1291 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1293 if (mc->muted_by_self ()) {
1295 return Gtkmm2ext::ExplicitActive;
1296 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1297 /* this will reflect both solo mutes AND master mutes */
1298 return Gtkmm2ext::ImplicitActive;
1300 /* no mute at all */
1301 return Gtkmm2ext::Off;
1306 if (mc->muted_by_self()) {
1308 return Gtkmm2ext::ExplicitActive;
1309 } else if (mc->muted_by_masters ()) {
1310 /* this shows only master mutes, not mute-by-others-soloing */
1311 return Gtkmm2ext::ImplicitActive;
1313 /* no mute at all */
1314 return Gtkmm2ext::Off;
1318 return ActiveState(0);
1322 RouteUI::update_mute_display ()
1328 mute_button->set_active_state (mute_active_state (_session, _route));
1333 RouteUI::route_rec_enable_changed ()
1335 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1339 RouteUI::session_rec_enable_changed ()
1341 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1345 RouteUI::blink_rec_display (bool blinkOn)
1347 if (!rec_enable_button || !_route) {
1351 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1359 if (track()->rec_enable_control()->get_value()) {
1360 switch (_session->record_status ()) {
1361 case Session::Recording:
1362 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1365 case Session::Disabled:
1366 case Session::Enabled:
1367 if (UIConfiguration::instance().get_blink_rec_arm()) {
1368 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1370 rec_enable_button->set_active_state ( ImplicitActive );
1375 if (step_edit_item) {
1376 step_edit_item->set_sensitive (false);
1380 rec_enable_button->unset_active_state ();
1382 if (step_edit_item) {
1383 step_edit_item->set_sensitive (true);
1387 check_rec_enable_sensitivity ();
1391 RouteUI::build_solo_menu (void)
1393 using namespace Menu_Helpers;
1395 solo_menu = new Menu;
1396 solo_menu->set_name ("ArdourContextMenu");
1397 MenuList& items = solo_menu->items();
1398 Gtk::CheckMenuItem* check;
1400 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1401 check->set_active (_route->solo_isolate_control()->solo_isolated());
1402 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1403 items.push_back (CheckMenuElem(*check));
1404 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1407 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1408 check->set_active (_route->solo_safe_control()->solo_safe());
1409 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1410 items.push_back (CheckMenuElem(*check));
1411 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1414 //items.push_back (SeparatorElem());
1415 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1420 RouteUI::build_mute_menu(void)
1422 using namespace Menu_Helpers;
1424 mute_menu = new Menu;
1425 mute_menu->set_name ("ArdourContextMenu");
1427 MenuList& items = mute_menu->items();
1429 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1430 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1431 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1432 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1433 pre_fader_mute_check->show_all();
1435 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1436 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1437 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1438 items.push_back (CheckMenuElem(*post_fader_mute_check));
1439 post_fader_mute_check->show_all();
1441 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1442 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1443 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1444 items.push_back (CheckMenuElem(*listen_mute_check));
1445 listen_mute_check->show_all();
1447 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1448 init_mute_menu(MuteMaster::Main, main_mute_check);
1449 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1450 items.push_back (CheckMenuElem(*main_mute_check));
1451 main_mute_check->show_all();
1453 //items.push_back (SeparatorElem());
1454 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1456 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1460 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1462 check->set_active (_route->mute_control()->mute_points() & mp);
1466 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1468 if (check->get_active()) {
1469 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1471 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1476 RouteUI::muting_change ()
1478 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1481 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1483 yn = (current & MuteMaster::PreFader);
1485 if (pre_fader_mute_check->get_active() != yn) {
1486 pre_fader_mute_check->set_active (yn);
1489 yn = (current & MuteMaster::PostFader);
1491 if (post_fader_mute_check->get_active() != yn) {
1492 post_fader_mute_check->set_active (yn);
1495 yn = (current & MuteMaster::Listen);
1497 if (listen_mute_check->get_active() != yn) {
1498 listen_mute_check->set_active (yn);
1501 yn = (current & MuteMaster::Main);
1503 if (main_mute_check->get_active() != yn) {
1504 main_mute_check->set_active (yn);
1509 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1511 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1515 bool view = solo_isolated_led->active_state();
1516 bool model = _route->solo_isolate_control()->solo_isolated();
1518 /* called BEFORE the view has changed */
1520 if (ev->button == 1) {
1521 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1524 /* disable isolate for all routes */
1525 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1527 /* enable isolate for all routes */
1528 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1533 if (model == view) {
1535 /* flip just this route */
1537 boost::shared_ptr<RouteList> rl (new RouteList);
1538 rl->push_back (_route);
1539 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1548 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1550 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1554 bool view = solo_safe_led->active_state();
1555 bool model = _route->solo_safe_control()->solo_safe();
1557 if (ev->button == 1) {
1558 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1559 boost::shared_ptr<RouteList> rl (_session->get_routes());
1561 /* disable solo safe for all routes */
1562 DisplaySuspender ds;
1563 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1564 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1567 /* enable solo safe for all routes */
1568 DisplaySuspender ds;
1569 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1570 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1575 if (model == view) {
1576 /* flip just this route */
1577 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1586 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1588 bool view = check->get_active();
1589 bool model = _route->solo_isolate_control()->solo_isolated();
1591 /* called AFTER the view has changed */
1593 if (model != view) {
1594 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1599 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1601 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1604 /** Ask the user to choose a colour, and then apply that color to my route
1607 RouteUI::choose_color ()
1609 _color_picker.popup (_route);
1612 /** Set the route's own color. This may not be used for display if
1613 * the route is in a group which shares its color with its routes.
1616 RouteUI::set_color (uint32_t c)
1618 _route->presentation_info().set_color (c);
1621 /** @return GUI state ID for things that are common to the route in all its representations */
1623 RouteUI::route_state_id () const
1625 return string_compose (X_("route %1"), _route->id().to_s());
1629 RouteUI::set_color_from_route ()
1631 if (_route->presentation_info().color_set()) {
1632 return 0; /* nothing to do */
1635 return 1; /* pick a color */
1638 /** @return true if this name should be used for the route, otherwise false */
1640 RouteUI::verify_new_route_name (const std::string& name)
1642 if (name.find (':') == string::npos) {
1646 MessageDialog colon_msg (
1647 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1648 false, MESSAGE_QUESTION, BUTTONS_NONE
1651 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1652 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1654 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1658 RouteUI::route_rename ()
1660 ArdourPrompter name_prompter (true);
1665 name_prompter.set_title (_("Rename Track"));
1667 name_prompter.set_title (_("Rename Bus"));
1669 name_prompter.set_prompt (_("New name:"));
1670 name_prompter.set_initial_text (_route->name());
1671 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1672 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1673 name_prompter.show_all ();
1676 switch (name_prompter.run ()) {
1677 case Gtk::RESPONSE_ACCEPT:
1678 name_prompter.get_result (result);
1679 name_prompter.hide ();
1680 if (result.length()) {
1681 if (verify_new_route_name (result)) {
1682 _route->set_name (result);
1685 /* back to name prompter */
1689 /* nothing entered, just get out of here */
1704 RouteUI::toggle_comment_editor ()
1706 // if (ignore_toggle) {
1710 if (comment_window && comment_window->is_visible ()) {
1711 comment_window->hide ();
1713 open_comment_editor ();
1719 RouteUI::open_comment_editor ()
1721 if (comment_window == 0) {
1722 setup_comment_editor ();
1726 title = _route->name();
1727 title += _(": comment editor");
1729 comment_window->set_title (title);
1730 comment_window->present();
1734 RouteUI::setup_comment_editor ()
1736 comment_window = new ArdourWindow (""); // title will be reset to show route
1737 comment_window->set_skip_taskbar_hint (true);
1738 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1739 comment_window->set_default_size (400, 200);
1741 comment_area = manage (new TextView());
1742 comment_area->set_name ("MixerTrackCommentArea");
1743 comment_area->set_wrap_mode (WRAP_WORD);
1744 comment_area->set_editable (true);
1745 comment_area->get_buffer()->set_text (_route->comment());
1746 comment_area->show ();
1748 comment_window->add (*comment_area);
1752 RouteUI::comment_changed ()
1754 ignore_comment_edit = true;
1756 comment_area->get_buffer()->set_text (_route->comment());
1758 ignore_comment_edit = false;
1762 RouteUI::comment_editor_done_editing ()
1764 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1766 string const str = comment_area->get_buffer()->get_text();
1767 if (str == _route->comment ()) {
1771 _route->set_comment (str, this);
1775 RouteUI::set_route_active (bool a, bool apply_to_selection)
1777 if (apply_to_selection) {
1778 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1780 _route->set_active (a, this);
1785 RouteUI::duplicate_selected_routes ()
1787 ARDOUR_UI::instance()->start_duplicate_routes();
1791 RouteUI::toggle_denormal_protection ()
1793 if (denormal_menu_item) {
1797 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1799 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1800 _route->set_denormal_protection (x);
1806 RouteUI::denormal_protection_changed ()
1808 if (denormal_menu_item) {
1809 denormal_menu_item->set_active (_route->denormal_protection());
1814 RouteUI::disconnect_input ()
1816 _route->input()->disconnect (this);
1820 RouteUI::disconnect_output ()
1822 _route->output()->disconnect (this);
1826 RouteUI::is_track () const
1828 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1831 boost::shared_ptr<Track>
1832 RouteUI::track() const
1834 return boost::dynamic_pointer_cast<Track>(_route);
1838 RouteUI::is_audio_track () const
1840 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1843 boost::shared_ptr<AudioTrack>
1844 RouteUI::audio_track() const
1846 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1850 RouteUI::is_midi_track () const
1852 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1855 boost::shared_ptr<MidiTrack>
1856 RouteUI::midi_track() const
1858 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1862 RouteUI::has_audio_outputs () const
1864 return (_route->n_outputs().n_audio() > 0);
1868 RouteUI::map_frozen ()
1870 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1872 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1875 check_rec_enable_sensitivity ();
1880 RouteUI::adjust_latency ()
1882 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1886 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1889 std::string safe_name;
1892 prompter.get_result (name, true);
1894 safe_name = legalize_for_path (name);
1895 safe_name += template_suffix;
1897 path = Glib::build_filename (dir, safe_name);
1899 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1900 bool overwrite = overwrite_file_dialog (prompter,
1901 _("Confirm Template Overwrite"),
1902 _("A template already exists with that name. Do you want to overwrite it?"));
1909 _route->save_as_template (path, name);
1915 RouteUI::save_as_template ()
1919 dir = ARDOUR::user_route_template_directory ();
1921 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1922 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1926 ArdourPrompter prompter (true); // modal
1928 prompter.set_title (_("Save As Template"));
1929 prompter.set_prompt (_("Template name:"));
1930 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1932 bool finished = false;
1934 switch (prompter.run()) {
1935 case RESPONSE_ACCEPT:
1936 finished = process_save_template_prompter (prompter, dir);
1946 RouteUI::check_rec_enable_sensitivity ()
1948 if (!rec_enable_button) {
1949 assert (0); // This should not happen
1952 if (!_session->writable()) {
1953 rec_enable_button->set_sensitive (false);
1957 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1958 rec_enable_button->set_sensitive (false);
1959 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1960 rec_enable_button->set_sensitive (false);
1962 rec_enable_button->set_sensitive (true);
1964 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1965 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1967 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1969 update_monitoring_display ();
1973 RouteUI::parameter_changed (string const & p)
1975 /* this handles RC and per-session parameter changes */
1977 if (p == "disable-disarm-during-roll") {
1978 check_rec_enable_sensitivity ();
1979 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1980 set_button_names ();
1981 } else if (p == "session-monitoring") {
1982 update_monitoring_display ();
1983 } else if (p == "auto-input") {
1984 update_monitoring_display ();
1985 } else if (p == "blink-rec-arm") {
1986 if (UIConfiguration::instance().get_blink_rec_arm()) {
1987 rec_blink_connection.disconnect ();
1988 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1990 rec_blink_connection.disconnect ();
1991 RouteUI::blink_rec_display(false);
1997 RouteUI::step_gain_up ()
1999 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2003 RouteUI::page_gain_up ()
2005 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2009 RouteUI::step_gain_down ()
2011 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2015 RouteUI::page_gain_down ()
2017 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2021 RouteUI::setup_invert_buttons ()
2023 /* remove old invert buttons */
2024 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2025 _invert_button_box.remove (**i);
2028 _invert_buttons.clear ();
2030 if (!_route || !_route->input()) {
2034 uint32_t const N = _route->input()->n_ports().n_audio ();
2036 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2038 for (uint32_t i = 0; i < to_add; ++i) {
2039 ArdourButton* b = manage (new ArdourButton);
2040 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2041 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2043 b->set_name (X_("invert button"));
2046 b->set_text (string_compose (X_("Ø (%1)"), N));
2048 b->set_text (X_("Ø"));
2051 b->set_text (string_compose (X_("Ø%1"), i + 1));
2054 if (N <= _max_invert_buttons) {
2055 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));
2057 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2060 _invert_buttons.push_back (b);
2061 _invert_button_box.pack_start (*b);
2064 _invert_button_box.set_spacing (1);
2065 _invert_button_box.show_all ();
2069 RouteUI::set_invert_button_state ()
2071 uint32_t const N = _route->input()->n_ports().n_audio();
2072 if (N > _max_invert_buttons) {
2074 /* One button for many channels; explicit active if all channels are inverted,
2075 implicit active if some are, off if none are.
2078 ArdourButton* b = _invert_buttons.front ();
2080 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2081 b->set_active_state (Gtkmm2ext::ExplicitActive);
2082 } else if (_route->phase_control()->any()) {
2083 b->set_active_state (Gtkmm2ext::ImplicitActive);
2085 b->set_active_state (Gtkmm2ext::Off);
2090 /* One button per channel; just set active */
2093 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2094 (*i)->set_active (_route->phase_control()->inverted (j));
2101 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2103 if (ev->button == 1 && i < _invert_buttons.size()) {
2104 uint32_t const N = _route->input()->n_ports().n_audio ();
2105 if (N <= _max_invert_buttons) {
2106 /* left-click inverts phase so long as we have a button per channel */
2107 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2116 RouteUI::invert_press (GdkEventButton* ev)
2118 using namespace Menu_Helpers;
2120 uint32_t const N = _route->input()->n_ports().n_audio();
2121 if (N <= _max_invert_buttons && ev->button != 3) {
2122 /* If we have an invert button per channel, we only pop
2123 up a menu on right-click; left click is handled
2129 delete _invert_menu;
2130 _invert_menu = new Menu;
2131 _invert_menu->set_name ("ArdourContextMenu");
2132 MenuList& items = _invert_menu->items ();
2134 for (uint32_t i = 0; i < N; ++i) {
2135 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2136 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2137 ++_i_am_the_modifier;
2138 e->set_active (_route->phase_control()->inverted (i));
2139 --_i_am_the_modifier;
2142 _invert_menu->popup (ev->button, ev->time);
2148 RouteUI::invert_menu_toggled (uint32_t c)
2150 if (_i_am_the_modifier) {
2155 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2159 RouteUI::set_invert_sensitive (bool yn)
2161 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2162 (*b)->set_sensitive (yn);
2167 RouteUI::request_redraw ()
2170 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2174 /** The Route's gui_changed signal has been emitted */
2176 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2178 if (what_changed.contains (Properties::color)) {
2179 if (set_color_from_route () == 0) {
2180 route_color_changed ();
2186 RouteUI::track_mode_changed (void)
2189 switch (track()->mode()) {
2190 case ARDOUR::NonLayered:
2191 case ARDOUR::Normal:
2192 rec_enable_button->set_icon (ArdourIcon::RecButton);
2194 case ARDOUR::Destructive:
2195 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2198 rec_enable_button->queue_draw();
2201 /** @return the color that this route should use; it maybe its own,
2202 or it maybe that of its route group.
2206 RouteUI::route_color () const
2209 RouteGroup* g = _route->route_group ();
2212 if (g && g->is_color()) {
2213 set_color_from_rgba (c, GroupTabs::group_color (g));
2215 set_color_from_rgba (c, _route->presentation_info().color());
2222 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2224 _showing_sends_to = send_to;
2225 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2229 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2231 if (_route == send_to) {
2232 show_sends_button->set_active (true);
2233 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2235 show_sends_button->set_active (false);
2236 send_blink_connection.disconnect ();
2241 RouteUI::route_group() const
2243 return _route->route_group();
2247 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2248 : WM::ProxyBase (name, string())
2249 , _route (boost::weak_ptr<Route> (route))
2251 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2254 RoutePinWindowProxy::~RoutePinWindowProxy()
2259 ARDOUR::SessionHandlePtr*
2260 RoutePinWindowProxy::session_handle ()
2262 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2263 if (aw) { return aw; }
2268 RoutePinWindowProxy::get (bool create)
2270 boost::shared_ptr<Route> r = _route.lock ();
2279 _window = new PluginPinDialog (r);
2280 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2282 aw->set_session (_session);
2284 _window->show_all ();
2290 RoutePinWindowProxy::route_going_away ()
2294 WM::Manager::instance().remove (this);
2295 going_away_connection.disconnect();
2300 RouteUI::maybe_add_route_print_mgr ()
2302 if (_route->pinmgr_proxy ()) {
2305 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2306 string_compose ("RPM-%1", _route->id()), _route);
2307 wp->set_session (_session);
2309 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2311 wp->set_state (*ui_xml, 0);
2315 void* existing_ui = _route->pinmgr_proxy ();
2317 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2320 _route->set_pingmgr_proxy (wp);
2322 WM::Manager::instance().register_window (wp);
2326 RouteUI::manage_pins ()
2328 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2336 RouteUI::fan_out (bool to_busses, bool group)
2338 DisplaySuspender ds;
2339 boost::shared_ptr<ARDOUR::Route> route = _route;
2340 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2343 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2344 if (route->n_outputs ().n_audio () != n_outputs) {
2345 MessageDialog msg (string_compose (
2346 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2347 n_outputs, route->n_outputs ().n_audio ()));
2352 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2354 /* count busses and channels/bus */
2355 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2356 std::map<std::string, uint32_t> busnames;
2357 for (uint32_t p = 0; p < n_outputs; ++p) {
2358 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2359 std::string bn = BUSNAME;
2363 if (busnames.size () < 2) {
2364 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2369 uint32_t outputs = 2;
2370 if (_session->master_out ()) {
2371 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2374 route->output ()->disconnect (this);
2375 route->panner_shell ()->set_bypassed (true);
2378 for (uint32_t p = 0; p < n_outputs; ++p) {
2379 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2380 std::string bn = BUSNAME;
2381 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2384 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2388 list<boost::shared_ptr<AudioTrack> > tl =
2389 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2393 boost::shared_ptr<ControlList> cl (new ControlList);
2394 cl->push_back (r->monitoring_control ());
2395 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2397 r->input ()->disconnect (this);
2399 to_group.push_back (r);
2400 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2405 RouteGroup* rg = NULL;
2406 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2407 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2408 if ((*i)->name () == pi->name ()) {
2414 rg = new RouteGroup (*_session, pi->name ());
2415 _session->add_route_group (rg);
2416 rg->set_gain (false);
2419 GroupTabs::set_group_color (rg, route->presentation_info().color());
2420 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2427 RouteUI::mark_hidden (bool yn)
2429 if (yn != _route->presentation_info().hidden()) {
2430 _route->presentation_info().set_hidden (yn);
2431 return true; // things changed
2436 boost::shared_ptr<Stripable>
2437 RouteUI::stripable () const