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::update_monitoring_display, 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->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_by_self() ? 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_by_self() ? 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_by_self() ? 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::update_monitoring_display ()
770 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
776 MonitorState ms = t->monitoring_state();
778 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
779 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
781 if (ms & MonitoringInput) {
782 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
784 monitor_input_button->unset_active_state ();
788 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
789 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
791 if (ms & MonitoringDisk) {
792 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
794 monitor_disk_button->unset_active_state ();
800 RouteUI::monitor_input_press(GdkEventButton*)
806 RouteUI::monitor_input_release(GdkEventButton* ev)
808 return monitor_release (ev, MonitorInput);
812 RouteUI::monitor_disk_press (GdkEventButton*)
818 RouteUI::monitor_disk_release (GdkEventButton* ev)
820 return monitor_release (ev, MonitorDisk);
824 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
826 if (ev->button != 1) {
830 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
837 boost::shared_ptr<RouteList> rl;
839 /* XXX for now, monitoring choices are orthogonal. cue monitoring
840 will follow in 3.X but requires mixing the input and playback (disk)
841 signal together, which requires yet more buffers.
844 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
845 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
847 /* this line will change when the options are non-orthogonal */
848 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
852 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
853 rl = _session->get_routes ();
855 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
856 if (_route->route_group() && _route->route_group()->is_monitoring()) {
857 rl = _route->route_group()->route_list();
859 rl.reset (new RouteList);
860 rl->push_back (route());
863 rl.reset (new RouteList);
864 rl->push_back (route());
868 _session->set_controls (route_list_to_control_list (rl, &Route::monitoring_control), (double) mc, Controllable::UseGroup);
874 RouteUI::build_record_menu ()
877 record_menu = new Menu;
878 record_menu->set_name ("ArdourContextMenu");
879 using namespace Menu_Helpers;
880 MenuList& items = record_menu->items();
882 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
883 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
885 if (is_midi_track()) {
886 items.push_back (SeparatorElem());
887 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
888 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
892 if (step_edit_item) {
893 if (track()->rec_enable_control()->get_value()) {
894 step_edit_item->set_sensitive (false);
896 step_edit_item->set_active (midi_track()->step_editing());
899 rec_safe_item->set_sensitive (!_route->record_enabled());
900 rec_safe_item->set_active (_route->record_safe());
905 RouteUI::toggle_step_edit ()
907 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
911 midi_track()->set_step_editing (step_edit_item->get_active());
915 RouteUI::toggle_rec_safe ()
917 if (_route->record_enabled()) {
921 boost::shared_ptr<RouteList> rl (new RouteList);
922 rl->push_back (_route);
923 _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
927 RouteUI::step_edit_changed (bool yn)
930 if (rec_enable_button) {
931 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
934 start_step_editing ();
936 if (step_edit_item) {
937 step_edit_item->set_active (true);
942 if (rec_enable_button) {
943 rec_enable_button->unset_active_state ();
946 stop_step_editing ();
948 if (step_edit_item) {
949 step_edit_item->set_active (false);
955 RouteUI::rec_enable_release (GdkEventButton* ev)
957 if (Keyboard::is_context_menu_event (ev)) {
958 build_record_menu ();
960 record_menu->popup (1, ev->time);
969 RouteUI::build_sends_menu ()
971 using namespace Menu_Helpers;
973 sends_menu = new Menu;
974 sends_menu->set_name ("ArdourContextMenu");
975 MenuList& items = sends_menu->items();
978 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
982 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
986 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
990 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
994 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
998 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1001 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1005 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1008 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1009 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1010 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1015 RouteUI::create_sends (Placement p, bool include_buses)
1017 _session->globally_add_internal_sends (_route, p, include_buses);
1021 RouteUI::create_selected_sends (Placement p, bool include_buses)
1023 boost::shared_ptr<RouteList> rlist (new RouteList);
1024 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1026 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1027 RouteTimeAxisView* rtv;
1029 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1030 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1031 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1032 rlist->push_back (rui->route());
1038 _session->add_internal_sends (_route, p, rlist);
1042 RouteUI::set_sends_gain_from_track ()
1044 _session->globally_set_send_gains_from_track (_route);
1048 RouteUI::set_sends_gain_to_zero ()
1050 _session->globally_set_send_gains_to_zero (_route);
1054 RouteUI::set_sends_gain_to_unity ()
1056 _session->globally_set_send_gains_to_unity (_route);
1060 RouteUI::show_sends_press(GdkEventButton* ev)
1062 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1066 if (!is_track() && show_sends_button) {
1068 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1070 // do nothing on midi sigc::bind event
1073 } else if (Keyboard::is_context_menu_event (ev)) {
1075 if (sends_menu == 0) {
1076 build_sends_menu ();
1079 sends_menu->popup (0, ev->time);
1083 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1086 set_showing_sends_to (boost::shared_ptr<Route> ());
1088 set_showing_sends_to (_route);
1097 RouteUI::show_sends_release (GdkEventButton*)
1103 RouteUI::send_blink (bool onoff)
1105 if (!show_sends_button) {
1110 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1112 show_sends_button->unset_active_state ();
1116 Gtkmm2ext::ActiveState
1117 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1119 boost::shared_ptr<SoloControl> sc = s->solo_control();
1122 return Gtkmm2ext::Off;
1125 if (!sc->can_solo()) {
1126 return Gtkmm2ext::Off;
1130 if (sc->self_soloed()) {
1131 return Gtkmm2ext::ExplicitActive;
1132 } else if (sc->soloed_by_others()) {
1133 return Gtkmm2ext::ImplicitActive;
1135 return Gtkmm2ext::Off;
1139 Gtkmm2ext::ActiveState
1140 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1142 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1145 return Gtkmm2ext::Off;
1148 if (s->is_master() || s->is_monitor()) {
1149 return Gtkmm2ext::Off;
1152 if (sc->solo_isolated()) {
1153 return Gtkmm2ext::ExplicitActive;
1155 return Gtkmm2ext::Off;
1159 Gtkmm2ext::ActiveState
1160 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1162 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1165 return Gtkmm2ext::Off;
1168 if (s->is_master() || s->is_monitor()) {
1169 return Gtkmm2ext::Off;
1172 if (sc->solo_safe()) {
1173 return Gtkmm2ext::ExplicitActive;
1175 return Gtkmm2ext::Off;
1180 RouteUI::update_solo_display ()
1182 bool yn = _route->solo_safe_control()->solo_safe ();
1184 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1185 solo_safe_check->set_active (yn);
1188 yn = _route->solo_isolate_control()->solo_isolated ();
1190 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1191 solo_isolated_check->set_active (yn);
1194 set_button_names ();
1196 if (solo_isolated_led) {
1197 if (_route->solo_isolate_control()->solo_isolated()) {
1198 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1200 solo_isolated_led->unset_active_state ();
1204 if (solo_safe_led) {
1205 if (_route->solo_safe_control()->solo_safe()) {
1206 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1208 solo_safe_led->unset_active_state ();
1212 solo_button->set_active_state (solo_active_state (_route));
1214 /* some changes to solo status can affect mute display, so catch up
1217 update_mute_display ();
1221 RouteUI::solo_changed_so_update_mute ()
1223 update_mute_display ();
1227 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1229 boost::shared_ptr<MuteControl> mc = s->mute_control();
1231 if (s->is_monitor()) {
1232 return Gtkmm2ext::Off;
1236 return Gtkmm2ext::Off;
1239 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1241 if (mc->muted_by_self ()) {
1243 return Gtkmm2ext::ExplicitActive;
1244 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1245 /* this will reflect both solo mutes AND master mutes */
1246 return Gtkmm2ext::ImplicitActive;
1248 /* no mute at all */
1249 return Gtkmm2ext::Off;
1254 if (mc->muted_by_self()) {
1256 return Gtkmm2ext::ExplicitActive;
1257 } else if (mc->muted_by_masters ()) {
1258 /* this shows only master mutes, not mute-by-others-soloing */
1259 return Gtkmm2ext::ImplicitActive;
1261 /* no mute at all */
1262 return Gtkmm2ext::Off;
1266 return ActiveState(0);
1270 RouteUI::update_mute_display ()
1276 mute_button->set_active_state (mute_active_state (_session, _route));
1280 RouteUI::update_vca_display ()
1286 VCAList vcas (_session->vca_manager().vcas());
1289 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1290 if (_route->slaved_to (*v)) {
1291 if (!label.empty()) {
1294 label += PBD::to_string ((*v)->number(), std::dec);
1298 if (label.empty()) {
1300 vca_button->set_active_state (Gtkmm2ext::Off);
1302 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1305 vca_button->set_text (label);
1309 RouteUI::route_rec_enable_changed ()
1311 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1312 update_monitoring_display ();
1316 RouteUI::session_rec_enable_changed ()
1318 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1319 update_monitoring_display ();
1323 RouteUI::blink_rec_display (bool blinkOn)
1325 if (!rec_enable_button || !_route) {
1329 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1337 if (track()->rec_enable_control()->get_value()) {
1338 switch (_session->record_status ()) {
1339 case Session::Recording:
1340 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1343 case Session::Disabled:
1344 case Session::Enabled:
1345 if (UIConfiguration::instance().get_blink_rec_arm()) {
1346 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1348 rec_enable_button->set_active_state ( ImplicitActive );
1353 if (step_edit_item) {
1354 step_edit_item->set_sensitive (false);
1358 rec_enable_button->unset_active_state ();
1360 if (step_edit_item) {
1361 step_edit_item->set_sensitive (true);
1365 check_rec_enable_sensitivity ();
1369 RouteUI::build_solo_menu (void)
1371 using namespace Menu_Helpers;
1373 solo_menu = new Menu;
1374 solo_menu->set_name ("ArdourContextMenu");
1375 MenuList& items = solo_menu->items();
1376 Gtk::CheckMenuItem* check;
1378 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1379 check->set_active (_route->solo_isolate_control()->solo_isolated());
1380 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1381 items.push_back (CheckMenuElem(*check));
1382 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1385 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1386 check->set_active (_route->solo_safe_control()->solo_safe());
1387 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1388 items.push_back (CheckMenuElem(*check));
1389 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1392 //items.push_back (SeparatorElem());
1393 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1398 RouteUI::build_mute_menu(void)
1400 using namespace Menu_Helpers;
1402 mute_menu = new Menu;
1403 mute_menu->set_name ("ArdourContextMenu");
1405 MenuList& items = mute_menu->items();
1407 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1408 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1409 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1410 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1411 pre_fader_mute_check->show_all();
1413 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1414 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1415 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1416 items.push_back (CheckMenuElem(*post_fader_mute_check));
1417 post_fader_mute_check->show_all();
1419 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1420 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1421 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1422 items.push_back (CheckMenuElem(*listen_mute_check));
1423 listen_mute_check->show_all();
1425 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1426 init_mute_menu(MuteMaster::Main, main_mute_check);
1427 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1428 items.push_back (CheckMenuElem(*main_mute_check));
1429 main_mute_check->show_all();
1431 //items.push_back (SeparatorElem());
1432 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1434 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1438 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1440 check->set_active (_route->mute_control()->mute_points() & mp);
1444 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1446 if (check->get_active()) {
1447 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1449 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1454 RouteUI::muting_change ()
1456 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1459 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1461 yn = (current & MuteMaster::PreFader);
1463 if (pre_fader_mute_check->get_active() != yn) {
1464 pre_fader_mute_check->set_active (yn);
1467 yn = (current & MuteMaster::PostFader);
1469 if (post_fader_mute_check->get_active() != yn) {
1470 post_fader_mute_check->set_active (yn);
1473 yn = (current & MuteMaster::Listen);
1475 if (listen_mute_check->get_active() != yn) {
1476 listen_mute_check->set_active (yn);
1479 yn = (current & MuteMaster::Main);
1481 if (main_mute_check->get_active() != yn) {
1482 main_mute_check->set_active (yn);
1487 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1489 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1493 bool view = solo_isolated_led->active_state();
1494 bool model = _route->solo_isolate_control()->solo_isolated();
1496 /* called BEFORE the view has changed */
1498 if (ev->button == 1) {
1499 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1502 /* disable isolate for all routes */
1503 DisplaySuspender ds;
1504 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 0.0, Controllable::NoGroup);
1506 /* enable isolate for all routes */
1507 DisplaySuspender ds;
1508 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 1.0, Controllable::NoGroup);
1513 if (model == view) {
1515 /* flip just this route */
1517 boost::shared_ptr<RouteList> rl (new RouteList);
1518 rl->push_back (_route);
1519 DisplaySuspender ds;
1520 _session->set_controls (route_list_to_control_list (rl, &Route::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1529 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1531 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1535 bool view = solo_safe_led->active_state();
1536 bool model = _route->solo_safe_control()->solo_safe();
1538 if (ev->button == 1) {
1539 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1540 boost::shared_ptr<RouteList> rl (_session->get_routes());
1542 /* disable solo safe for all routes */
1543 DisplaySuspender ds;
1544 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1545 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1548 /* enable solo safe for all routes */
1549 DisplaySuspender ds;
1550 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1551 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1556 if (model == view) {
1557 /* flip just this route */
1558 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1567 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1569 bool view = check->get_active();
1570 bool model = _route->solo_isolate_control()->solo_isolated();
1572 /* called AFTER the view has changed */
1574 if (model != view) {
1575 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1580 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1582 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1585 /** Ask the user to choose a colour, and then apply that color to my route
1588 RouteUI::choose_color ()
1591 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1598 /** Set the route's own color. This may not be used for display if
1599 * the route is in a group which shares its color with its routes.
1602 RouteUI::set_color (const Gdk::Color & c)
1604 /* leave _color alone in the group case so that tracks can retain their
1605 * own pre-group colors.
1610 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1612 /* note: we use the route state ID here so that color is the same for both
1613 the time axis view and the mixer strip
1616 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1617 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1620 /** @return GUI state ID for things that are common to the route in all its representations */
1622 RouteUI::route_state_id () const
1624 return string_compose (X_("route %1"), _route->id().to_s());
1628 RouteUI::set_color_from_route ()
1630 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1638 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1641 _color.set_green (g);
1642 _color.set_blue (b);
1647 /** @return true if this name should be used for the route, otherwise false */
1649 RouteUI::verify_new_route_name (const std::string& name)
1651 if (name.find (':') == string::npos) {
1655 MessageDialog colon_msg (
1656 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1657 false, MESSAGE_QUESTION, BUTTONS_NONE
1660 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1661 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1663 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1667 RouteUI::route_rename ()
1669 ArdourPrompter name_prompter (true);
1674 name_prompter.set_title (_("Rename Track"));
1676 name_prompter.set_title (_("Rename Bus"));
1678 name_prompter.set_prompt (_("New name:"));
1679 name_prompter.set_initial_text (_route->name());
1680 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1681 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1682 name_prompter.show_all ();
1685 switch (name_prompter.run ()) {
1686 case Gtk::RESPONSE_ACCEPT:
1687 name_prompter.get_result (result);
1688 name_prompter.hide ();
1689 if (result.length()) {
1690 if (verify_new_route_name (result)) {
1691 _route->set_name (result);
1694 /* back to name prompter */
1698 /* nothing entered, just get out of here */
1713 RouteUI::property_changed (const PropertyChange& what_changed)
1715 if (what_changed.contains (ARDOUR::Properties::name)) {
1716 name_label.set_text (_route->name());
1721 RouteUI::toggle_comment_editor ()
1723 // if (ignore_toggle) {
1727 if (comment_window && comment_window->is_visible ()) {
1728 comment_window->hide ();
1730 open_comment_editor ();
1736 RouteUI::open_comment_editor ()
1738 if (comment_window == 0) {
1739 setup_comment_editor ();
1743 title = _route->name();
1744 title += _(": comment editor");
1746 comment_window->set_title (title);
1747 comment_window->present();
1751 RouteUI::setup_comment_editor ()
1753 comment_window = new ArdourWindow (""); // title will be reset to show route
1754 comment_window->set_skip_taskbar_hint (true);
1755 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1756 comment_window->set_default_size (400, 200);
1758 comment_area = manage (new TextView());
1759 comment_area->set_name ("MixerTrackCommentArea");
1760 comment_area->set_wrap_mode (WRAP_WORD);
1761 comment_area->set_editable (true);
1762 comment_area->get_buffer()->set_text (_route->comment());
1763 comment_area->show ();
1765 comment_window->add (*comment_area);
1769 RouteUI::comment_changed ()
1771 ignore_comment_edit = true;
1773 comment_area->get_buffer()->set_text (_route->comment());
1775 ignore_comment_edit = false;
1779 RouteUI::comment_editor_done_editing ()
1781 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1783 string const str = comment_area->get_buffer()->get_text();
1784 if (str == _route->comment ()) {
1788 _route->set_comment (str, this);
1792 RouteUI::set_route_active (bool a, bool apply_to_selection)
1794 if (apply_to_selection) {
1795 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1797 _route->set_active (a, this);
1802 RouteUI::duplicate_selected_routes ()
1804 ARDOUR_UI::instance()->start_duplicate_routes();
1808 RouteUI::toggle_denormal_protection ()
1810 if (denormal_menu_item) {
1814 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1816 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1817 _route->set_denormal_protection (x);
1823 RouteUI::denormal_protection_changed ()
1825 if (denormal_menu_item) {
1826 denormal_menu_item->set_active (_route->denormal_protection());
1831 RouteUI::disconnect_input ()
1833 _route->input()->disconnect (this);
1837 RouteUI::disconnect_output ()
1839 _route->output()->disconnect (this);
1843 RouteUI::is_track () const
1845 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1848 boost::shared_ptr<Track>
1849 RouteUI::track() const
1851 return boost::dynamic_pointer_cast<Track>(_route);
1855 RouteUI::is_audio_track () const
1857 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1860 boost::shared_ptr<AudioTrack>
1861 RouteUI::audio_track() const
1863 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1867 RouteUI::is_midi_track () const
1869 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1872 boost::shared_ptr<MidiTrack>
1873 RouteUI::midi_track() const
1875 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1879 RouteUI::has_audio_outputs () const
1881 return (_route->n_outputs().n_audio() > 0);
1885 RouteUI::name() const
1887 return _route->name();
1891 RouteUI::map_frozen ()
1893 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1895 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1898 check_rec_enable_sensitivity ();
1903 RouteUI::adjust_latency ()
1905 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1909 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1912 std::string safe_name;
1915 prompter.get_result (name, true);
1917 safe_name = legalize_for_path (name);
1918 safe_name += template_suffix;
1920 path = Glib::build_filename (dir, safe_name);
1922 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1923 bool overwrite = overwrite_file_dialog (prompter,
1924 _("Confirm Template Overwrite"),
1925 _("A template already exists with that name. Do you want to overwrite it?"));
1932 _route->save_as_template (path, name);
1938 RouteUI::save_as_template ()
1942 dir = ARDOUR::user_route_template_directory ();
1944 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1945 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1949 ArdourPrompter prompter (true); // modal
1951 prompter.set_title (_("Save As Template"));
1952 prompter.set_prompt (_("Template name:"));
1953 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1955 bool finished = false;
1957 switch (prompter.run()) {
1958 case RESPONSE_ACCEPT:
1959 finished = process_save_template_prompter (prompter, dir);
1969 RouteUI::check_rec_enable_sensitivity ()
1971 if (!rec_enable_button) {
1972 assert (0); // This should not happen
1975 if (!_session->writable()) {
1976 rec_enable_button->set_sensitive (false);
1980 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1981 rec_enable_button->set_sensitive (false);
1982 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1983 rec_enable_button->set_sensitive (false);
1985 rec_enable_button->set_sensitive (true);
1987 if (_route && _route->record_safe ()) {
1988 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1990 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1992 update_monitoring_display ();
1996 RouteUI::parameter_changed (string const & p)
1998 /* this handles RC and per-session parameter changes */
2000 if (p == "disable-disarm-during-roll") {
2001 check_rec_enable_sensitivity ();
2002 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2003 set_button_names ();
2004 } else if (p == "auto-input") {
2005 update_monitoring_display ();
2006 } else if (p == "blink-rec-arm") {
2007 if (UIConfiguration::instance().get_blink_rec_arm()) {
2008 rec_blink_connection.disconnect ();
2009 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2011 rec_blink_connection.disconnect ();
2012 RouteUI::blink_rec_display(false);
2018 RouteUI::step_gain_up ()
2020 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2024 RouteUI::page_gain_up ()
2026 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2030 RouteUI::step_gain_down ()
2032 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2036 RouteUI::page_gain_down ()
2038 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2042 RouteUI::open_remote_control_id_dialog ()
2044 ArdourDialog dialog (_("Remote Control ID"));
2045 SpinButton* spin = 0;
2047 dialog.get_vbox()->set_border_width (18);
2049 if (Config->get_remote_model() == UserOrdered) {
2050 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2052 HBox* hbox = manage (new HBox);
2053 hbox->set_spacing (6);
2054 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2055 spin = manage (new SpinButton);
2056 spin->set_digits (0);
2057 spin->set_increments (1, 10);
2058 spin->set_range (0, limit);
2059 spin->set_value (_route->presentation_info().group_order());
2060 hbox->pack_start (*spin);
2061 dialog.get_vbox()->pack_start (*hbox);
2063 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2064 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2066 Label* l = manage (new Label());
2067 if (_route->is_master() || _route->is_monitor()) {
2068 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2069 "The remote control ID of %3 cannot be changed."),
2070 Gtkmm2ext::markup_escape_text (_route->name()),
2071 _route->presentation_info().group_order(),
2072 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2074 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2075 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2076 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2077 (is_track() ? _("track") : _("bus")),
2078 _route->presentation_info().group_order(),
2079 "<span size=\"small\" style=\"italic\">",
2081 Gtkmm2ext::markup_escape_text (_route->name()),
2084 dialog.get_vbox()->pack_start (*l);
2085 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2089 int const r = dialog.run ();
2091 if (r == RESPONSE_ACCEPT && spin) {
2092 _route->set_presentation_group_order_explicit (spin->get_value_as_int ());
2097 RouteUI::setup_invert_buttons ()
2099 /* remove old invert buttons */
2100 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2101 _invert_button_box.remove (**i);
2104 _invert_buttons.clear ();
2106 if (!_route || !_route->input()) {
2110 uint32_t const N = _route->input()->n_ports().n_audio ();
2112 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2114 for (uint32_t i = 0; i < to_add; ++i) {
2115 ArdourButton* b = manage (new ArdourButton);
2116 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2117 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2119 b->set_name (X_("invert button"));
2122 b->set_text (string_compose (X_("Ø (%1)"), N));
2124 b->set_text (X_("Ø"));
2127 b->set_text (string_compose (X_("Ø%1"), i + 1));
2130 if (N <= _max_invert_buttons) {
2131 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));
2133 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2136 _invert_buttons.push_back (b);
2137 _invert_button_box.pack_start (*b);
2140 _invert_button_box.set_spacing (1);
2141 _invert_button_box.show_all ();
2145 RouteUI::set_invert_button_state ()
2147 uint32_t const N = _route->input()->n_ports().n_audio();
2148 if (N > _max_invert_buttons) {
2150 /* One button for many channels; explicit active if all channels are inverted,
2151 implicit active if some are, off if none are.
2154 ArdourButton* b = _invert_buttons.front ();
2156 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2157 b->set_active_state (Gtkmm2ext::ExplicitActive);
2158 } else if (_route->phase_control()->any()) {
2159 b->set_active_state (Gtkmm2ext::ImplicitActive);
2161 b->set_active_state (Gtkmm2ext::Off);
2166 /* One button per channel; just set active */
2169 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2170 (*i)->set_active (_route->phase_control()->inverted (j));
2177 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2179 if (ev->button == 1 && i < _invert_buttons.size()) {
2180 uint32_t const N = _route->input()->n_ports().n_audio ();
2181 if (N <= _max_invert_buttons) {
2182 /* left-click inverts phase so long as we have a button per channel */
2183 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2192 RouteUI::invert_press (GdkEventButton* ev)
2194 using namespace Menu_Helpers;
2196 uint32_t const N = _route->input()->n_ports().n_audio();
2197 if (N <= _max_invert_buttons && ev->button != 3) {
2198 /* If we have an invert button per channel, we only pop
2199 up a menu on right-click; left click is handled
2205 delete _invert_menu;
2206 _invert_menu = new Menu;
2207 _invert_menu->set_name ("ArdourContextMenu");
2208 MenuList& items = _invert_menu->items ();
2210 for (uint32_t i = 0; i < N; ++i) {
2211 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2212 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2213 ++_i_am_the_modifier;
2214 e->set_active (_route->phase_control()->inverted (i));
2215 --_i_am_the_modifier;
2218 _invert_menu->popup (0, ev->time);
2224 RouteUI::invert_menu_toggled (uint32_t c)
2226 if (_i_am_the_modifier) {
2231 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2235 RouteUI::set_invert_sensitive (bool yn)
2237 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2238 (*b)->set_sensitive (yn);
2243 RouteUI::request_redraw ()
2246 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2250 /** The Route's gui_changed signal has been emitted */
2252 RouteUI::route_gui_changed (string what_changed)
2254 if (what_changed == "color") {
2255 if (set_color_from_route () == 0) {
2256 route_color_changed ();
2262 RouteUI::track_mode_changed (void)
2265 switch (track()->mode()) {
2266 case ARDOUR::NonLayered:
2267 case ARDOUR::Normal:
2268 rec_enable_button->set_icon (ArdourIcon::RecButton);
2270 case ARDOUR::Destructive:
2271 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2274 rec_enable_button->queue_draw();
2277 /** @return the color that this route should use; it maybe its own,
2278 or it maybe that of its route group.
2281 RouteUI::color () const
2283 RouteGroup* g = _route->route_group ();
2285 if (g && g->is_color()) {
2287 set_color_from_rgba (c, GroupTabs::group_color (g));
2295 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2297 _showing_sends_to = send_to;
2298 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2302 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2304 if (_route == send_to) {
2305 show_sends_button->set_active (true);
2306 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2308 show_sends_button->set_active (false);
2309 send_blink_connection.disconnect ();
2314 RouteUI::route_group() const
2316 return _route->route_group();
2320 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2321 : WM::ProxyBase (name, string())
2322 , _route (boost::weak_ptr<Route> (route))
2324 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2327 RoutePinWindowProxy::~RoutePinWindowProxy()
2332 ARDOUR::SessionHandlePtr*
2333 RoutePinWindowProxy::session_handle ()
2335 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2336 if (aw) { return aw; }
2341 RoutePinWindowProxy::get (bool create)
2343 boost::shared_ptr<Route> r = _route.lock ();
2352 _window = new PluginPinDialog (r);
2353 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2355 aw->set_session (_session);
2357 _window->show_all ();
2363 RoutePinWindowProxy::route_going_away ()
2367 WM::Manager::instance().remove (this);
2368 going_away_connection.disconnect();
2372 RouteUI::maybe_add_route_print_mgr ()
2374 if (_route->pinmgr_proxy ()) {
2377 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2378 string_compose ("RPM-%1", _route->id()), _route);
2379 wp->set_session (_session);
2381 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2383 wp->set_state (*ui_xml, 0);
2387 void* existing_ui = _route->pinmgr_proxy ();
2389 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2392 _route->set_pingmgr_proxy (wp);
2394 WM::Manager::instance().register_window (wp);
2398 RouteUI::manage_pins ()
2400 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();