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.
20 #include <boost/algorithm/string.hpp>
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
35 #include "ardour/dB.h"
36 #include "ardour/route_group.h"
37 #include "ardour/vca.h"
38 #include "ardour/vca_manager.h"
40 #include "ardour_ui.h"
43 #include "ardour_button.h"
46 #include "plugin_pin_dialog.h"
48 #include "gui_thread.h"
49 #include "ardour_dialog.h"
50 #include "latency_gui.h"
51 #include "mixer_strip.h"
52 #include "automation_time_axis.h"
53 #include "route_time_axis.h"
54 #include "group_tabs.h"
56 #include "ui_config.h"
58 #include "ardour/audio_track.h"
59 #include "ardour/audioengine.h"
60 #include "ardour/filename_extensions.h"
61 #include "ardour/midi_track.h"
62 #include "ardour/internal_send.h"
63 #include "ardour/profile.h"
64 #include "ardour/send.h"
65 #include "ardour/route.h"
66 #include "ardour/session.h"
67 #include "ardour/template_utils.h"
71 using namespace Gtkmm2ext;
72 using namespace ARDOUR;
73 using namespace ARDOUR_UI_UTILS;
77 uint32_t RouteUI::_max_invert_buttons = 3;
78 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
79 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
80 std::string RouteUI::program_port_prefix;
82 RouteUI::RouteUI (ARDOUR::Session* sess)
94 if (program_port_prefix.empty()) {
95 // compare to gtk2_ardour/port_group.cc
96 string lpn (PROGRAM_NAME);
97 boost::to_lower (lpn);
98 program_port_prefix = lpn + ":"; // e.g. "ardour:"
106 gui_object_state().remove_node (route_state_id());
109 _route.reset (); /* drop reference to route, so that it can be cleaned up */
110 route_connections.drop_connections ();
116 delete comment_window;
117 delete input_selector;
118 delete output_selector;
121 send_blink_connection.disconnect ();
122 rec_blink_connection.disconnect ();
128 self_destruct = true;
134 pre_fader_mute_check = 0;
135 post_fader_mute_check = 0;
136 listen_mute_check = 0;
139 solo_isolated_check = 0;
140 solo_isolated_led = 0;
144 denormal_menu_item = 0;
147 multiple_mute_change = false;
148 multiple_solo_change = false;
149 _i_am_the_modifier = 0;
155 setup_invert_buttons ();
157 mute_button = manage (new ArdourButton);
158 mute_button->set_name ("mute button");
159 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
161 solo_button = manage (new ArdourButton);
162 solo_button->set_name ("solo button");
163 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
164 solo_button->set_no_show_all (true);
166 rec_enable_button = manage (new ArdourButton);
167 rec_enable_button->set_name ("record enable button");
168 rec_enable_button->set_icon (ArdourIcon::RecButton);
169 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
171 if (UIConfiguration::instance().get_blink_rec_arm()) {
172 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
175 show_sends_button = manage (new ArdourButton);
176 show_sends_button->set_name ("send alert button");
177 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
179 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
180 monitor_input_button->set_name ("monitor button");
181 monitor_input_button->set_text (_("In"));
182 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
183 monitor_input_button->set_no_show_all (true);
185 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
186 monitor_disk_button->set_name ("monitor button");
187 monitor_disk_button->set_text (_("Disk"));
188 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
189 monitor_disk_button->set_no_show_all (true);
191 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
192 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
193 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
195 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
196 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
198 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
199 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
201 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
202 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
204 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
205 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
206 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
207 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
209 monitor_input_button->set_distinct_led_click (false);
210 monitor_disk_button->set_distinct_led_click (false);
212 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
213 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
215 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
216 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
218 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
224 route_connections.drop_connections ();
232 denormal_menu_item = 0;
236 RouteUI::self_delete ()
242 RouteUI::set_route (boost::shared_ptr<Route> rp)
248 if (set_color_from_route()) {
249 set_color (unique_random_color());
253 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
256 delete input_selector;
259 delete output_selector;
262 mute_button->set_controllable (_route->mute_control());
263 solo_button->set_controllable (_route->solo_control());
265 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
267 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
269 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
270 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
271 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
272 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
274 if (_route->phase_control()) {
275 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
279 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
280 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
281 track_mode_changed();
285 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
287 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
288 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
290 if (_session->writable() && is_track()) {
291 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
293 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
294 t->RecordSafeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
296 rec_enable_button->show();
297 rec_enable_button->set_controllable (t->rec_enable_control());
299 if (is_midi_track()) {
300 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
301 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
306 /* this will work for busses and tracks, and needs to be called to
307 set up the name entry/name label display.
311 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
312 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
314 update_monitoring_display ();
317 mute_button->unset_flags (Gtk::CAN_FOCUS);
318 solo_button->unset_flags (Gtk::CAN_FOCUS);
322 if (_route->is_monitor() || _route->is_master()) {
323 solo_button->hide ();
330 setup_invert_buttons ();
331 set_invert_button_state ();
333 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
334 bus_send_display_changed (s);
336 update_mute_display ();
337 update_solo_display ();
339 if (!UIConfiguration::instance().get_blink_rec_arm()) {
340 blink_rec_display(true); // set initial rec-en button state
343 check_rec_enable_sensitivity ();
344 maybe_add_route_print_mgr ();
345 route_color_changed();
349 RouteUI::polarity_changed ()
355 set_invert_button_state ();
359 RouteUI::mute_press (GdkEventButton* ev)
361 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
365 //if this is a binding action, let the ArdourButton handle it
366 if ( BindingProxy::is_bind_action(ev) )
369 multiple_mute_change = false;
371 if (Keyboard::is_context_menu_event (ev)) {
377 mute_menu->popup(0,ev->time);
383 if (Keyboard::is_button2_event (ev)) {
384 // button2-click is "momentary"
386 _mute_release = new SoloMuteRelease (_route->muted ());
389 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
391 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
393 /* toggle mute on everything (but
394 * exclude the master and monitor)
396 * because we are going to erase
397 * elements of the list we need to work
401 boost::shared_ptr<RouteList> copy (new RouteList);
403 *copy = *_session->get_routes ();
405 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
406 if ((*i)->is_master() || (*i)->is_monitor()) {
414 _mute_release->routes = copy;
418 _session->set_mute (copy, !_route->muted());
420 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
422 /* Primary-button1 inverts the implication of
423 the group being active. If the group is
424 active (for mute), then this modifier means
425 "do not apply to mute". If the group is
426 inactive (for mute), then this modifier
427 means "apply to route". This is all
428 accomplished by passing just the actual
429 route, along with the InverseGroup group
432 NOTE: Primary-button2 is MIDI learn.
435 boost::shared_ptr<RouteList> rl;
437 if (ev->button == 1) {
439 rl.reset (new RouteList);
440 rl->push_back (_route);
443 _mute_release->routes = rl;
447 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
452 /* plain click applies change to this route */
454 boost::shared_ptr<RouteList> rl (new RouteList);
455 rl->push_back (_route);
458 _mute_release->routes = rl;
461 _session->set_mute (rl, !_route->muted());
471 RouteUI::mute_release (GdkEventButton* /*ev*/)
475 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
476 delete _mute_release;
484 RouteUI::edit_output_configuration ()
486 if (output_selector == 0) {
488 boost::shared_ptr<Send> send;
489 boost::shared_ptr<IO> output;
491 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
492 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
493 output = send->output();
495 output = _route->output ();
498 output = _route->output ();
501 output_selector = new IOSelectorWindow (_session, output);
504 if (output_selector->is_visible()) {
505 output_selector->get_toplevel()->get_window()->raise();
507 output_selector->present ();
510 //output_selector->set_keep_above (true);
514 RouteUI::edit_input_configuration ()
516 if (input_selector == 0) {
517 input_selector = new IOSelectorWindow (_session, _route->input());
520 if (input_selector->is_visible()) {
521 input_selector->get_toplevel()->get_window()->raise();
523 input_selector->present ();
526 //input_selector->set_keep_above (true);
530 RouteUI::solo_press(GdkEventButton* ev)
532 /* ignore double/triple clicks */
534 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
538 //if this is a binding action, let the ArdourButton handle it
539 if ( BindingProxy::is_bind_action(ev) )
542 multiple_solo_change = false;
544 if (Keyboard::is_context_menu_event (ev)) {
546 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
547 ! (solo_safe_led && solo_safe_led->is_visible())) {
549 if (solo_menu == 0) {
553 solo_menu->popup (1, ev->time);
558 if (Keyboard::is_button2_event (ev)) {
560 // button2-click is "momentary"
561 _solo_release = new SoloMuteRelease (_route->self_soloed());
564 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
566 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
568 /* Primary-Tertiary-click applies change to all routes */
571 _solo_release->routes = _session->get_routes ();
575 if (Config->get_solo_control_is_listen_control()) {
576 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::UseGroup);
578 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, Controllable::UseGroup);
581 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
583 // Primary-Secondary-click: exclusively solo this track
586 _solo_release->exclusive = true;
588 boost::shared_ptr<RouteList> routes = _session->get_routes();
590 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
591 if ((*i)->soloed ()) {
592 _solo_release->routes_on->push_back (*i);
594 _solo_release->routes_off->push_back (*i);
599 if (Config->get_solo_control_is_listen_control()) {
600 /* ??? we need a just_one_listen() method */
603 _session->set_just_one_solo (_route, true);
606 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
608 // shift-click: toggle solo isolated status
610 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
611 delete _solo_release;
614 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
616 /* Primary-button1: solo mix group.
617 NOTE: Primary-button2 is MIDI learn.
620 /* Primary-button1 applies change to the mix group even if it is not active
621 NOTE: Primary-button2 is MIDI learn.
624 boost::shared_ptr<RouteList> rl;
626 if (ev->button == 1) {
628 /* Primary-button1 inverts the implication of
629 the group being active. If the group is
630 active (for solo), then this modifier means
631 "do not apply to solo". If the group is
632 inactive (for mute), then this modifier
633 means "apply to route". This is all
634 accomplished by passing just the actual
635 route, along with the InverseGroup group
638 NOTE: Primary-button2 is MIDI learn.
641 rl.reset (new RouteList);
642 rl->push_back (_route);
645 _solo_release->routes = rl;
650 if (Config->get_solo_control_is_listen_control()) {
651 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
653 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
657 delete _solo_release;
662 /* click: solo this route */
664 boost::shared_ptr<RouteList> rl (new RouteList);
665 rl->push_back (route());
668 _solo_release->routes = rl;
672 if (Config->get_solo_control_is_listen_control()) {
673 _session->set_listen (rl, !_route->listening_via_monitor());
675 _session->set_solo (rl, !_route->self_soloed());
685 RouteUI::solo_release (GdkEventButton* /*ev*/)
689 if (_solo_release->exclusive) {
693 if (Config->get_solo_control_is_listen_control()) {
694 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
696 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
700 delete _solo_release;
708 RouteUI::rec_enable_press(GdkEventButton* ev)
710 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
714 //if this is a binding action, let the ArdourButton handle it
715 if ( BindingProxy::is_bind_action(ev) )
718 if (!_session->engine().connected()) {
719 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
724 if (is_midi_track()) {
726 /* rec-enable button exits from step editing */
728 if (midi_track()->step_editing()) {
729 midi_track()->set_step_editing (false);
734 if (is_track() && rec_enable_button) {
736 if (Keyboard::is_button2_event (ev)) {
738 //rec arm does not have a momentary mode
741 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
744 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
746 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
748 /* Primary-button1 applies change to the route group (even if it is not active)
749 NOTE: Primary-button2 is MIDI learn.
752 if (ev->button == 1) {
754 boost::shared_ptr<RouteList> rl;
756 rl.reset (new RouteList);
757 rl->push_back (_route);
760 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
763 } else if (Keyboard::is_context_menu_event (ev)) {
765 /* do this on release */
769 boost::shared_ptr<RouteList> rl (new RouteList);
770 rl->push_back (route());
772 _session->set_record_enabled (rl, !_route->record_enabled());
780 RouteUI::monitoring_changed ()
782 update_monitoring_display ();
786 RouteUI::update_monitoring_display ()
792 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
798 MonitorState ms = t->monitoring_state();
800 if (t->monitoring_choice() & MonitorInput) {
801 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
803 if (ms & MonitoringInput) {
804 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
806 monitor_input_button->unset_active_state ();
810 if (t->monitoring_choice() & MonitorDisk) {
811 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
813 if (ms & MonitoringDisk) {
814 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
816 monitor_disk_button->unset_active_state ();
822 RouteUI::monitor_input_press(GdkEventButton*)
828 RouteUI::monitor_input_release(GdkEventButton* ev)
830 return monitor_release (ev, MonitorInput);
834 RouteUI::monitor_disk_press (GdkEventButton*)
840 RouteUI::monitor_disk_release (GdkEventButton* ev)
842 return monitor_release (ev, MonitorDisk);
846 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
848 if (ev->button != 1) {
852 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
859 boost::shared_ptr<RouteList> rl;
861 /* XXX for now, monitoring choices are orthogonal. cue monitoring
862 will follow in 3.X but requires mixing the input and playback (disk)
863 signal together, which requires yet more buffers.
866 if (t->monitoring_choice() & monitor_choice) {
867 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
869 /* this line will change when the options are non-orthogonal */
870 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
874 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
875 rl = _session->get_routes ();
877 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
878 if (_route->route_group() && _route->route_group()->is_monitoring()) {
879 rl = _route->route_group()->route_list();
881 rl.reset (new RouteList);
882 rl->push_back (route());
885 rl.reset (new RouteList);
886 rl->push_back (route());
890 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
896 RouteUI::build_record_menu ()
899 record_menu = new Menu;
900 record_menu->set_name ("ArdourContextMenu");
901 using namespace Menu_Helpers;
902 MenuList& items = record_menu->items();
904 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
905 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
907 if (is_midi_track()) {
908 items.push_back (SeparatorElem());
909 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
910 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
914 if (step_edit_item) {
915 step_edit_item->set_sensitive (!_route->record_enabled());
916 step_edit_item->set_active (midi_track()->step_editing());
919 rec_safe_item->set_sensitive (!_route->record_enabled());
920 rec_safe_item->set_active (_route->record_safe());
925 RouteUI::toggle_step_edit ()
927 if (!is_midi_track() || _route->record_enabled()) {
931 midi_track()->set_step_editing (step_edit_item->get_active());
935 RouteUI::toggle_rec_safe ()
937 if (_route->record_enabled()) {
941 boost::shared_ptr<RouteList> rl (new RouteList);
942 rl->push_back (_route);
943 _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
947 RouteUI::step_edit_changed (bool yn)
950 if (rec_enable_button) {
951 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
954 start_step_editing ();
956 if (step_edit_item) {
957 step_edit_item->set_active (true);
962 if (rec_enable_button) {
963 rec_enable_button->unset_active_state ();
966 stop_step_editing ();
968 if (step_edit_item) {
969 step_edit_item->set_active (false);
975 RouteUI::rec_enable_release (GdkEventButton* ev)
977 if (Keyboard::is_context_menu_event (ev)) {
978 build_record_menu ();
980 record_menu->popup (1, ev->time);
989 RouteUI::build_sends_menu ()
991 using namespace Menu_Helpers;
993 sends_menu = new Menu;
994 sends_menu->set_name ("ArdourContextMenu");
995 MenuList& items = sends_menu->items();
998 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1002 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1006 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1010 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1014 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1018 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1021 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1025 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1028 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1029 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1030 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1035 RouteUI::create_sends (Placement p, bool include_buses)
1037 _session->globally_add_internal_sends (_route, p, include_buses);
1041 RouteUI::create_selected_sends (Placement p, bool include_buses)
1043 boost::shared_ptr<RouteList> rlist (new RouteList);
1044 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1046 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1047 RouteTimeAxisView* rtv;
1049 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1050 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1051 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1052 rlist->push_back (rui->route());
1058 _session->add_internal_sends (_route, p, rlist);
1062 RouteUI::set_sends_gain_from_track ()
1064 _session->globally_set_send_gains_from_track (_route);
1068 RouteUI::set_sends_gain_to_zero ()
1070 _session->globally_set_send_gains_to_zero (_route);
1074 RouteUI::set_sends_gain_to_unity ()
1076 _session->globally_set_send_gains_to_unity (_route);
1080 RouteUI::show_sends_press(GdkEventButton* ev)
1082 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1086 if (!is_track() && show_sends_button) {
1088 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1090 // do nothing on midi sigc::bind event
1093 } else if (Keyboard::is_context_menu_event (ev)) {
1095 if (sends_menu == 0) {
1096 build_sends_menu ();
1099 sends_menu->popup (0, ev->time);
1103 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1106 set_showing_sends_to (boost::shared_ptr<Route> ());
1108 set_showing_sends_to (_route);
1117 RouteUI::show_sends_release (GdkEventButton*)
1123 RouteUI::send_blink (bool onoff)
1125 if (!show_sends_button) {
1130 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1132 show_sends_button->unset_active_state ();
1136 Gtkmm2ext::ActiveState
1137 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1139 if (r->is_master() || r->is_monitor()) {
1140 return Gtkmm2ext::Off;
1143 if (Config->get_solo_control_is_listen_control()) {
1145 if (r->listening_via_monitor()) {
1146 return Gtkmm2ext::ExplicitActive;
1148 return Gtkmm2ext::Off;
1154 if (!r->self_soloed()) {
1155 return Gtkmm2ext::ImplicitActive;
1157 return Gtkmm2ext::ExplicitActive;
1160 return Gtkmm2ext::Off;
1164 Gtkmm2ext::ActiveState
1165 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1167 if (r->is_master() || r->is_monitor()) {
1168 return Gtkmm2ext::Off;
1171 if (r->solo_isolated()) {
1172 return Gtkmm2ext::ExplicitActive;
1174 return Gtkmm2ext::Off;
1178 Gtkmm2ext::ActiveState
1179 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1181 if (r->is_master() || r->is_monitor()) {
1182 return Gtkmm2ext::Off;
1185 if (r->solo_safe()) {
1186 return Gtkmm2ext::ExplicitActive;
1188 return Gtkmm2ext::Off;
1193 RouteUI::update_solo_display ()
1195 bool yn = _route->solo_safe ();
1197 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1198 solo_safe_check->set_active (yn);
1201 yn = _route->solo_isolated ();
1203 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1204 solo_isolated_check->set_active (yn);
1207 set_button_names ();
1209 if (solo_isolated_led) {
1210 if (_route->solo_isolated()) {
1211 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1213 solo_isolated_led->unset_active_state ();
1217 if (solo_safe_led) {
1218 if (_route->solo_safe()) {
1219 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1221 solo_safe_led->unset_active_state ();
1225 solo_button->set_active_state (solo_active_state (_route));
1227 /* some changes to solo status can affect mute display, so catch up
1230 update_mute_display ();
1234 RouteUI::solo_changed_so_update_mute ()
1236 update_mute_display ();
1240 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1242 if (r->is_monitor()) {
1243 return ActiveState(0);
1246 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1250 return Gtkmm2ext::ExplicitActive;
1251 } else if (r->muted_by_others ()) {
1252 /* this will reflect both solo mutes AND master mutes */
1253 return Gtkmm2ext::ImplicitActive;
1255 /* no mute at all */
1256 return Gtkmm2ext::Off;
1263 return Gtkmm2ext::ExplicitActive;
1264 } else if (r->mute_master()->muted_by_others()) {
1265 /* note the direct use of MuteMaster API here. We are
1266 not interested in showing
1267 others-soloed-so-this-muted status in this branch.
1269 return Gtkmm2ext::ImplicitActive;
1271 /* no mute at all */
1272 return Gtkmm2ext::Off;
1276 return ActiveState(0);
1280 RouteUI::update_mute_display ()
1286 mute_button->set_active_state (mute_active_state (_session, _route));
1290 RouteUI::update_vca_display ()
1296 VCAList vcas (_session->vca_manager().vcas());
1299 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1300 if (_route->slaved_to (*v)) {
1301 if (!label.empty()) {
1304 label += PBD::to_string ((*v)->number(), std::dec);
1308 if (label.empty()) {
1310 vca_button->set_active_state (Gtkmm2ext::Off);
1312 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1315 vca_button->set_text (label);
1319 RouteUI::route_rec_enable_changed ()
1321 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1322 update_monitoring_display ();
1326 RouteUI::session_rec_enable_changed ()
1328 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1329 update_monitoring_display ();
1333 RouteUI::blink_rec_display (bool blinkOn)
1335 if (!rec_enable_button || !_route) {
1338 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1342 if (_route->record_enabled()) {
1343 switch (_session->record_status ()) {
1344 case Session::Recording:
1345 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1348 case Session::Disabled:
1349 case Session::Enabled:
1350 if ( UIConfiguration::instance().get_blink_rec_arm() )
1351 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1353 rec_enable_button->set_active_state ( ImplicitActive );
1358 if (step_edit_item) {
1359 step_edit_item->set_sensitive (false);
1363 rec_enable_button->unset_active_state ();
1365 if (step_edit_item) {
1366 step_edit_item->set_sensitive (true);
1370 check_rec_enable_sensitivity ();
1374 RouteUI::build_solo_menu (void)
1376 using namespace Menu_Helpers;
1378 solo_menu = new Menu;
1379 solo_menu->set_name ("ArdourContextMenu");
1380 MenuList& items = solo_menu->items();
1381 Gtk::CheckMenuItem* check;
1383 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1384 check->set_active (_route->solo_isolated());
1385 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1386 items.push_back (CheckMenuElem(*check));
1387 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1390 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1391 check->set_active (_route->solo_safe());
1392 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1393 items.push_back (CheckMenuElem(*check));
1394 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1397 //items.push_back (SeparatorElem());
1398 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1403 RouteUI::build_mute_menu(void)
1405 using namespace Menu_Helpers;
1407 mute_menu = new Menu;
1408 mute_menu->set_name ("ArdourContextMenu");
1410 MenuList& items = mute_menu->items();
1412 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1413 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1414 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1415 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1416 pre_fader_mute_check->show_all();
1418 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1419 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1420 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1421 items.push_back (CheckMenuElem(*post_fader_mute_check));
1422 post_fader_mute_check->show_all();
1424 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1425 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1426 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1427 items.push_back (CheckMenuElem(*listen_mute_check));
1428 listen_mute_check->show_all();
1430 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1431 init_mute_menu(MuteMaster::Main, main_mute_check);
1432 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1433 items.push_back (CheckMenuElem(*main_mute_check));
1434 main_mute_check->show_all();
1436 //items.push_back (SeparatorElem());
1437 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1439 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1443 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1445 check->set_active (_route->mute_points() & mp);
1449 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1451 if (check->get_active()) {
1452 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1454 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1459 RouteUI::muting_change ()
1461 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1464 MuteMaster::MutePoint current = _route->mute_points ();
1466 yn = (current & MuteMaster::PreFader);
1468 if (pre_fader_mute_check->get_active() != yn) {
1469 pre_fader_mute_check->set_active (yn);
1472 yn = (current & MuteMaster::PostFader);
1474 if (post_fader_mute_check->get_active() != yn) {
1475 post_fader_mute_check->set_active (yn);
1478 yn = (current & MuteMaster::Listen);
1480 if (listen_mute_check->get_active() != yn) {
1481 listen_mute_check->set_active (yn);
1484 yn = (current & MuteMaster::Main);
1486 if (main_mute_check->get_active() != yn) {
1487 main_mute_check->set_active (yn);
1492 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1494 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1498 bool view = solo_isolated_led->active_state();
1499 bool model = _route->solo_isolated();
1501 /* called BEFORE the view has changed */
1503 if (ev->button == 1) {
1504 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1507 /* disable isolate for all routes */
1508 DisplaySuspender ds;
1509 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1511 /* enable isolate for all routes */
1512 DisplaySuspender ds;
1513 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1518 if (model == view) {
1520 /* flip just this route */
1522 boost::shared_ptr<RouteList> rl (new RouteList);
1523 rl->push_back (_route);
1524 DisplaySuspender ds;
1525 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1534 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1536 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1540 bool view = solo_safe_led->active_state();
1541 bool model = _route->solo_safe();
1543 if (ev->button == 1) {
1544 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1545 boost::shared_ptr<RouteList> rl (_session->get_routes());
1547 /* disable solo safe for all routes */
1548 DisplaySuspender ds;
1549 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1550 (*i)->set_solo_safe (false, Controllable::NoGroup);
1553 /* enable solo safe for all routes */
1554 DisplaySuspender ds;
1555 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1556 (*i)->set_solo_safe (true, Controllable::NoGroup);
1561 if (model == view) {
1562 /* flip just this route */
1563 _route->set_solo_safe (!view, Controllable::NoGroup);
1572 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1574 bool view = check->get_active();
1575 bool model = _route->solo_isolated();
1577 /* called AFTER the view has changed */
1579 if (model != view) {
1580 _route->set_solo_isolated (view, Controllable::UseGroup);
1585 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1587 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1590 /** Ask the user to choose a colour, and then apply that color to my route
1593 RouteUI::choose_color ()
1596 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1603 /** Set the route's own color. This may not be used for display if
1604 * the route is in a group which shares its color with its routes.
1607 RouteUI::set_color (const Gdk::Color & c)
1609 /* leave _color alone in the group case so that tracks can retain their
1610 * own pre-group colors.
1615 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1617 /* note: we use the route state ID here so that color is the same for both
1618 the time axis view and the mixer strip
1621 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1622 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
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 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1643 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1646 _color.set_green (g);
1647 _color.set_blue (b);
1652 /** @return true if this name should be used for the route, otherwise false */
1654 RouteUI::verify_new_route_name (const std::string& name)
1656 if (name.find (':') == string::npos) {
1660 MessageDialog colon_msg (
1661 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1662 false, MESSAGE_QUESTION, BUTTONS_NONE
1665 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1666 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1668 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1672 RouteUI::route_rename ()
1674 ArdourPrompter name_prompter (true);
1679 name_prompter.set_title (_("Rename Track"));
1681 name_prompter.set_title (_("Rename Bus"));
1683 name_prompter.set_prompt (_("New name:"));
1684 name_prompter.set_initial_text (_route->name());
1685 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1686 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1687 name_prompter.show_all ();
1690 switch (name_prompter.run ()) {
1691 case Gtk::RESPONSE_ACCEPT:
1692 name_prompter.get_result (result);
1693 name_prompter.hide ();
1694 if (result.length()) {
1695 if (verify_new_route_name (result)) {
1696 _route->set_name (result);
1699 /* back to name prompter */
1703 /* nothing entered, just get out of here */
1718 RouteUI::property_changed (const PropertyChange& what_changed)
1720 if (what_changed.contains (ARDOUR::Properties::name)) {
1721 name_label.set_text (_route->name());
1726 RouteUI::toggle_comment_editor ()
1728 // if (ignore_toggle) {
1732 if (comment_window && comment_window->is_visible ()) {
1733 comment_window->hide ();
1735 open_comment_editor ();
1741 RouteUI::open_comment_editor ()
1743 if (comment_window == 0) {
1744 setup_comment_editor ();
1748 title = _route->name();
1749 title += _(": comment editor");
1751 comment_window->set_title (title);
1752 comment_window->present();
1756 RouteUI::setup_comment_editor ()
1758 comment_window = new ArdourWindow (""); // title will be reset to show route
1759 comment_window->set_skip_taskbar_hint (true);
1760 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1761 comment_window->set_default_size (400, 200);
1763 comment_area = manage (new TextView());
1764 comment_area->set_name ("MixerTrackCommentArea");
1765 comment_area->set_wrap_mode (WRAP_WORD);
1766 comment_area->set_editable (true);
1767 comment_area->get_buffer()->set_text (_route->comment());
1768 comment_area->show ();
1770 comment_window->add (*comment_area);
1774 RouteUI::comment_changed ()
1776 ignore_comment_edit = true;
1778 comment_area->get_buffer()->set_text (_route->comment());
1780 ignore_comment_edit = false;
1784 RouteUI::comment_editor_done_editing ()
1786 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1788 string const str = comment_area->get_buffer()->get_text();
1789 if (str == _route->comment ()) {
1793 _route->set_comment (str, this);
1797 RouteUI::set_route_active (bool a, bool apply_to_selection)
1799 if (apply_to_selection) {
1800 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1802 _route->set_active (a, this);
1807 RouteUI::duplicate_selected_routes ()
1809 ARDOUR_UI::instance()->start_duplicate_routes();
1813 RouteUI::toggle_denormal_protection ()
1815 if (denormal_menu_item) {
1819 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1821 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1822 _route->set_denormal_protection (x);
1828 RouteUI::denormal_protection_changed ()
1830 if (denormal_menu_item) {
1831 denormal_menu_item->set_active (_route->denormal_protection());
1836 RouteUI::disconnect_input ()
1838 _route->input()->disconnect (this);
1842 RouteUI::disconnect_output ()
1844 _route->output()->disconnect (this);
1848 RouteUI::is_track () const
1850 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1853 boost::shared_ptr<Track>
1854 RouteUI::track() const
1856 return boost::dynamic_pointer_cast<Track>(_route);
1860 RouteUI::is_audio_track () const
1862 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1865 boost::shared_ptr<AudioTrack>
1866 RouteUI::audio_track() const
1868 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1872 RouteUI::is_midi_track () const
1874 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1877 boost::shared_ptr<MidiTrack>
1878 RouteUI::midi_track() const
1880 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1884 RouteUI::has_audio_outputs () const
1886 return (_route->n_outputs().n_audio() > 0);
1890 RouteUI::name() const
1892 return _route->name();
1896 RouteUI::map_frozen ()
1898 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1900 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1903 check_rec_enable_sensitivity ();
1908 RouteUI::adjust_latency ()
1910 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1914 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1917 std::string safe_name;
1920 prompter.get_result (name, true);
1922 safe_name = legalize_for_path (name);
1923 safe_name += template_suffix;
1925 path = Glib::build_filename (dir, safe_name);
1927 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1928 bool overwrite = overwrite_file_dialog (prompter,
1929 _("Confirm Template Overwrite"),
1930 _("A template already exists with that name. Do you want to overwrite it?"));
1937 _route->save_as_template (path, name);
1943 RouteUI::save_as_template ()
1947 dir = ARDOUR::user_route_template_directory ();
1949 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1950 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1954 ArdourPrompter prompter (true); // modal
1956 prompter.set_title (_("Save As Template"));
1957 prompter.set_prompt (_("Template name:"));
1958 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1960 bool finished = false;
1962 switch (prompter.run()) {
1963 case RESPONSE_ACCEPT:
1964 finished = process_save_template_prompter (prompter, dir);
1974 RouteUI::check_rec_enable_sensitivity ()
1976 if (!rec_enable_button) {
1977 assert (0); // This should not happen
1980 if (!_session->writable()) {
1981 rec_enable_button->set_sensitive (false);
1985 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1986 rec_enable_button->set_sensitive (false);
1987 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1988 rec_enable_button->set_sensitive (false);
1990 rec_enable_button->set_sensitive (true);
1992 if (_route && _route->record_safe ()) {
1993 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1995 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1997 update_monitoring_display ();
2001 RouteUI::parameter_changed (string const & p)
2003 /* this handles RC and per-session parameter changes */
2005 if (p == "disable-disarm-during-roll") {
2006 check_rec_enable_sensitivity ();
2007 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2008 set_button_names ();
2009 } else if (p == "auto-input") {
2010 update_monitoring_display ();
2011 } else if (p == "blink-rec-arm") {
2012 if (UIConfiguration::instance().get_blink_rec_arm()) {
2013 rec_blink_connection.disconnect ();
2014 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2016 rec_blink_connection.disconnect ();
2017 RouteUI::blink_rec_display(false);
2023 RouteUI::step_gain_up ()
2025 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2029 RouteUI::page_gain_up ()
2031 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2035 RouteUI::step_gain_down ()
2037 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2041 RouteUI::page_gain_down ()
2043 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2047 RouteUI::open_remote_control_id_dialog ()
2049 ArdourDialog dialog (_("Remote Control ID"));
2050 SpinButton* spin = 0;
2052 dialog.get_vbox()->set_border_width (18);
2054 if (Config->get_remote_model() == UserOrdered) {
2055 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2057 HBox* hbox = manage (new HBox);
2058 hbox->set_spacing (6);
2059 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2060 spin = manage (new SpinButton);
2061 spin->set_digits (0);
2062 spin->set_increments (1, 10);
2063 spin->set_range (0, limit);
2064 spin->set_value (_route->remote_control_id());
2065 hbox->pack_start (*spin);
2066 dialog.get_vbox()->pack_start (*hbox);
2068 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2069 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2071 Label* l = manage (new Label());
2072 if (_route->is_master() || _route->is_monitor()) {
2073 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2074 "The remote control ID of %3 cannot be changed."),
2075 Gtkmm2ext::markup_escape_text (_route->name()),
2076 _route->remote_control_id(),
2077 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2079 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2080 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2081 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2082 (is_track() ? _("track") : _("bus")),
2083 _route->remote_control_id(),
2084 "<span size=\"small\" style=\"italic\">",
2086 Gtkmm2ext::markup_escape_text (_route->name()),
2089 dialog.get_vbox()->pack_start (*l);
2090 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2094 int const r = dialog.run ();
2096 if (r == RESPONSE_ACCEPT && spin) {
2097 _route->set_remote_control_id (spin->get_value_as_int ());
2102 RouteUI::setup_invert_buttons ()
2104 /* remove old invert buttons */
2105 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2106 _invert_button_box.remove (**i);
2109 _invert_buttons.clear ();
2111 if (!_route || !_route->input()) {
2115 uint32_t const N = _route->input()->n_ports().n_audio ();
2117 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2119 for (uint32_t i = 0; i < to_add; ++i) {
2120 ArdourButton* b = manage (new ArdourButton);
2121 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2122 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2124 b->set_name (X_("invert button"));
2127 b->set_text (string_compose (X_("Ø (%1)"), N));
2129 b->set_text (X_("Ø"));
2132 b->set_text (string_compose (X_("Ø%1"), i + 1));
2135 if (N <= _max_invert_buttons) {
2136 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track. Right-click to show menu."), i + 1));
2138 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2141 _invert_buttons.push_back (b);
2142 _invert_button_box.pack_start (*b);
2145 _invert_button_box.set_spacing (1);
2146 _invert_button_box.show_all ();
2150 RouteUI::set_invert_button_state ()
2152 uint32_t const N = _route->input()->n_ports().n_audio();
2153 if (N > _max_invert_buttons) {
2155 /* One button for many channels; explicit active if all channels are inverted,
2156 implicit active if some are, off if none are.
2159 ArdourButton* b = _invert_buttons.front ();
2161 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2162 b->set_active_state (Gtkmm2ext::ExplicitActive);
2163 } else if (_route->phase_invert().any()) {
2164 b->set_active_state (Gtkmm2ext::ImplicitActive);
2166 b->set_active_state (Gtkmm2ext::Off);
2171 /* One button per channel; just set active */
2174 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2175 (*i)->set_active (_route->phase_invert (j));
2182 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2184 if (ev->button == 1 && i < _invert_buttons.size()) {
2185 uint32_t const N = _route->input()->n_ports().n_audio ();
2186 if (N <= _max_invert_buttons) {
2187 /* left-click inverts phase so long as we have a button per channel */
2188 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2197 RouteUI::invert_press (GdkEventButton* ev)
2199 using namespace Menu_Helpers;
2201 uint32_t const N = _route->input()->n_ports().n_audio();
2202 if (N <= _max_invert_buttons && ev->button != 3) {
2203 /* If we have an invert button per channel, we only pop
2204 up a menu on right-click; left click is handled
2210 delete _invert_menu;
2211 _invert_menu = new Menu;
2212 _invert_menu->set_name ("ArdourContextMenu");
2213 MenuList& items = _invert_menu->items ();
2215 for (uint32_t i = 0; i < N; ++i) {
2216 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2217 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2218 ++_i_am_the_modifier;
2219 e->set_active (_route->phase_invert (i));
2220 --_i_am_the_modifier;
2223 _invert_menu->popup (0, ev->time);
2229 RouteUI::invert_menu_toggled (uint32_t c)
2231 if (_i_am_the_modifier) {
2235 _route->set_phase_invert (c, !_route->phase_invert (c));
2239 RouteUI::set_invert_sensitive (bool yn)
2241 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2242 (*b)->set_sensitive (yn);
2247 RouteUI::request_redraw ()
2250 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2254 /** The Route's gui_changed signal has been emitted */
2256 RouteUI::route_gui_changed (string what_changed)
2258 if (what_changed == "color") {
2259 if (set_color_from_route () == 0) {
2260 route_color_changed ();
2266 RouteUI::track_mode_changed (void)
2269 switch (track()->mode()) {
2270 case ARDOUR::NonLayered:
2271 case ARDOUR::Normal:
2272 rec_enable_button->set_icon (ArdourIcon::RecButton);
2274 case ARDOUR::Destructive:
2275 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2278 rec_enable_button->queue_draw();
2281 /** @return the color that this route should use; it maybe its own,
2282 or it maybe that of its route group.
2285 RouteUI::color () const
2287 RouteGroup* g = _route->route_group ();
2289 if (g && g->is_color()) {
2291 set_color_from_rgba (c, GroupTabs::group_color (g));
2299 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2301 _showing_sends_to = send_to;
2302 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2306 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2308 if (_route == send_to) {
2309 show_sends_button->set_active (true);
2310 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2312 show_sends_button->set_active (false);
2313 send_blink_connection.disconnect ();
2318 RouteUI::route_group() const
2320 return _route->route_group();
2324 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2325 : WM::ProxyBase (name, string())
2326 , _route (boost::weak_ptr<Route> (route))
2328 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2331 RoutePinWindowProxy::~RoutePinWindowProxy()
2336 ARDOUR::SessionHandlePtr*
2337 RoutePinWindowProxy::session_handle ()
2339 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2340 if (aw) { return aw; }
2345 RoutePinWindowProxy::get (bool create)
2347 boost::shared_ptr<Route> r = _route.lock ();
2356 _window = new PluginPinDialog (r);
2357 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2359 aw->set_session (_session);
2361 _window->show_all ();
2367 RoutePinWindowProxy::route_going_away ()
2371 WM::Manager::instance().remove (this);
2372 going_away_connection.disconnect();
2376 RouteUI::maybe_add_route_print_mgr ()
2378 if (_route->pinmgr_proxy ()) {
2381 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2382 string_compose ("RPM-%1", _route->id()), _route);
2383 wp->set_session (_session);
2385 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2387 wp->set_state (*ui_xml, 0);
2391 void* existing_ui = _route->pinmgr_proxy ();
2393 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2396 _route->set_pingmgr_proxy (wp);
2398 WM::Manager::instance().register_window (wp);
2402 RouteUI::manage_pins ()
2404 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();