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, &Stripable::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, &Stripable::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, &Stripable::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(), &Stripable::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, &Stripable::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, &Stripable::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, &Stripable::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(), &Stripable::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, &Stripable::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, &Stripable::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->rec_enable_control()->get_value());
900 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
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 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
923 /* This check is made inside the control too, but dong it here can't
927 if (_route->rec_enable_control()->get_value()) {
931 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
935 RouteUI::step_edit_changed (bool yn)
938 if (rec_enable_button) {
939 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
942 start_step_editing ();
944 if (step_edit_item) {
945 step_edit_item->set_active (true);
950 if (rec_enable_button) {
951 rec_enable_button->unset_active_state ();
954 stop_step_editing ();
956 if (step_edit_item) {
957 step_edit_item->set_active (false);
963 RouteUI::rec_enable_release (GdkEventButton* ev)
965 if (Keyboard::is_context_menu_event (ev)) {
966 build_record_menu ();
968 record_menu->popup (1, ev->time);
977 RouteUI::build_sends_menu ()
979 using namespace Menu_Helpers;
981 sends_menu = new Menu;
982 sends_menu->set_name ("ArdourContextMenu");
983 MenuList& items = sends_menu->items();
986 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
990 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
994 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
998 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1002 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1006 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1009 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1013 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1016 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1017 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1018 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1023 RouteUI::create_sends (Placement p, bool include_buses)
1025 _session->globally_add_internal_sends (_route, p, include_buses);
1029 RouteUI::create_selected_sends (Placement p, bool include_buses)
1031 boost::shared_ptr<RouteList> rlist (new RouteList);
1032 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1034 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1035 RouteTimeAxisView* rtv;
1037 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1038 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1039 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1040 rlist->push_back (rui->route());
1046 _session->add_internal_sends (_route, p, rlist);
1050 RouteUI::set_sends_gain_from_track ()
1052 _session->globally_set_send_gains_from_track (_route);
1056 RouteUI::set_sends_gain_to_zero ()
1058 _session->globally_set_send_gains_to_zero (_route);
1062 RouteUI::set_sends_gain_to_unity ()
1064 _session->globally_set_send_gains_to_unity (_route);
1068 RouteUI::show_sends_press(GdkEventButton* ev)
1070 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1074 if (!is_track() && show_sends_button) {
1076 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1078 // do nothing on midi sigc::bind event
1081 } else if (Keyboard::is_context_menu_event (ev)) {
1083 if (sends_menu == 0) {
1084 build_sends_menu ();
1087 sends_menu->popup (0, ev->time);
1091 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1094 set_showing_sends_to (boost::shared_ptr<Route> ());
1096 set_showing_sends_to (_route);
1105 RouteUI::show_sends_release (GdkEventButton*)
1111 RouteUI::send_blink (bool onoff)
1113 if (!show_sends_button) {
1118 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1120 show_sends_button->unset_active_state ();
1124 Gtkmm2ext::ActiveState
1125 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1127 boost::shared_ptr<SoloControl> sc = s->solo_control();
1130 return Gtkmm2ext::Off;
1133 if (!sc->can_solo()) {
1134 return Gtkmm2ext::Off;
1138 if (sc->self_soloed()) {
1139 return Gtkmm2ext::ExplicitActive;
1140 } else if (sc->soloed_by_others()) {
1141 return Gtkmm2ext::ImplicitActive;
1143 return Gtkmm2ext::Off;
1147 Gtkmm2ext::ActiveState
1148 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1150 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1153 return Gtkmm2ext::Off;
1156 if (s->is_master() || s->is_monitor()) {
1157 return Gtkmm2ext::Off;
1160 if (sc->solo_isolated()) {
1161 return Gtkmm2ext::ExplicitActive;
1163 return Gtkmm2ext::Off;
1167 Gtkmm2ext::ActiveState
1168 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1170 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1173 return Gtkmm2ext::Off;
1176 if (s->is_master() || s->is_monitor()) {
1177 return Gtkmm2ext::Off;
1180 if (sc->solo_safe()) {
1181 return Gtkmm2ext::ExplicitActive;
1183 return Gtkmm2ext::Off;
1188 RouteUI::update_solo_display ()
1190 bool yn = _route->solo_safe_control()->solo_safe ();
1192 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1193 solo_safe_check->set_active (yn);
1196 yn = _route->solo_isolate_control()->solo_isolated ();
1198 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1199 solo_isolated_check->set_active (yn);
1202 set_button_names ();
1204 if (solo_isolated_led) {
1205 if (_route->solo_isolate_control()->solo_isolated()) {
1206 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1208 solo_isolated_led->unset_active_state ();
1212 if (solo_safe_led) {
1213 if (_route->solo_safe_control()->solo_safe()) {
1214 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1216 solo_safe_led->unset_active_state ();
1220 solo_button->set_active_state (solo_active_state (_route));
1222 /* some changes to solo status can affect mute display, so catch up
1225 update_mute_display ();
1229 RouteUI::solo_changed_so_update_mute ()
1231 update_mute_display ();
1235 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1237 boost::shared_ptr<MuteControl> mc = s->mute_control();
1239 if (s->is_monitor()) {
1240 return Gtkmm2ext::Off;
1244 return Gtkmm2ext::Off;
1247 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1249 if (mc->muted_by_self ()) {
1251 return Gtkmm2ext::ExplicitActive;
1252 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1253 /* this will reflect both solo mutes AND master mutes */
1254 return Gtkmm2ext::ImplicitActive;
1256 /* no mute at all */
1257 return Gtkmm2ext::Off;
1262 if (mc->muted_by_self()) {
1264 return Gtkmm2ext::ExplicitActive;
1265 } else if (mc->muted_by_masters ()) {
1266 /* this shows only master mutes, not mute-by-others-soloing */
1267 return Gtkmm2ext::ImplicitActive;
1269 /* no mute at all */
1270 return Gtkmm2ext::Off;
1274 return ActiveState(0);
1278 RouteUI::update_mute_display ()
1284 mute_button->set_active_state (mute_active_state (_session, _route));
1288 RouteUI::update_vca_display ()
1294 VCAList vcas (_session->vca_manager().vcas());
1297 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1298 if (_route->slaved_to (*v)) {
1299 if (!label.empty()) {
1302 label += PBD::to_string ((*v)->number(), std::dec);
1306 if (label.empty()) {
1308 vca_button->set_active_state (Gtkmm2ext::Off);
1310 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1313 vca_button->set_text (label);
1317 RouteUI::route_rec_enable_changed ()
1319 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1320 update_monitoring_display ();
1324 RouteUI::session_rec_enable_changed ()
1326 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1327 update_monitoring_display ();
1331 RouteUI::blink_rec_display (bool blinkOn)
1333 if (!rec_enable_button || !_route) {
1337 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1345 if (track()->rec_enable_control()->get_value()) {
1346 switch (_session->record_status ()) {
1347 case Session::Recording:
1348 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1351 case Session::Disabled:
1352 case Session::Enabled:
1353 if (UIConfiguration::instance().get_blink_rec_arm()) {
1354 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1356 rec_enable_button->set_active_state ( ImplicitActive );
1361 if (step_edit_item) {
1362 step_edit_item->set_sensitive (false);
1366 rec_enable_button->unset_active_state ();
1368 if (step_edit_item) {
1369 step_edit_item->set_sensitive (true);
1373 check_rec_enable_sensitivity ();
1377 RouteUI::build_solo_menu (void)
1379 using namespace Menu_Helpers;
1381 solo_menu = new Menu;
1382 solo_menu->set_name ("ArdourContextMenu");
1383 MenuList& items = solo_menu->items();
1384 Gtk::CheckMenuItem* check;
1386 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1387 check->set_active (_route->solo_isolate_control()->solo_isolated());
1388 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1389 items.push_back (CheckMenuElem(*check));
1390 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1393 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1394 check->set_active (_route->solo_safe_control()->solo_safe());
1395 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1396 items.push_back (CheckMenuElem(*check));
1397 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1400 //items.push_back (SeparatorElem());
1401 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1406 RouteUI::build_mute_menu(void)
1408 using namespace Menu_Helpers;
1410 mute_menu = new Menu;
1411 mute_menu->set_name ("ArdourContextMenu");
1413 MenuList& items = mute_menu->items();
1415 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1416 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1417 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1418 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1419 pre_fader_mute_check->show_all();
1421 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1422 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1423 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1424 items.push_back (CheckMenuElem(*post_fader_mute_check));
1425 post_fader_mute_check->show_all();
1427 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1428 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1429 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1430 items.push_back (CheckMenuElem(*listen_mute_check));
1431 listen_mute_check->show_all();
1433 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1434 init_mute_menu(MuteMaster::Main, main_mute_check);
1435 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1436 items.push_back (CheckMenuElem(*main_mute_check));
1437 main_mute_check->show_all();
1439 //items.push_back (SeparatorElem());
1440 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1442 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1446 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1448 check->set_active (_route->mute_control()->mute_points() & mp);
1452 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1454 if (check->get_active()) {
1455 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1457 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1462 RouteUI::muting_change ()
1464 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1467 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1469 yn = (current & MuteMaster::PreFader);
1471 if (pre_fader_mute_check->get_active() != yn) {
1472 pre_fader_mute_check->set_active (yn);
1475 yn = (current & MuteMaster::PostFader);
1477 if (post_fader_mute_check->get_active() != yn) {
1478 post_fader_mute_check->set_active (yn);
1481 yn = (current & MuteMaster::Listen);
1483 if (listen_mute_check->get_active() != yn) {
1484 listen_mute_check->set_active (yn);
1487 yn = (current & MuteMaster::Main);
1489 if (main_mute_check->get_active() != yn) {
1490 main_mute_check->set_active (yn);
1495 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1497 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1501 bool view = solo_isolated_led->active_state();
1502 bool model = _route->solo_isolate_control()->solo_isolated();
1504 /* called BEFORE the view has changed */
1506 if (ev->button == 1) {
1507 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1510 /* disable isolate for all routes */
1511 DisplaySuspender ds;
1512 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1514 /* enable isolate for all routes */
1515 DisplaySuspender ds;
1516 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1521 if (model == view) {
1523 /* flip just this route */
1525 boost::shared_ptr<RouteList> rl (new RouteList);
1526 rl->push_back (_route);
1527 DisplaySuspender ds;
1528 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1537 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1539 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1543 bool view = solo_safe_led->active_state();
1544 bool model = _route->solo_safe_control()->solo_safe();
1546 if (ev->button == 1) {
1547 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1548 boost::shared_ptr<RouteList> rl (_session->get_routes());
1550 /* disable solo safe for all routes */
1551 DisplaySuspender ds;
1552 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1553 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1556 /* enable solo safe for all routes */
1557 DisplaySuspender ds;
1558 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1559 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1564 if (model == view) {
1565 /* flip just this route */
1566 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1575 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1577 bool view = check->get_active();
1578 bool model = _route->solo_isolate_control()->solo_isolated();
1580 /* called AFTER the view has changed */
1582 if (model != view) {
1583 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1588 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1590 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1593 /** Ask the user to choose a colour, and then apply that color to my route
1596 RouteUI::choose_color ()
1599 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1606 /** Set the route's own color. This may not be used for display if
1607 * the route is in a group which shares its color with its routes.
1610 RouteUI::set_color (const Gdk::Color & c)
1612 /* leave _color alone in the group case so that tracks can retain their
1613 * own pre-group colors.
1618 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1620 /* note: we use the route state ID here so that color is the same for both
1621 the time axis view and the mixer strip
1624 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1625 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1628 /** @return GUI state ID for things that are common to the route in all its representations */
1630 RouteUI::route_state_id () const
1632 return string_compose (X_("route %1"), _route->id().to_s());
1636 RouteUI::set_color_from_route ()
1638 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1646 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1649 _color.set_green (g);
1650 _color.set_blue (b);
1655 /** @return true if this name should be used for the route, otherwise false */
1657 RouteUI::verify_new_route_name (const std::string& name)
1659 if (name.find (':') == string::npos) {
1663 MessageDialog colon_msg (
1664 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1665 false, MESSAGE_QUESTION, BUTTONS_NONE
1668 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1669 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1671 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1675 RouteUI::route_rename ()
1677 ArdourPrompter name_prompter (true);
1682 name_prompter.set_title (_("Rename Track"));
1684 name_prompter.set_title (_("Rename Bus"));
1686 name_prompter.set_prompt (_("New name:"));
1687 name_prompter.set_initial_text (_route->name());
1688 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1689 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1690 name_prompter.show_all ();
1693 switch (name_prompter.run ()) {
1694 case Gtk::RESPONSE_ACCEPT:
1695 name_prompter.get_result (result);
1696 name_prompter.hide ();
1697 if (result.length()) {
1698 if (verify_new_route_name (result)) {
1699 _route->set_name (result);
1702 /* back to name prompter */
1706 /* nothing entered, just get out of here */
1721 RouteUI::property_changed (const PropertyChange& what_changed)
1723 if (what_changed.contains (ARDOUR::Properties::name)) {
1724 name_label.set_text (_route->name());
1729 RouteUI::toggle_comment_editor ()
1731 // if (ignore_toggle) {
1735 if (comment_window && comment_window->is_visible ()) {
1736 comment_window->hide ();
1738 open_comment_editor ();
1744 RouteUI::open_comment_editor ()
1746 if (comment_window == 0) {
1747 setup_comment_editor ();
1751 title = _route->name();
1752 title += _(": comment editor");
1754 comment_window->set_title (title);
1755 comment_window->present();
1759 RouteUI::setup_comment_editor ()
1761 comment_window = new ArdourWindow (""); // title will be reset to show route
1762 comment_window->set_skip_taskbar_hint (true);
1763 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1764 comment_window->set_default_size (400, 200);
1766 comment_area = manage (new TextView());
1767 comment_area->set_name ("MixerTrackCommentArea");
1768 comment_area->set_wrap_mode (WRAP_WORD);
1769 comment_area->set_editable (true);
1770 comment_area->get_buffer()->set_text (_route->comment());
1771 comment_area->show ();
1773 comment_window->add (*comment_area);
1777 RouteUI::comment_changed ()
1779 ignore_comment_edit = true;
1781 comment_area->get_buffer()->set_text (_route->comment());
1783 ignore_comment_edit = false;
1787 RouteUI::comment_editor_done_editing ()
1789 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1791 string const str = comment_area->get_buffer()->get_text();
1792 if (str == _route->comment ()) {
1796 _route->set_comment (str, this);
1800 RouteUI::set_route_active (bool a, bool apply_to_selection)
1802 if (apply_to_selection) {
1803 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1805 _route->set_active (a, this);
1810 RouteUI::duplicate_selected_routes ()
1812 ARDOUR_UI::instance()->start_duplicate_routes();
1816 RouteUI::toggle_denormal_protection ()
1818 if (denormal_menu_item) {
1822 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1824 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1825 _route->set_denormal_protection (x);
1831 RouteUI::denormal_protection_changed ()
1833 if (denormal_menu_item) {
1834 denormal_menu_item->set_active (_route->denormal_protection());
1839 RouteUI::disconnect_input ()
1841 _route->input()->disconnect (this);
1845 RouteUI::disconnect_output ()
1847 _route->output()->disconnect (this);
1851 RouteUI::is_track () const
1853 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1856 boost::shared_ptr<Track>
1857 RouteUI::track() const
1859 return boost::dynamic_pointer_cast<Track>(_route);
1863 RouteUI::is_audio_track () const
1865 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1868 boost::shared_ptr<AudioTrack>
1869 RouteUI::audio_track() const
1871 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1875 RouteUI::is_midi_track () const
1877 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1880 boost::shared_ptr<MidiTrack>
1881 RouteUI::midi_track() const
1883 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1887 RouteUI::has_audio_outputs () const
1889 return (_route->n_outputs().n_audio() > 0);
1893 RouteUI::name() const
1895 return _route->name();
1899 RouteUI::map_frozen ()
1901 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1903 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1906 check_rec_enable_sensitivity ();
1911 RouteUI::adjust_latency ()
1913 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1917 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1920 std::string safe_name;
1923 prompter.get_result (name, true);
1925 safe_name = legalize_for_path (name);
1926 safe_name += template_suffix;
1928 path = Glib::build_filename (dir, safe_name);
1930 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1931 bool overwrite = overwrite_file_dialog (prompter,
1932 _("Confirm Template Overwrite"),
1933 _("A template already exists with that name. Do you want to overwrite it?"));
1940 _route->save_as_template (path, name);
1946 RouteUI::save_as_template ()
1950 dir = ARDOUR::user_route_template_directory ();
1952 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1953 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1957 ArdourPrompter prompter (true); // modal
1959 prompter.set_title (_("Save As Template"));
1960 prompter.set_prompt (_("Template name:"));
1961 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1963 bool finished = false;
1965 switch (prompter.run()) {
1966 case RESPONSE_ACCEPT:
1967 finished = process_save_template_prompter (prompter, dir);
1977 RouteUI::check_rec_enable_sensitivity ()
1979 if (!rec_enable_button) {
1980 assert (0); // This should not happen
1983 if (!_session->writable()) {
1984 rec_enable_button->set_sensitive (false);
1988 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1989 rec_enable_button->set_sensitive (false);
1990 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1991 rec_enable_button->set_sensitive (false);
1993 rec_enable_button->set_sensitive (true);
1995 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1996 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1998 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2000 update_monitoring_display ();
2004 RouteUI::parameter_changed (string const & p)
2006 /* this handles RC and per-session parameter changes */
2008 if (p == "disable-disarm-during-roll") {
2009 check_rec_enable_sensitivity ();
2010 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2011 set_button_names ();
2012 } else if (p == "auto-input") {
2013 update_monitoring_display ();
2014 } else if (p == "blink-rec-arm") {
2015 if (UIConfiguration::instance().get_blink_rec_arm()) {
2016 rec_blink_connection.disconnect ();
2017 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2019 rec_blink_connection.disconnect ();
2020 RouteUI::blink_rec_display(false);
2026 RouteUI::step_gain_up ()
2028 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2032 RouteUI::page_gain_up ()
2034 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2038 RouteUI::step_gain_down ()
2040 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2044 RouteUI::page_gain_down ()
2046 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2050 RouteUI::setup_invert_buttons ()
2052 /* remove old invert buttons */
2053 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2054 _invert_button_box.remove (**i);
2057 _invert_buttons.clear ();
2059 if (!_route || !_route->input()) {
2063 uint32_t const N = _route->input()->n_ports().n_audio ();
2065 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2067 for (uint32_t i = 0; i < to_add; ++i) {
2068 ArdourButton* b = manage (new ArdourButton);
2069 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2070 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2072 b->set_name (X_("invert button"));
2075 b->set_text (string_compose (X_("Ø (%1)"), N));
2077 b->set_text (X_("Ø"));
2080 b->set_text (string_compose (X_("Ø%1"), i + 1));
2083 if (N <= _max_invert_buttons) {
2084 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));
2086 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2089 _invert_buttons.push_back (b);
2090 _invert_button_box.pack_start (*b);
2093 _invert_button_box.set_spacing (1);
2094 _invert_button_box.show_all ();
2098 RouteUI::set_invert_button_state ()
2100 uint32_t const N = _route->input()->n_ports().n_audio();
2101 if (N > _max_invert_buttons) {
2103 /* One button for many channels; explicit active if all channels are inverted,
2104 implicit active if some are, off if none are.
2107 ArdourButton* b = _invert_buttons.front ();
2109 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2110 b->set_active_state (Gtkmm2ext::ExplicitActive);
2111 } else if (_route->phase_control()->any()) {
2112 b->set_active_state (Gtkmm2ext::ImplicitActive);
2114 b->set_active_state (Gtkmm2ext::Off);
2119 /* One button per channel; just set active */
2122 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2123 (*i)->set_active (_route->phase_control()->inverted (j));
2130 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2132 if (ev->button == 1 && i < _invert_buttons.size()) {
2133 uint32_t const N = _route->input()->n_ports().n_audio ();
2134 if (N <= _max_invert_buttons) {
2135 /* left-click inverts phase so long as we have a button per channel */
2136 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2145 RouteUI::invert_press (GdkEventButton* ev)
2147 using namespace Menu_Helpers;
2149 uint32_t const N = _route->input()->n_ports().n_audio();
2150 if (N <= _max_invert_buttons && ev->button != 3) {
2151 /* If we have an invert button per channel, we only pop
2152 up a menu on right-click; left click is handled
2158 delete _invert_menu;
2159 _invert_menu = new Menu;
2160 _invert_menu->set_name ("ArdourContextMenu");
2161 MenuList& items = _invert_menu->items ();
2163 for (uint32_t i = 0; i < N; ++i) {
2164 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2165 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2166 ++_i_am_the_modifier;
2167 e->set_active (_route->phase_control()->inverted (i));
2168 --_i_am_the_modifier;
2171 _invert_menu->popup (0, ev->time);
2177 RouteUI::invert_menu_toggled (uint32_t c)
2179 if (_i_am_the_modifier) {
2184 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2188 RouteUI::set_invert_sensitive (bool yn)
2190 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2191 (*b)->set_sensitive (yn);
2196 RouteUI::request_redraw ()
2199 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2203 /** The Route's gui_changed signal has been emitted */
2205 RouteUI::route_gui_changed (string what_changed)
2207 if (what_changed == "color") {
2208 if (set_color_from_route () == 0) {
2209 route_color_changed ();
2215 RouteUI::track_mode_changed (void)
2218 switch (track()->mode()) {
2219 case ARDOUR::NonLayered:
2220 case ARDOUR::Normal:
2221 rec_enable_button->set_icon (ArdourIcon::RecButton);
2223 case ARDOUR::Destructive:
2224 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2227 rec_enable_button->queue_draw();
2230 /** @return the color that this route should use; it maybe its own,
2231 or it maybe that of its route group.
2234 RouteUI::color () const
2236 RouteGroup* g = _route->route_group ();
2238 if (g && g->is_color()) {
2240 set_color_from_rgba (c, GroupTabs::group_color (g));
2248 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2250 _showing_sends_to = send_to;
2251 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2255 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2257 if (_route == send_to) {
2258 show_sends_button->set_active (true);
2259 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2261 show_sends_button->set_active (false);
2262 send_blink_connection.disconnect ();
2267 RouteUI::route_group() const
2269 return _route->route_group();
2273 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2274 : WM::ProxyBase (name, string())
2275 , _route (boost::weak_ptr<Route> (route))
2277 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2280 RoutePinWindowProxy::~RoutePinWindowProxy()
2285 ARDOUR::SessionHandlePtr*
2286 RoutePinWindowProxy::session_handle ()
2288 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2289 if (aw) { return aw; }
2294 RoutePinWindowProxy::get (bool create)
2296 boost::shared_ptr<Route> r = _route.lock ();
2305 _window = new PluginPinDialog (r);
2306 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2308 aw->set_session (_session);
2310 _window->show_all ();
2316 RoutePinWindowProxy::route_going_away ()
2320 WM::Manager::instance().remove (this);
2321 going_away_connection.disconnect();
2325 RouteUI::maybe_add_route_print_mgr ()
2327 if (_route->pinmgr_proxy ()) {
2330 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2331 string_compose ("RPM-%1", _route->id()), _route);
2332 wp->set_session (_session);
2334 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2336 wp->set_state (*ui_xml, 0);
2340 void* existing_ui = _route->pinmgr_proxy ();
2342 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2345 _route->set_pingmgr_proxy (wp);
2347 WM::Manager::instance().register_window (wp);
2351 RouteUI::manage_pins ()
2353 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();