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/solo_isolate_control.h"
38 #include "ardour/vca.h"
39 #include "ardour/vca_manager.h"
40 #include "ardour/audio_track.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/filename_extensions.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/monitor_control.h"
45 #include "ardour/internal_send.h"
46 #include "ardour/profile.h"
47 #include "ardour/phase_control.h"
48 #include "ardour/send.h"
49 #include "ardour/route.h"
50 #include "ardour/session.h"
51 #include "ardour/template_utils.h"
53 #include "ardour_ui.h"
56 #include "ardour_button.h"
59 #include "plugin_pin_dialog.h"
61 #include "gui_thread.h"
62 #include "ardour_dialog.h"
63 #include "latency_gui.h"
64 #include "mixer_strip.h"
65 #include "automation_time_axis.h"
66 #include "route_time_axis.h"
67 #include "group_tabs.h"
69 #include "ui_config.h"
74 using namespace Gtkmm2ext;
75 using namespace ARDOUR;
76 using namespace ARDOUR_UI_UTILS;
80 uint32_t RouteUI::_max_invert_buttons = 3;
81 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
82 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
83 std::string RouteUI::program_port_prefix;
85 RouteUI::RouteUI (ARDOUR::Session* sess)
97 if (program_port_prefix.empty()) {
98 // compare to gtk2_ardour/port_group.cc
99 string lpn (PROGRAM_NAME);
100 boost::to_lower (lpn);
101 program_port_prefix = lpn + ":"; // e.g. "ardour:"
109 gui_object_state().remove_node (route_state_id());
112 _route.reset (); /* drop reference to route, so that it can be cleaned up */
113 route_connections.drop_connections ();
119 delete comment_window;
120 delete input_selector;
121 delete output_selector;
124 send_blink_connection.disconnect ();
125 rec_blink_connection.disconnect ();
131 self_destruct = true;
137 pre_fader_mute_check = 0;
138 post_fader_mute_check = 0;
139 listen_mute_check = 0;
142 solo_isolated_check = 0;
143 solo_isolated_led = 0;
147 denormal_menu_item = 0;
150 multiple_mute_change = false;
151 multiple_solo_change = false;
152 _i_am_the_modifier = 0;
158 setup_invert_buttons ();
160 mute_button = manage (new ArdourButton);
161 mute_button->set_name ("mute button");
162 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
164 solo_button = manage (new ArdourButton);
165 solo_button->set_name ("solo button");
166 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
167 solo_button->set_no_show_all (true);
169 rec_enable_button = manage (new ArdourButton);
170 rec_enable_button->set_name ("record enable button");
171 rec_enable_button->set_icon (ArdourIcon::RecButton);
172 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
174 if (UIConfiguration::instance().get_blink_rec_arm()) {
175 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
178 show_sends_button = manage (new ArdourButton);
179 show_sends_button->set_name ("send alert button");
180 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
182 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
183 monitor_input_button->set_name ("monitor button");
184 monitor_input_button->set_text (_("In"));
185 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
186 monitor_input_button->set_no_show_all (true);
188 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
189 monitor_disk_button->set_name ("monitor button");
190 monitor_disk_button->set_text (_("Disk"));
191 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
192 monitor_disk_button->set_no_show_all (true);
194 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
195 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
196 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
198 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
199 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
201 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
202 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
204 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
205 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
207 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
208 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
209 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
210 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
212 monitor_input_button->set_distinct_led_click (false);
213 monitor_disk_button->set_distinct_led_click (false);
215 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
216 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
218 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
219 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
221 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
227 route_connections.drop_connections ();
235 denormal_menu_item = 0;
239 RouteUI::self_delete ()
245 RouteUI::set_route (boost::shared_ptr<Route> rp)
251 if (set_color_from_route()) {
252 set_color (unique_random_color());
256 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
259 delete input_selector;
262 delete output_selector;
265 mute_button->set_controllable (_route->mute_control());
266 solo_button->set_controllable (_route->solo_control());
268 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
270 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
272 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
273 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
274 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
275 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
276 _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->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
294 t->rec_safe_control()->Changed.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->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this, _1, _2), 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->mute_control()->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_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
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_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted() ? 0.0 : 1.0, 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_control (_route->mute_control(), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
471 RouteUI::mute_release (GdkEventButton* /*ev*/)
475 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Route::mute_control), _mute_release->active, 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 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
577 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
579 // Primary-Secondary-click: exclusively solo this track
582 _solo_release->exclusive = true;
584 boost::shared_ptr<RouteList> routes = _session->get_routes();
586 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
587 if ((*i)->soloed ()) {
588 _solo_release->routes_on->push_back (*i);
590 _solo_release->routes_off->push_back (*i);
595 if (Config->get_solo_control_is_listen_control()) {
596 /* ??? we need a just_one_listen() method */
599 boost::shared_ptr<ControlList> cl (new ControlList);
600 cl->push_back (_route->solo_control());
601 _session->set_controls (cl, 1.0, Controllable::NoGroup);
604 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
606 // shift-click: toggle solo isolated status
608 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
609 delete _solo_release;
612 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
614 /* Primary-button1: solo mix group.
615 NOTE: Primary-button2 is MIDI learn.
618 /* Primary-button1 applies change to the mix group even if it is not active
619 NOTE: Primary-button2 is MIDI learn.
622 boost::shared_ptr<RouteList> rl;
624 if (ev->button == 1) {
626 /* Primary-button1 inverts the implication of
627 the group being active. If the group is
628 active (for solo), then this modifier means
629 "do not apply to solo". If the group is
630 inactive (for mute), then this modifier
631 means "apply to route". This is all
632 accomplished by passing just the actual
633 route, along with the InverseGroup group
636 NOTE: Primary-button2 is MIDI learn.
639 rl.reset (new RouteList);
640 rl->push_back (_route);
643 _solo_release->routes = rl;
648 _session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
651 delete _solo_release;
656 /* click: solo this route */
658 boost::shared_ptr<RouteList> rl (new RouteList);
659 rl->push_back (route());
662 _solo_release->routes = rl;
666 _session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::UseGroup);
675 RouteUI::solo_release (GdkEventButton* /*ev*/)
679 if (_solo_release->exclusive) {
683 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Route::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
686 delete _solo_release;
694 RouteUI::rec_enable_press(GdkEventButton* ev)
696 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
700 //if this is a binding action, let the ArdourButton handle it
701 if ( BindingProxy::is_bind_action(ev) )
704 if (!_session->engine().connected()) {
705 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
710 if (is_midi_track()) {
712 /* rec-enable button exits from step editing */
714 if (midi_track()->step_editing()) {
715 midi_track()->set_step_editing (false);
720 if (is_track() && rec_enable_button) {
722 if (Keyboard::is_button2_event (ev)) {
724 //rec arm does not have a momentary mode
727 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
730 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Track::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
732 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
734 /* Primary-button1 applies change to the route group (even if it is not active)
735 NOTE: Primary-button2 is MIDI learn.
738 if (ev->button == 1) {
740 boost::shared_ptr<RouteList> rl;
742 rl.reset (new RouteList);
743 rl->push_back (_route);
746 _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
749 } else if (Keyboard::is_context_menu_event (ev)) {
751 /* do this on release */
755 boost::shared_ptr<Track> trk = track();
756 _session->set_control (trk->rec_enable_control(), !trk->rec_enable_control()->get_value(), Controllable::UseGroup);
764 RouteUI::monitoring_changed (bool, Controllable::GroupControlDisposition)
766 update_monitoring_display ();
770 RouteUI::update_monitoring_display ()
776 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
782 MonitorState ms = t->monitoring_state();
784 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
785 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
787 if (ms & MonitoringInput) {
788 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
790 monitor_input_button->unset_active_state ();
794 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
795 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
797 if (ms & MonitoringDisk) {
798 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
800 monitor_disk_button->unset_active_state ();
806 RouteUI::monitor_input_press(GdkEventButton*)
812 RouteUI::monitor_input_release(GdkEventButton* ev)
814 return monitor_release (ev, MonitorInput);
818 RouteUI::monitor_disk_press (GdkEventButton*)
824 RouteUI::monitor_disk_release (GdkEventButton* ev)
826 return monitor_release (ev, MonitorDisk);
830 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
832 if (ev->button != 1) {
836 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
843 boost::shared_ptr<RouteList> rl;
845 /* XXX for now, monitoring choices are orthogonal. cue monitoring
846 will follow in 3.X but requires mixing the input and playback (disk)
847 signal together, which requires yet more buffers.
850 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
851 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
853 /* this line will change when the options are non-orthogonal */
854 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
858 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
859 rl = _session->get_routes ();
861 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
862 if (_route->route_group() && _route->route_group()->is_monitoring()) {
863 rl = _route->route_group()->route_list();
865 rl.reset (new RouteList);
866 rl->push_back (route());
869 rl.reset (new RouteList);
870 rl->push_back (route());
874 _session->set_controls (route_list_to_control_list (rl, &Route::monitoring_control), (double) mc, Controllable::UseGroup);
880 RouteUI::build_record_menu ()
883 record_menu = new Menu;
884 record_menu->set_name ("ArdourContextMenu");
885 using namespace Menu_Helpers;
886 MenuList& items = record_menu->items();
888 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
889 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
891 if (is_midi_track()) {
892 items.push_back (SeparatorElem());
893 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
894 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
898 if (step_edit_item) {
899 if (track()->rec_enable_control()->get_value()) {
900 step_edit_item->set_sensitive (false);
902 step_edit_item->set_active (midi_track()->step_editing());
905 rec_safe_item->set_sensitive (!_route->record_enabled());
906 rec_safe_item->set_active (_route->record_safe());
911 RouteUI::toggle_step_edit ()
913 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
917 midi_track()->set_step_editing (step_edit_item->get_active());
921 RouteUI::toggle_rec_safe ()
923 if (_route->record_enabled()) {
927 boost::shared_ptr<RouteList> rl (new RouteList);
928 rl->push_back (_route);
929 _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
933 RouteUI::step_edit_changed (bool yn)
936 if (rec_enable_button) {
937 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
940 start_step_editing ();
942 if (step_edit_item) {
943 step_edit_item->set_active (true);
948 if (rec_enable_button) {
949 rec_enable_button->unset_active_state ();
952 stop_step_editing ();
954 if (step_edit_item) {
955 step_edit_item->set_active (false);
961 RouteUI::rec_enable_release (GdkEventButton* ev)
963 if (Keyboard::is_context_menu_event (ev)) {
964 build_record_menu ();
966 record_menu->popup (1, ev->time);
975 RouteUI::build_sends_menu ()
977 using namespace Menu_Helpers;
979 sends_menu = new Menu;
980 sends_menu->set_name ("ArdourContextMenu");
981 MenuList& items = sends_menu->items();
984 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
988 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
992 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
996 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1000 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1004 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1007 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1011 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1014 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1015 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1016 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1021 RouteUI::create_sends (Placement p, bool include_buses)
1023 _session->globally_add_internal_sends (_route, p, include_buses);
1027 RouteUI::create_selected_sends (Placement p, bool include_buses)
1029 boost::shared_ptr<RouteList> rlist (new RouteList);
1030 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1032 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1033 RouteTimeAxisView* rtv;
1035 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1036 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1037 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1038 rlist->push_back (rui->route());
1044 _session->add_internal_sends (_route, p, rlist);
1048 RouteUI::set_sends_gain_from_track ()
1050 _session->globally_set_send_gains_from_track (_route);
1054 RouteUI::set_sends_gain_to_zero ()
1056 _session->globally_set_send_gains_to_zero (_route);
1060 RouteUI::set_sends_gain_to_unity ()
1062 _session->globally_set_send_gains_to_unity (_route);
1066 RouteUI::show_sends_press(GdkEventButton* ev)
1068 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1072 if (!is_track() && show_sends_button) {
1074 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1076 // do nothing on midi sigc::bind event
1079 } else if (Keyboard::is_context_menu_event (ev)) {
1081 if (sends_menu == 0) {
1082 build_sends_menu ();
1085 sends_menu->popup (0, ev->time);
1089 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1092 set_showing_sends_to (boost::shared_ptr<Route> ());
1094 set_showing_sends_to (_route);
1103 RouteUI::show_sends_release (GdkEventButton*)
1109 RouteUI::send_blink (bool onoff)
1111 if (!show_sends_button) {
1116 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1118 show_sends_button->unset_active_state ();
1122 Gtkmm2ext::ActiveState
1123 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1125 if (r->is_master() || r->is_monitor()) {
1126 return Gtkmm2ext::Off;
1129 if (Config->get_solo_control_is_listen_control()) {
1131 if (r->listening_via_monitor()) {
1132 return Gtkmm2ext::ExplicitActive;
1134 return Gtkmm2ext::Off;
1140 if (!r->self_soloed()) {
1141 return Gtkmm2ext::ImplicitActive;
1143 return Gtkmm2ext::ExplicitActive;
1146 return Gtkmm2ext::Off;
1150 Gtkmm2ext::ActiveState
1151 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1153 if (r->is_master() || r->is_monitor()) {
1154 return Gtkmm2ext::Off;
1157 if (r->solo_isolate_control()->solo_isolated()) {
1158 return Gtkmm2ext::ExplicitActive;
1160 return Gtkmm2ext::Off;
1164 Gtkmm2ext::ActiveState
1165 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1167 if (r->is_master() || r->is_monitor()) {
1168 return Gtkmm2ext::Off;
1171 if (r->solo_safe_control()->solo_safe()) {
1172 return Gtkmm2ext::ExplicitActive;
1174 return Gtkmm2ext::Off;
1179 RouteUI::update_solo_display ()
1181 bool yn = _route->solo_safe_control()->solo_safe ();
1183 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1184 solo_safe_check->set_active (yn);
1187 yn = _route->solo_isolate_control()->solo_isolated ();
1189 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1190 solo_isolated_check->set_active (yn);
1193 set_button_names ();
1195 if (solo_isolated_led) {
1196 if (_route->solo_isolate_control()->solo_isolated()) {
1197 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1199 solo_isolated_led->unset_active_state ();
1203 if (solo_safe_led) {
1204 if (_route->solo_safe_control()->solo_safe()) {
1205 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1207 solo_safe_led->unset_active_state ();
1211 solo_button->set_active_state (solo_active_state (_route));
1213 /* some changes to solo status can affect mute display, so catch up
1216 update_mute_display ();
1220 RouteUI::solo_changed_so_update_mute ()
1222 update_mute_display ();
1226 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1228 if (r->is_monitor()) {
1229 return ActiveState(0);
1232 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1236 return Gtkmm2ext::ExplicitActive;
1237 } else if (r->muted_by_others_soloing ()) {
1238 /* this will reflect both solo mutes AND master mutes */
1239 return Gtkmm2ext::ImplicitActive;
1241 /* no mute at all */
1242 return Gtkmm2ext::Off;
1249 return Gtkmm2ext::ExplicitActive;
1250 } else if (r->muted_by_others()) {
1251 /* note the direct use of MuteMaster API here. We are
1252 not interested in showing
1253 others-soloed-so-this-muted status in this
1256 return Gtkmm2ext::ImplicitActive;
1258 /* no mute at all */
1259 return Gtkmm2ext::Off;
1263 return ActiveState(0);
1267 RouteUI::update_mute_display ()
1273 mute_button->set_active_state (mute_active_state (_session, _route));
1277 RouteUI::update_vca_display ()
1283 VCAList vcas (_session->vca_manager().vcas());
1286 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1287 if (_route->slaved_to (*v)) {
1288 if (!label.empty()) {
1291 label += PBD::to_string ((*v)->number(), std::dec);
1295 if (label.empty()) {
1297 vca_button->set_active_state (Gtkmm2ext::Off);
1299 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1302 vca_button->set_text (label);
1306 RouteUI::route_rec_enable_changed ()
1308 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1309 update_monitoring_display ();
1313 RouteUI::session_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::blink_rec_display (bool blinkOn)
1322 if (!rec_enable_button || !_route) {
1326 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1334 if (track()->rec_enable_control()->get_value()) {
1335 switch (_session->record_status ()) {
1336 case Session::Recording:
1337 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1340 case Session::Disabled:
1341 case Session::Enabled:
1342 if (UIConfiguration::instance().get_blink_rec_arm()) {
1343 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1345 rec_enable_button->set_active_state ( ImplicitActive );
1350 if (step_edit_item) {
1351 step_edit_item->set_sensitive (false);
1355 rec_enable_button->unset_active_state ();
1357 if (step_edit_item) {
1358 step_edit_item->set_sensitive (true);
1362 check_rec_enable_sensitivity ();
1366 RouteUI::build_solo_menu (void)
1368 using namespace Menu_Helpers;
1370 solo_menu = new Menu;
1371 solo_menu->set_name ("ArdourContextMenu");
1372 MenuList& items = solo_menu->items();
1373 Gtk::CheckMenuItem* check;
1375 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1376 check->set_active (_route->solo_isolate_control()->solo_isolated());
1377 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1378 items.push_back (CheckMenuElem(*check));
1379 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1382 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1383 check->set_active (_route->solo_safe_control()->solo_safe());
1384 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1385 items.push_back (CheckMenuElem(*check));
1386 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1389 //items.push_back (SeparatorElem());
1390 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1395 RouteUI::build_mute_menu(void)
1397 using namespace Menu_Helpers;
1399 mute_menu = new Menu;
1400 mute_menu->set_name ("ArdourContextMenu");
1402 MenuList& items = mute_menu->items();
1404 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1405 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1406 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1407 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1408 pre_fader_mute_check->show_all();
1410 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1411 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1412 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1413 items.push_back (CheckMenuElem(*post_fader_mute_check));
1414 post_fader_mute_check->show_all();
1416 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1417 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1418 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1419 items.push_back (CheckMenuElem(*listen_mute_check));
1420 listen_mute_check->show_all();
1422 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1423 init_mute_menu(MuteMaster::Main, main_mute_check);
1424 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1425 items.push_back (CheckMenuElem(*main_mute_check));
1426 main_mute_check->show_all();
1428 //items.push_back (SeparatorElem());
1429 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1431 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1435 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1437 check->set_active (_route->mute_control()->mute_points() & mp);
1441 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1443 if (check->get_active()) {
1444 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1446 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1451 RouteUI::muting_change ()
1453 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1456 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1458 yn = (current & MuteMaster::PreFader);
1460 if (pre_fader_mute_check->get_active() != yn) {
1461 pre_fader_mute_check->set_active (yn);
1464 yn = (current & MuteMaster::PostFader);
1466 if (post_fader_mute_check->get_active() != yn) {
1467 post_fader_mute_check->set_active (yn);
1470 yn = (current & MuteMaster::Listen);
1472 if (listen_mute_check->get_active() != yn) {
1473 listen_mute_check->set_active (yn);
1476 yn = (current & MuteMaster::Main);
1478 if (main_mute_check->get_active() != yn) {
1479 main_mute_check->set_active (yn);
1484 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1486 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1490 bool view = solo_isolated_led->active_state();
1491 bool model = _route->solo_isolate_control()->solo_isolated();
1493 /* called BEFORE the view has changed */
1495 if (ev->button == 1) {
1496 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1499 /* disable isolate for all routes */
1500 DisplaySuspender ds;
1501 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 0.0, Controllable::NoGroup);
1503 /* enable isolate for all routes */
1504 DisplaySuspender ds;
1505 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 1.0, Controllable::NoGroup);
1510 if (model == view) {
1512 /* flip just this route */
1514 boost::shared_ptr<RouteList> rl (new RouteList);
1515 rl->push_back (_route);
1516 DisplaySuspender ds;
1517 _session->set_controls (route_list_to_control_list (rl, &Route::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1526 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1528 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1532 bool view = solo_safe_led->active_state();
1533 bool model = _route->solo_safe_control()->solo_safe();
1535 if (ev->button == 1) {
1536 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1537 boost::shared_ptr<RouteList> rl (_session->get_routes());
1539 /* disable solo safe for all routes */
1540 DisplaySuspender ds;
1541 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1542 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1545 /* enable solo safe for all routes */
1546 DisplaySuspender ds;
1547 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1548 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1553 if (model == view) {
1554 /* flip just this route */
1555 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1564 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1566 bool view = check->get_active();
1567 bool model = _route->solo_isolate_control()->solo_isolated();
1569 /* called AFTER the view has changed */
1571 if (model != view) {
1572 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1577 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1579 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1582 /** Ask the user to choose a colour, and then apply that color to my route
1585 RouteUI::choose_color ()
1588 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1595 /** Set the route's own color. This may not be used for display if
1596 * the route is in a group which shares its color with its routes.
1599 RouteUI::set_color (const Gdk::Color & c)
1601 /* leave _color alone in the group case so that tracks can retain their
1602 * own pre-group colors.
1607 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1609 /* note: we use the route state ID here so that color is the same for both
1610 the time axis view and the mixer strip
1613 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1614 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1617 /** @return GUI state ID for things that are common to the route in all its representations */
1619 RouteUI::route_state_id () const
1621 return string_compose (X_("route %1"), _route->id().to_s());
1625 RouteUI::set_color_from_route ()
1627 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1635 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1638 _color.set_green (g);
1639 _color.set_blue (b);
1644 /** @return true if this name should be used for the route, otherwise false */
1646 RouteUI::verify_new_route_name (const std::string& name)
1648 if (name.find (':') == string::npos) {
1652 MessageDialog colon_msg (
1653 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1654 false, MESSAGE_QUESTION, BUTTONS_NONE
1657 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1658 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1660 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1664 RouteUI::route_rename ()
1666 ArdourPrompter name_prompter (true);
1671 name_prompter.set_title (_("Rename Track"));
1673 name_prompter.set_title (_("Rename Bus"));
1675 name_prompter.set_prompt (_("New name:"));
1676 name_prompter.set_initial_text (_route->name());
1677 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1678 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1679 name_prompter.show_all ();
1682 switch (name_prompter.run ()) {
1683 case Gtk::RESPONSE_ACCEPT:
1684 name_prompter.get_result (result);
1685 name_prompter.hide ();
1686 if (result.length()) {
1687 if (verify_new_route_name (result)) {
1688 _route->set_name (result);
1691 /* back to name prompter */
1695 /* nothing entered, just get out of here */
1710 RouteUI::property_changed (const PropertyChange& what_changed)
1712 if (what_changed.contains (ARDOUR::Properties::name)) {
1713 name_label.set_text (_route->name());
1718 RouteUI::toggle_comment_editor ()
1720 // if (ignore_toggle) {
1724 if (comment_window && comment_window->is_visible ()) {
1725 comment_window->hide ();
1727 open_comment_editor ();
1733 RouteUI::open_comment_editor ()
1735 if (comment_window == 0) {
1736 setup_comment_editor ();
1740 title = _route->name();
1741 title += _(": comment editor");
1743 comment_window->set_title (title);
1744 comment_window->present();
1748 RouteUI::setup_comment_editor ()
1750 comment_window = new ArdourWindow (""); // title will be reset to show route
1751 comment_window->set_skip_taskbar_hint (true);
1752 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1753 comment_window->set_default_size (400, 200);
1755 comment_area = manage (new TextView());
1756 comment_area->set_name ("MixerTrackCommentArea");
1757 comment_area->set_wrap_mode (WRAP_WORD);
1758 comment_area->set_editable (true);
1759 comment_area->get_buffer()->set_text (_route->comment());
1760 comment_area->show ();
1762 comment_window->add (*comment_area);
1766 RouteUI::comment_changed ()
1768 ignore_comment_edit = true;
1770 comment_area->get_buffer()->set_text (_route->comment());
1772 ignore_comment_edit = false;
1776 RouteUI::comment_editor_done_editing ()
1778 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1780 string const str = comment_area->get_buffer()->get_text();
1781 if (str == _route->comment ()) {
1785 _route->set_comment (str, this);
1789 RouteUI::set_route_active (bool a, bool apply_to_selection)
1791 if (apply_to_selection) {
1792 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1794 _route->set_active (a, this);
1799 RouteUI::duplicate_selected_routes ()
1801 ARDOUR_UI::instance()->start_duplicate_routes();
1805 RouteUI::toggle_denormal_protection ()
1807 if (denormal_menu_item) {
1811 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1813 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1814 _route->set_denormal_protection (x);
1820 RouteUI::denormal_protection_changed ()
1822 if (denormal_menu_item) {
1823 denormal_menu_item->set_active (_route->denormal_protection());
1828 RouteUI::disconnect_input ()
1830 _route->input()->disconnect (this);
1834 RouteUI::disconnect_output ()
1836 _route->output()->disconnect (this);
1840 RouteUI::is_track () const
1842 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1845 boost::shared_ptr<Track>
1846 RouteUI::track() const
1848 return boost::dynamic_pointer_cast<Track>(_route);
1852 RouteUI::is_audio_track () const
1854 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1857 boost::shared_ptr<AudioTrack>
1858 RouteUI::audio_track() const
1860 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1864 RouteUI::is_midi_track () const
1866 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1869 boost::shared_ptr<MidiTrack>
1870 RouteUI::midi_track() const
1872 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1876 RouteUI::has_audio_outputs () const
1878 return (_route->n_outputs().n_audio() > 0);
1882 RouteUI::name() const
1884 return _route->name();
1888 RouteUI::map_frozen ()
1890 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1892 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1895 check_rec_enable_sensitivity ();
1900 RouteUI::adjust_latency ()
1902 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1906 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1909 std::string safe_name;
1912 prompter.get_result (name, true);
1914 safe_name = legalize_for_path (name);
1915 safe_name += template_suffix;
1917 path = Glib::build_filename (dir, safe_name);
1919 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1920 bool overwrite = overwrite_file_dialog (prompter,
1921 _("Confirm Template Overwrite"),
1922 _("A template already exists with that name. Do you want to overwrite it?"));
1929 _route->save_as_template (path, name);
1935 RouteUI::save_as_template ()
1939 dir = ARDOUR::user_route_template_directory ();
1941 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1942 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1946 ArdourPrompter prompter (true); // modal
1948 prompter.set_title (_("Save As Template"));
1949 prompter.set_prompt (_("Template name:"));
1950 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1952 bool finished = false;
1954 switch (prompter.run()) {
1955 case RESPONSE_ACCEPT:
1956 finished = process_save_template_prompter (prompter, dir);
1966 RouteUI::check_rec_enable_sensitivity ()
1968 if (!rec_enable_button) {
1969 assert (0); // This should not happen
1972 if (!_session->writable()) {
1973 rec_enable_button->set_sensitive (false);
1977 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1978 rec_enable_button->set_sensitive (false);
1979 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1980 rec_enable_button->set_sensitive (false);
1982 rec_enable_button->set_sensitive (true);
1984 if (_route && _route->record_safe ()) {
1985 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1987 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1989 update_monitoring_display ();
1993 RouteUI::parameter_changed (string const & p)
1995 /* this handles RC and per-session parameter changes */
1997 if (p == "disable-disarm-during-roll") {
1998 check_rec_enable_sensitivity ();
1999 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2000 set_button_names ();
2001 } else if (p == "auto-input") {
2002 update_monitoring_display ();
2003 } else if (p == "blink-rec-arm") {
2004 if (UIConfiguration::instance().get_blink_rec_arm()) {
2005 rec_blink_connection.disconnect ();
2006 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2008 rec_blink_connection.disconnect ();
2009 RouteUI::blink_rec_display(false);
2015 RouteUI::step_gain_up ()
2017 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2021 RouteUI::page_gain_up ()
2023 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2027 RouteUI::step_gain_down ()
2029 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2033 RouteUI::page_gain_down ()
2035 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2039 RouteUI::open_remote_control_id_dialog ()
2041 ArdourDialog dialog (_("Remote Control ID"));
2042 SpinButton* spin = 0;
2044 dialog.get_vbox()->set_border_width (18);
2046 if (Config->get_remote_model() == UserOrdered) {
2047 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2049 HBox* hbox = manage (new HBox);
2050 hbox->set_spacing (6);
2051 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2052 spin = manage (new SpinButton);
2053 spin->set_digits (0);
2054 spin->set_increments (1, 10);
2055 spin->set_range (0, limit);
2056 spin->set_value (_route->remote_control_id());
2057 hbox->pack_start (*spin);
2058 dialog.get_vbox()->pack_start (*hbox);
2060 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2061 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2063 Label* l = manage (new Label());
2064 if (_route->is_master() || _route->is_monitor()) {
2065 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2066 "The remote control ID of %3 cannot be changed."),
2067 Gtkmm2ext::markup_escape_text (_route->name()),
2068 _route->remote_control_id(),
2069 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2071 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2072 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2073 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2074 (is_track() ? _("track") : _("bus")),
2075 _route->remote_control_id(),
2076 "<span size=\"small\" style=\"italic\">",
2078 Gtkmm2ext::markup_escape_text (_route->name()),
2081 dialog.get_vbox()->pack_start (*l);
2082 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2086 int const r = dialog.run ();
2088 if (r == RESPONSE_ACCEPT && spin) {
2089 _route->set_remote_control_id (spin->get_value_as_int ());
2094 RouteUI::setup_invert_buttons ()
2096 /* remove old invert buttons */
2097 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2098 _invert_button_box.remove (**i);
2101 _invert_buttons.clear ();
2103 if (!_route || !_route->input()) {
2107 uint32_t const N = _route->input()->n_ports().n_audio ();
2109 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2111 for (uint32_t i = 0; i < to_add; ++i) {
2112 ArdourButton* b = manage (new ArdourButton);
2113 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2114 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2116 b->set_name (X_("invert button"));
2119 b->set_text (string_compose (X_("Ø (%1)"), N));
2121 b->set_text (X_("Ø"));
2124 b->set_text (string_compose (X_("Ø%1"), i + 1));
2127 if (N <= _max_invert_buttons) {
2128 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));
2130 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2133 _invert_buttons.push_back (b);
2134 _invert_button_box.pack_start (*b);
2137 _invert_button_box.set_spacing (1);
2138 _invert_button_box.show_all ();
2142 RouteUI::set_invert_button_state ()
2144 uint32_t const N = _route->input()->n_ports().n_audio();
2145 if (N > _max_invert_buttons) {
2147 /* One button for many channels; explicit active if all channels are inverted,
2148 implicit active if some are, off if none are.
2151 ArdourButton* b = _invert_buttons.front ();
2153 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2154 b->set_active_state (Gtkmm2ext::ExplicitActive);
2155 } else if (_route->phase_control()->any()) {
2156 b->set_active_state (Gtkmm2ext::ImplicitActive);
2158 b->set_active_state (Gtkmm2ext::Off);
2163 /* One button per channel; just set active */
2166 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2167 (*i)->set_active (_route->phase_control()->inverted (j));
2174 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2176 if (ev->button == 1 && i < _invert_buttons.size()) {
2177 uint32_t const N = _route->input()->n_ports().n_audio ();
2178 if (N <= _max_invert_buttons) {
2179 /* left-click inverts phase so long as we have a button per channel */
2180 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2189 RouteUI::invert_press (GdkEventButton* ev)
2191 using namespace Menu_Helpers;
2193 uint32_t const N = _route->input()->n_ports().n_audio();
2194 if (N <= _max_invert_buttons && ev->button != 3) {
2195 /* If we have an invert button per channel, we only pop
2196 up a menu on right-click; left click is handled
2202 delete _invert_menu;
2203 _invert_menu = new Menu;
2204 _invert_menu->set_name ("ArdourContextMenu");
2205 MenuList& items = _invert_menu->items ();
2207 for (uint32_t i = 0; i < N; ++i) {
2208 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2209 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2210 ++_i_am_the_modifier;
2211 e->set_active (_route->phase_control()->inverted (i));
2212 --_i_am_the_modifier;
2215 _invert_menu->popup (0, ev->time);
2221 RouteUI::invert_menu_toggled (uint32_t c)
2223 if (_i_am_the_modifier) {
2228 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2232 RouteUI::set_invert_sensitive (bool yn)
2234 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2235 (*b)->set_sensitive (yn);
2240 RouteUI::request_redraw ()
2243 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2247 /** The Route's gui_changed signal has been emitted */
2249 RouteUI::route_gui_changed (string what_changed)
2251 if (what_changed == "color") {
2252 if (set_color_from_route () == 0) {
2253 route_color_changed ();
2259 RouteUI::track_mode_changed (void)
2262 switch (track()->mode()) {
2263 case ARDOUR::NonLayered:
2264 case ARDOUR::Normal:
2265 rec_enable_button->set_icon (ArdourIcon::RecButton);
2267 case ARDOUR::Destructive:
2268 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2271 rec_enable_button->queue_draw();
2274 /** @return the color that this route should use; it maybe its own,
2275 or it maybe that of its route group.
2278 RouteUI::color () const
2280 RouteGroup* g = _route->route_group ();
2282 if (g && g->is_color()) {
2284 set_color_from_rgba (c, GroupTabs::group_color (g));
2292 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2294 _showing_sends_to = send_to;
2295 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2299 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2301 if (_route == send_to) {
2302 show_sends_button->set_active (true);
2303 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2305 show_sends_button->set_active (false);
2306 send_blink_connection.disconnect ();
2311 RouteUI::route_group() const
2313 return _route->route_group();
2317 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2318 : WM::ProxyBase (name, string())
2319 , _route (boost::weak_ptr<Route> (route))
2321 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2324 RoutePinWindowProxy::~RoutePinWindowProxy()
2329 ARDOUR::SessionHandlePtr*
2330 RoutePinWindowProxy::session_handle ()
2332 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2333 if (aw) { return aw; }
2338 RoutePinWindowProxy::get (bool create)
2340 boost::shared_ptr<Route> r = _route.lock ();
2349 _window = new PluginPinDialog (r);
2350 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2352 aw->set_session (_session);
2354 _window->show_all ();
2360 RoutePinWindowProxy::route_going_away ()
2364 WM::Manager::instance().remove (this);
2365 going_away_connection.disconnect();
2369 RouteUI::maybe_add_route_print_mgr ()
2371 if (_route->pinmgr_proxy ()) {
2374 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2375 string_compose ("RPM-%1", _route->id()), _route);
2376 wp->set_session (_session);
2378 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2380 wp->set_state (*ui_xml, 0);
2384 void* existing_ui = _route->pinmgr_proxy ();
2386 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2389 _route->set_pingmgr_proxy (wp);
2391 WM::Manager::instance().register_window (wp);
2395 RouteUI::manage_pins ()
2397 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();