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);
1247 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1251 return Gtkmm2ext::ExplicitActive;
1252 } else if (r->muted_by_others()) {
1253 return Gtkmm2ext::ImplicitActive;
1255 /* no mute at all */
1256 return Gtkmm2ext::Off;
1263 return Gtkmm2ext::ExplicitActive;
1265 /* no mute at all */
1266 return Gtkmm2ext::Off;
1270 return ActiveState(0);
1274 RouteUI::update_mute_display ()
1280 mute_button->set_active_state (mute_active_state (_session, _route));
1284 RouteUI::update_vca_display ()
1290 VCAList vcas (_session->vca_manager().vcas());
1293 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1294 if (_route->slaved_to (*v)) {
1295 if (!label.empty()) {
1298 label += PBD::to_string ((*v)->number(), std::dec);
1302 if (label.empty()) {
1304 vca_button->set_active_state (Gtkmm2ext::Off);
1306 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1309 vca_button->set_text (label);
1313 RouteUI::route_rec_enable_changed ()
1315 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1316 update_monitoring_display ();
1320 RouteUI::session_rec_enable_changed ()
1322 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1323 update_monitoring_display ();
1327 RouteUI::blink_rec_display (bool blinkOn)
1329 if (!rec_enable_button || !_route) {
1332 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1336 if (_route->record_enabled()) {
1337 switch (_session->record_status ()) {
1338 case Session::Recording:
1339 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1342 case Session::Disabled:
1343 case Session::Enabled:
1344 if ( UIConfiguration::instance().get_blink_rec_arm() )
1345 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1347 rec_enable_button->set_active_state ( ImplicitActive );
1352 if (step_edit_item) {
1353 step_edit_item->set_sensitive (false);
1357 rec_enable_button->unset_active_state ();
1359 if (step_edit_item) {
1360 step_edit_item->set_sensitive (true);
1364 check_rec_enable_sensitivity ();
1368 RouteUI::build_solo_menu (void)
1370 using namespace Menu_Helpers;
1372 solo_menu = new Menu;
1373 solo_menu->set_name ("ArdourContextMenu");
1374 MenuList& items = solo_menu->items();
1375 Gtk::CheckMenuItem* check;
1377 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1378 check->set_active (_route->solo_isolated());
1379 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1380 items.push_back (CheckMenuElem(*check));
1381 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1384 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1385 check->set_active (_route->solo_safe());
1386 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1387 items.push_back (CheckMenuElem(*check));
1388 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1391 //items.push_back (SeparatorElem());
1392 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1397 RouteUI::build_mute_menu(void)
1399 using namespace Menu_Helpers;
1401 mute_menu = new Menu;
1402 mute_menu->set_name ("ArdourContextMenu");
1404 MenuList& items = mute_menu->items();
1406 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1407 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1408 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1409 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1410 pre_fader_mute_check->show_all();
1412 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1413 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1414 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1415 items.push_back (CheckMenuElem(*post_fader_mute_check));
1416 post_fader_mute_check->show_all();
1418 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1419 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1420 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1421 items.push_back (CheckMenuElem(*listen_mute_check));
1422 listen_mute_check->show_all();
1424 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1425 init_mute_menu(MuteMaster::Main, main_mute_check);
1426 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1427 items.push_back (CheckMenuElem(*main_mute_check));
1428 main_mute_check->show_all();
1430 //items.push_back (SeparatorElem());
1431 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1433 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1437 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1439 check->set_active (_route->mute_points() & mp);
1443 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1445 if (check->get_active()) {
1446 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1448 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1453 RouteUI::muting_change ()
1455 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1458 MuteMaster::MutePoint current = _route->mute_points ();
1460 yn = (current & MuteMaster::PreFader);
1462 if (pre_fader_mute_check->get_active() != yn) {
1463 pre_fader_mute_check->set_active (yn);
1466 yn = (current & MuteMaster::PostFader);
1468 if (post_fader_mute_check->get_active() != yn) {
1469 post_fader_mute_check->set_active (yn);
1472 yn = (current & MuteMaster::Listen);
1474 if (listen_mute_check->get_active() != yn) {
1475 listen_mute_check->set_active (yn);
1478 yn = (current & MuteMaster::Main);
1480 if (main_mute_check->get_active() != yn) {
1481 main_mute_check->set_active (yn);
1486 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1488 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1492 bool view = solo_isolated_led->active_state();
1493 bool model = _route->solo_isolated();
1495 /* called BEFORE the view has changed */
1497 if (ev->button == 1) {
1498 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1501 /* disable isolate for all routes */
1502 DisplaySuspender ds;
1503 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1505 /* enable isolate for all routes */
1506 DisplaySuspender ds;
1507 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1512 if (model == view) {
1514 /* flip just this route */
1516 boost::shared_ptr<RouteList> rl (new RouteList);
1517 rl->push_back (_route);
1518 DisplaySuspender ds;
1519 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1528 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1530 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1534 bool view = solo_safe_led->active_state();
1535 bool model = _route->solo_safe();
1537 if (ev->button == 1) {
1538 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1539 boost::shared_ptr<RouteList> rl (_session->get_routes());
1541 /* disable solo safe for all routes */
1542 DisplaySuspender ds;
1543 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1544 (*i)->set_solo_safe (false, Controllable::NoGroup);
1547 /* enable solo safe for all routes */
1548 DisplaySuspender ds;
1549 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1550 (*i)->set_solo_safe (true, Controllable::NoGroup);
1555 if (model == view) {
1556 /* flip just this route */
1557 _route->set_solo_safe (!view, Controllable::NoGroup);
1566 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1568 bool view = check->get_active();
1569 bool model = _route->solo_isolated();
1571 /* called AFTER the view has changed */
1573 if (model != view) {
1574 _route->set_solo_isolated (view, Controllable::UseGroup);
1579 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1581 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1584 /** Ask the user to choose a colour, and then apply that color to my route
1587 RouteUI::choose_color ()
1590 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1597 /** Set the route's own color. This may not be used for display if
1598 * the route is in a group which shares its color with its routes.
1601 RouteUI::set_color (const Gdk::Color & c)
1603 /* leave _color alone in the group case so that tracks can retain their
1604 * own pre-group colors.
1609 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1611 /* note: we use the route state ID here so that color is the same for both
1612 the time axis view and the mixer strip
1615 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1616 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1619 /** @return GUI state ID for things that are common to the route in all its representations */
1621 RouteUI::route_state_id () const
1623 return string_compose (X_("route %1"), _route->id().to_s());
1627 RouteUI::set_color_from_route ()
1629 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1637 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1640 _color.set_green (g);
1641 _color.set_blue (b);
1646 /** @return true if this name should be used for the route, otherwise false */
1648 RouteUI::verify_new_route_name (const std::string& name)
1650 if (name.find (':') == string::npos) {
1654 MessageDialog colon_msg (
1655 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1656 false, MESSAGE_QUESTION, BUTTONS_NONE
1659 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1660 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1662 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1666 RouteUI::route_rename ()
1668 ArdourPrompter name_prompter (true);
1673 name_prompter.set_title (_("Rename Track"));
1675 name_prompter.set_title (_("Rename Bus"));
1677 name_prompter.set_prompt (_("New name:"));
1678 name_prompter.set_initial_text (_route->name());
1679 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1680 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1681 name_prompter.show_all ();
1684 switch (name_prompter.run ()) {
1685 case Gtk::RESPONSE_ACCEPT:
1686 name_prompter.get_result (result);
1687 name_prompter.hide ();
1688 if (result.length()) {
1689 if (verify_new_route_name (result)) {
1690 _route->set_name (result);
1693 /* back to name prompter */
1697 /* nothing entered, just get out of here */
1712 RouteUI::property_changed (const PropertyChange& what_changed)
1714 if (what_changed.contains (ARDOUR::Properties::name)) {
1715 name_label.set_text (_route->name());
1720 RouteUI::toggle_comment_editor ()
1722 // if (ignore_toggle) {
1726 if (comment_window && comment_window->is_visible ()) {
1727 comment_window->hide ();
1729 open_comment_editor ();
1735 RouteUI::open_comment_editor ()
1737 if (comment_window == 0) {
1738 setup_comment_editor ();
1742 title = _route->name();
1743 title += _(": comment editor");
1745 comment_window->set_title (title);
1746 comment_window->present();
1750 RouteUI::setup_comment_editor ()
1752 comment_window = new ArdourWindow (""); // title will be reset to show route
1753 comment_window->set_skip_taskbar_hint (true);
1754 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1755 comment_window->set_default_size (400, 200);
1757 comment_area = manage (new TextView());
1758 comment_area->set_name ("MixerTrackCommentArea");
1759 comment_area->set_wrap_mode (WRAP_WORD);
1760 comment_area->set_editable (true);
1761 comment_area->get_buffer()->set_text (_route->comment());
1762 comment_area->show ();
1764 comment_window->add (*comment_area);
1768 RouteUI::comment_changed ()
1770 ignore_comment_edit = true;
1772 comment_area->get_buffer()->set_text (_route->comment());
1774 ignore_comment_edit = false;
1778 RouteUI::comment_editor_done_editing ()
1780 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1782 string const str = comment_area->get_buffer()->get_text();
1783 if (str == _route->comment ()) {
1787 _route->set_comment (str, this);
1791 RouteUI::set_route_active (bool a, bool apply_to_selection)
1793 if (apply_to_selection) {
1794 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1796 _route->set_active (a, this);
1801 RouteUI::duplicate_selected_routes ()
1803 ARDOUR_UI::instance()->start_duplicate_routes();
1807 RouteUI::toggle_denormal_protection ()
1809 if (denormal_menu_item) {
1813 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1815 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1816 _route->set_denormal_protection (x);
1822 RouteUI::denormal_protection_changed ()
1824 if (denormal_menu_item) {
1825 denormal_menu_item->set_active (_route->denormal_protection());
1830 RouteUI::disconnect_input ()
1832 _route->input()->disconnect (this);
1836 RouteUI::disconnect_output ()
1838 _route->output()->disconnect (this);
1842 RouteUI::is_track () const
1844 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1847 boost::shared_ptr<Track>
1848 RouteUI::track() const
1850 return boost::dynamic_pointer_cast<Track>(_route);
1854 RouteUI::is_audio_track () const
1856 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1859 boost::shared_ptr<AudioTrack>
1860 RouteUI::audio_track() const
1862 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1866 RouteUI::is_midi_track () const
1868 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1871 boost::shared_ptr<MidiTrack>
1872 RouteUI::midi_track() const
1874 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1878 RouteUI::has_audio_outputs () const
1880 return (_route->n_outputs().n_audio() > 0);
1884 RouteUI::name() const
1886 return _route->name();
1890 RouteUI::map_frozen ()
1892 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1894 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1897 check_rec_enable_sensitivity ();
1902 RouteUI::adjust_latency ()
1904 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1908 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1911 std::string safe_name;
1914 prompter.get_result (name, true);
1916 safe_name = legalize_for_path (name);
1917 safe_name += template_suffix;
1919 path = Glib::build_filename (dir, safe_name);
1921 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1922 bool overwrite = overwrite_file_dialog (prompter,
1923 _("Confirm Template Overwrite"),
1924 _("A template already exists with that name. Do you want to overwrite it?"));
1931 _route->save_as_template (path, name);
1937 RouteUI::save_as_template ()
1941 dir = ARDOUR::user_route_template_directory ();
1943 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1944 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1948 ArdourPrompter prompter (true); // modal
1950 prompter.set_title (_("Save As Template"));
1951 prompter.set_prompt (_("Template name:"));
1952 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1954 bool finished = false;
1956 switch (prompter.run()) {
1957 case RESPONSE_ACCEPT:
1958 finished = process_save_template_prompter (prompter, dir);
1968 RouteUI::check_rec_enable_sensitivity ()
1970 if (!rec_enable_button) {
1971 assert (0); // This should not happen
1974 if (!_session->writable()) {
1975 rec_enable_button->set_sensitive (false);
1979 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1980 rec_enable_button->set_sensitive (false);
1981 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1982 rec_enable_button->set_sensitive (false);
1984 rec_enable_button->set_sensitive (true);
1986 if (_route && _route->record_safe ()) {
1987 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1989 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1991 update_monitoring_display ();
1995 RouteUI::parameter_changed (string const & p)
1997 /* this handles RC and per-session parameter changes */
1999 if (p == "disable-disarm-during-roll") {
2000 check_rec_enable_sensitivity ();
2001 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2002 set_button_names ();
2003 } else if (p == "auto-input") {
2004 update_monitoring_display ();
2005 } else if (p == "blink-rec-arm") {
2006 if (UIConfiguration::instance().get_blink_rec_arm()) {
2007 rec_blink_connection.disconnect ();
2008 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2010 rec_blink_connection.disconnect ();
2011 RouteUI::blink_rec_display(false);
2017 RouteUI::step_gain_up ()
2019 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2023 RouteUI::page_gain_up ()
2025 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2029 RouteUI::step_gain_down ()
2031 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2035 RouteUI::page_gain_down ()
2037 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2041 RouteUI::open_remote_control_id_dialog ()
2043 ArdourDialog dialog (_("Remote Control ID"));
2044 SpinButton* spin = 0;
2046 dialog.get_vbox()->set_border_width (18);
2048 if (Config->get_remote_model() == UserOrdered) {
2049 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2051 HBox* hbox = manage (new HBox);
2052 hbox->set_spacing (6);
2053 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2054 spin = manage (new SpinButton);
2055 spin->set_digits (0);
2056 spin->set_increments (1, 10);
2057 spin->set_range (0, limit);
2058 spin->set_value (_route->remote_control_id());
2059 hbox->pack_start (*spin);
2060 dialog.get_vbox()->pack_start (*hbox);
2062 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2063 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2065 Label* l = manage (new Label());
2066 if (_route->is_master() || _route->is_monitor()) {
2067 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2068 "The remote control ID of %3 cannot be changed."),
2069 Gtkmm2ext::markup_escape_text (_route->name()),
2070 _route->remote_control_id(),
2071 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2073 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2074 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2075 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2076 (is_track() ? _("track") : _("bus")),
2077 _route->remote_control_id(),
2078 "<span size=\"small\" style=\"italic\">",
2080 Gtkmm2ext::markup_escape_text (_route->name()),
2083 dialog.get_vbox()->pack_start (*l);
2084 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2088 int const r = dialog.run ();
2090 if (r == RESPONSE_ACCEPT && spin) {
2091 _route->set_remote_control_id (spin->get_value_as_int ());
2096 RouteUI::setup_invert_buttons ()
2098 /* remove old invert buttons */
2099 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2100 _invert_button_box.remove (**i);
2103 _invert_buttons.clear ();
2105 if (!_route || !_route->input()) {
2109 uint32_t const N = _route->input()->n_ports().n_audio ();
2111 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2113 for (uint32_t i = 0; i < to_add; ++i) {
2114 ArdourButton* b = manage (new ArdourButton);
2115 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2116 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2118 b->set_name (X_("invert button"));
2121 b->set_text (string_compose (X_("Ø (%1)"), N));
2123 b->set_text (X_("Ø"));
2126 b->set_text (string_compose (X_("Ø%1"), i + 1));
2129 if (N <= _max_invert_buttons) {
2130 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));
2132 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2135 _invert_buttons.push_back (b);
2136 _invert_button_box.pack_start (*b);
2139 _invert_button_box.set_spacing (1);
2140 _invert_button_box.show_all ();
2144 RouteUI::set_invert_button_state ()
2146 uint32_t const N = _route->input()->n_ports().n_audio();
2147 if (N > _max_invert_buttons) {
2149 /* One button for many channels; explicit active if all channels are inverted,
2150 implicit active if some are, off if none are.
2153 ArdourButton* b = _invert_buttons.front ();
2155 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2156 b->set_active_state (Gtkmm2ext::ExplicitActive);
2157 } else if (_route->phase_invert().any()) {
2158 b->set_active_state (Gtkmm2ext::ImplicitActive);
2160 b->set_active_state (Gtkmm2ext::Off);
2165 /* One button per channel; just set active */
2168 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2169 (*i)->set_active (_route->phase_invert (j));
2176 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2178 if (ev->button == 1 && i < _invert_buttons.size()) {
2179 uint32_t const N = _route->input()->n_ports().n_audio ();
2180 if (N <= _max_invert_buttons) {
2181 /* left-click inverts phase so long as we have a button per channel */
2182 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2191 RouteUI::invert_press (GdkEventButton* ev)
2193 using namespace Menu_Helpers;
2195 uint32_t const N = _route->input()->n_ports().n_audio();
2196 if (N <= _max_invert_buttons && ev->button != 3) {
2197 /* If we have an invert button per channel, we only pop
2198 up a menu on right-click; left click is handled
2204 delete _invert_menu;
2205 _invert_menu = new Menu;
2206 _invert_menu->set_name ("ArdourContextMenu");
2207 MenuList& items = _invert_menu->items ();
2209 for (uint32_t i = 0; i < N; ++i) {
2210 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2211 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2212 ++_i_am_the_modifier;
2213 e->set_active (_route->phase_invert (i));
2214 --_i_am_the_modifier;
2217 _invert_menu->popup (0, ev->time);
2223 RouteUI::invert_menu_toggled (uint32_t c)
2225 if (_i_am_the_modifier) {
2229 _route->set_phase_invert (c, !_route->phase_invert (c));
2233 RouteUI::set_invert_sensitive (bool yn)
2235 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2236 (*b)->set_sensitive (yn);
2241 RouteUI::request_redraw ()
2244 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2248 /** The Route's gui_changed signal has been emitted */
2250 RouteUI::route_gui_changed (string what_changed)
2252 if (what_changed == "color") {
2253 if (set_color_from_route () == 0) {
2254 route_color_changed ();
2260 RouteUI::track_mode_changed (void)
2263 switch (track()->mode()) {
2264 case ARDOUR::NonLayered:
2265 case ARDOUR::Normal:
2266 rec_enable_button->set_icon (ArdourIcon::RecButton);
2268 case ARDOUR::Destructive:
2269 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2272 rec_enable_button->queue_draw();
2275 /** @return the color that this route should use; it maybe its own,
2276 or it maybe that of its route group.
2279 RouteUI::color () const
2281 RouteGroup* g = _route->route_group ();
2283 if (g && g->is_color()) {
2285 set_color_from_rgba (c, GroupTabs::group_color (g));
2293 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2295 _showing_sends_to = send_to;
2296 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2300 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2302 if (_route == send_to) {
2303 show_sends_button->set_active (true);
2304 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2306 show_sends_button->set_active (false);
2307 send_blink_connection.disconnect ();
2312 RouteUI::route_group() const
2314 return _route->route_group();
2318 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2319 : WM::ProxyBase (name, string())
2320 , _route (boost::weak_ptr<Route> (route))
2322 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2325 RoutePinWindowProxy::~RoutePinWindowProxy()
2330 ARDOUR::SessionHandlePtr*
2331 RoutePinWindowProxy::session_handle ()
2333 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2334 if (aw) { return aw; }
2339 RoutePinWindowProxy::get (bool create)
2341 boost::shared_ptr<Route> r = _route.lock ();
2350 _window = new PluginPinDialog (r);
2351 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2353 aw->set_session (_session);
2355 _window->show_all ();
2361 RoutePinWindowProxy::route_going_away ()
2365 WM::Manager::instance().remove (this);
2366 going_away_connection.disconnect();
2370 RouteUI::maybe_add_route_print_mgr ()
2372 if (_route->pinmgr_proxy ()) {
2375 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2376 string_compose ("RPM-%1", _route->id()), _route);
2377 wp->set_session (_session);
2379 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2381 wp->set_state (*ui_xml, 0);
2385 void* existing_ui = _route->pinmgr_proxy ();
2387 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2390 _route->set_pingmgr_proxy (wp);
2392 WM::Manager::instance().register_window (wp);
2396 RouteUI::manage_pins ()
2398 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();