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<Route> r)
1119 if (!r->can_solo()) {
1120 return Gtkmm2ext::Off;
1123 if (Config->get_solo_control_is_listen_control()) {
1125 if (r->listening_via_monitor()) {
1126 return Gtkmm2ext::ExplicitActive;
1128 return Gtkmm2ext::Off;
1134 if (!r->self_soloed()) {
1135 return Gtkmm2ext::ImplicitActive;
1137 return Gtkmm2ext::ExplicitActive;
1140 return Gtkmm2ext::Off;
1144 Gtkmm2ext::ActiveState
1145 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1147 if (r->is_master() || r->is_monitor()) {
1148 return Gtkmm2ext::Off;
1151 if (r->solo_isolate_control()->solo_isolated()) {
1152 return Gtkmm2ext::ExplicitActive;
1154 return Gtkmm2ext::Off;
1158 Gtkmm2ext::ActiveState
1159 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1161 if (r->is_master() || r->is_monitor()) {
1162 return Gtkmm2ext::Off;
1165 if (r->solo_safe_control()->solo_safe()) {
1166 return Gtkmm2ext::ExplicitActive;
1168 return Gtkmm2ext::Off;
1173 RouteUI::update_solo_display ()
1175 bool yn = _route->solo_safe_control()->solo_safe ();
1177 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1178 solo_safe_check->set_active (yn);
1181 yn = _route->solo_isolate_control()->solo_isolated ();
1183 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1184 solo_isolated_check->set_active (yn);
1187 set_button_names ();
1189 if (solo_isolated_led) {
1190 if (_route->solo_isolate_control()->solo_isolated()) {
1191 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1193 solo_isolated_led->unset_active_state ();
1197 if (solo_safe_led) {
1198 if (_route->solo_safe_control()->solo_safe()) {
1199 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1201 solo_safe_led->unset_active_state ();
1205 solo_button->set_active_state (solo_active_state (_route));
1207 /* some changes to solo status can affect mute display, so catch up
1210 update_mute_display ();
1214 RouteUI::solo_changed_so_update_mute ()
1216 update_mute_display ();
1220 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1222 if (r->is_monitor()) {
1223 return ActiveState(0);
1226 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1228 std::cerr << r->name() << " self " << r->mute_control()->muted_by_self() << " others " << r->muted_by_others() << " soloing " << r->muted_by_others_soloing() << std::endl;
1230 if (r->mute_control()->muted_by_self ()) {
1232 return Gtkmm2ext::ExplicitActive;
1233 } else if (r->muted_by_others_soloing () || r->muted_by_others()) {
1234 /* this will reflect both solo mutes AND master mutes */
1235 return Gtkmm2ext::ImplicitActive;
1237 /* no mute at all */
1238 return Gtkmm2ext::Off;
1243 if (r->mute_control()->muted_by_self()) {
1245 return Gtkmm2ext::ExplicitActive;
1246 } else if (r->muted_by_others()) {
1247 /* this shows only master mutes, not mute-by-others-soloing */
1248 return Gtkmm2ext::ImplicitActive;
1250 /* no mute at all */
1251 return Gtkmm2ext::Off;
1255 return ActiveState(0);
1259 RouteUI::update_mute_display ()
1265 mute_button->set_active_state (mute_active_state (_session, _route));
1269 RouteUI::update_vca_display ()
1275 VCAList vcas (_session->vca_manager().vcas());
1278 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1279 if (_route->slaved_to (*v)) {
1280 if (!label.empty()) {
1283 label += PBD::to_string ((*v)->number(), std::dec);
1287 if (label.empty()) {
1289 vca_button->set_active_state (Gtkmm2ext::Off);
1291 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1294 vca_button->set_text (label);
1298 RouteUI::route_rec_enable_changed ()
1300 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1301 update_monitoring_display ();
1305 RouteUI::session_rec_enable_changed ()
1307 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1308 update_monitoring_display ();
1312 RouteUI::blink_rec_display (bool blinkOn)
1314 if (!rec_enable_button || !_route) {
1318 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1326 if (track()->rec_enable_control()->get_value()) {
1327 switch (_session->record_status ()) {
1328 case Session::Recording:
1329 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1332 case Session::Disabled:
1333 case Session::Enabled:
1334 if (UIConfiguration::instance().get_blink_rec_arm()) {
1335 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1337 rec_enable_button->set_active_state ( ImplicitActive );
1342 if (step_edit_item) {
1343 step_edit_item->set_sensitive (false);
1347 rec_enable_button->unset_active_state ();
1349 if (step_edit_item) {
1350 step_edit_item->set_sensitive (true);
1354 check_rec_enable_sensitivity ();
1358 RouteUI::build_solo_menu (void)
1360 using namespace Menu_Helpers;
1362 solo_menu = new Menu;
1363 solo_menu->set_name ("ArdourContextMenu");
1364 MenuList& items = solo_menu->items();
1365 Gtk::CheckMenuItem* check;
1367 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1368 check->set_active (_route->solo_isolate_control()->solo_isolated());
1369 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1370 items.push_back (CheckMenuElem(*check));
1371 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1374 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1375 check->set_active (_route->solo_safe_control()->solo_safe());
1376 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1377 items.push_back (CheckMenuElem(*check));
1378 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1381 //items.push_back (SeparatorElem());
1382 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1387 RouteUI::build_mute_menu(void)
1389 using namespace Menu_Helpers;
1391 mute_menu = new Menu;
1392 mute_menu->set_name ("ArdourContextMenu");
1394 MenuList& items = mute_menu->items();
1396 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1397 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1398 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1399 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1400 pre_fader_mute_check->show_all();
1402 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1403 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1404 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1405 items.push_back (CheckMenuElem(*post_fader_mute_check));
1406 post_fader_mute_check->show_all();
1408 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1409 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1410 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1411 items.push_back (CheckMenuElem(*listen_mute_check));
1412 listen_mute_check->show_all();
1414 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1415 init_mute_menu(MuteMaster::Main, main_mute_check);
1416 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1417 items.push_back (CheckMenuElem(*main_mute_check));
1418 main_mute_check->show_all();
1420 //items.push_back (SeparatorElem());
1421 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1423 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1427 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1429 check->set_active (_route->mute_control()->mute_points() & mp);
1433 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1435 if (check->get_active()) {
1436 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1438 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1443 RouteUI::muting_change ()
1445 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1448 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1450 yn = (current & MuteMaster::PreFader);
1452 if (pre_fader_mute_check->get_active() != yn) {
1453 pre_fader_mute_check->set_active (yn);
1456 yn = (current & MuteMaster::PostFader);
1458 if (post_fader_mute_check->get_active() != yn) {
1459 post_fader_mute_check->set_active (yn);
1462 yn = (current & MuteMaster::Listen);
1464 if (listen_mute_check->get_active() != yn) {
1465 listen_mute_check->set_active (yn);
1468 yn = (current & MuteMaster::Main);
1470 if (main_mute_check->get_active() != yn) {
1471 main_mute_check->set_active (yn);
1476 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1478 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1482 bool view = solo_isolated_led->active_state();
1483 bool model = _route->solo_isolate_control()->solo_isolated();
1485 /* called BEFORE the view has changed */
1487 if (ev->button == 1) {
1488 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1491 /* disable isolate for all routes */
1492 DisplaySuspender ds;
1493 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 0.0, Controllable::NoGroup);
1495 /* enable isolate for all routes */
1496 DisplaySuspender ds;
1497 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 1.0, Controllable::NoGroup);
1502 if (model == view) {
1504 /* flip just this route */
1506 boost::shared_ptr<RouteList> rl (new RouteList);
1507 rl->push_back (_route);
1508 DisplaySuspender ds;
1509 _session->set_controls (route_list_to_control_list (rl, &Route::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1518 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1520 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1524 bool view = solo_safe_led->active_state();
1525 bool model = _route->solo_safe_control()->solo_safe();
1527 if (ev->button == 1) {
1528 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1529 boost::shared_ptr<RouteList> rl (_session->get_routes());
1531 /* disable solo safe for all routes */
1532 DisplaySuspender ds;
1533 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1534 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1537 /* enable solo safe for all routes */
1538 DisplaySuspender ds;
1539 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1540 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1545 if (model == view) {
1546 /* flip just this route */
1547 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1556 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1558 bool view = check->get_active();
1559 bool model = _route->solo_isolate_control()->solo_isolated();
1561 /* called AFTER the view has changed */
1563 if (model != view) {
1564 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1569 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1571 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1574 /** Ask the user to choose a colour, and then apply that color to my route
1577 RouteUI::choose_color ()
1580 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1587 /** Set the route's own color. This may not be used for display if
1588 * the route is in a group which shares its color with its routes.
1591 RouteUI::set_color (const Gdk::Color & c)
1593 /* leave _color alone in the group case so that tracks can retain their
1594 * own pre-group colors.
1599 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1601 /* note: we use the route state ID here so that color is the same for both
1602 the time axis view and the mixer strip
1605 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1606 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1609 /** @return GUI state ID for things that are common to the route in all its representations */
1611 RouteUI::route_state_id () const
1613 return string_compose (X_("route %1"), _route->id().to_s());
1617 RouteUI::set_color_from_route ()
1619 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1627 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1630 _color.set_green (g);
1631 _color.set_blue (b);
1636 /** @return true if this name should be used for the route, otherwise false */
1638 RouteUI::verify_new_route_name (const std::string& name)
1640 if (name.find (':') == string::npos) {
1644 MessageDialog colon_msg (
1645 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1646 false, MESSAGE_QUESTION, BUTTONS_NONE
1649 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1650 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1652 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1656 RouteUI::route_rename ()
1658 ArdourPrompter name_prompter (true);
1663 name_prompter.set_title (_("Rename Track"));
1665 name_prompter.set_title (_("Rename Bus"));
1667 name_prompter.set_prompt (_("New name:"));
1668 name_prompter.set_initial_text (_route->name());
1669 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1670 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1671 name_prompter.show_all ();
1674 switch (name_prompter.run ()) {
1675 case Gtk::RESPONSE_ACCEPT:
1676 name_prompter.get_result (result);
1677 name_prompter.hide ();
1678 if (result.length()) {
1679 if (verify_new_route_name (result)) {
1680 _route->set_name (result);
1683 /* back to name prompter */
1687 /* nothing entered, just get out of here */
1702 RouteUI::property_changed (const PropertyChange& what_changed)
1704 if (what_changed.contains (ARDOUR::Properties::name)) {
1705 name_label.set_text (_route->name());
1710 RouteUI::toggle_comment_editor ()
1712 // if (ignore_toggle) {
1716 if (comment_window && comment_window->is_visible ()) {
1717 comment_window->hide ();
1719 open_comment_editor ();
1725 RouteUI::open_comment_editor ()
1727 if (comment_window == 0) {
1728 setup_comment_editor ();
1732 title = _route->name();
1733 title += _(": comment editor");
1735 comment_window->set_title (title);
1736 comment_window->present();
1740 RouteUI::setup_comment_editor ()
1742 comment_window = new ArdourWindow (""); // title will be reset to show route
1743 comment_window->set_skip_taskbar_hint (true);
1744 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1745 comment_window->set_default_size (400, 200);
1747 comment_area = manage (new TextView());
1748 comment_area->set_name ("MixerTrackCommentArea");
1749 comment_area->set_wrap_mode (WRAP_WORD);
1750 comment_area->set_editable (true);
1751 comment_area->get_buffer()->set_text (_route->comment());
1752 comment_area->show ();
1754 comment_window->add (*comment_area);
1758 RouteUI::comment_changed ()
1760 ignore_comment_edit = true;
1762 comment_area->get_buffer()->set_text (_route->comment());
1764 ignore_comment_edit = false;
1768 RouteUI::comment_editor_done_editing ()
1770 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1772 string const str = comment_area->get_buffer()->get_text();
1773 if (str == _route->comment ()) {
1777 _route->set_comment (str, this);
1781 RouteUI::set_route_active (bool a, bool apply_to_selection)
1783 if (apply_to_selection) {
1784 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1786 _route->set_active (a, this);
1791 RouteUI::duplicate_selected_routes ()
1793 ARDOUR_UI::instance()->start_duplicate_routes();
1797 RouteUI::toggle_denormal_protection ()
1799 if (denormal_menu_item) {
1803 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1805 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1806 _route->set_denormal_protection (x);
1812 RouteUI::denormal_protection_changed ()
1814 if (denormal_menu_item) {
1815 denormal_menu_item->set_active (_route->denormal_protection());
1820 RouteUI::disconnect_input ()
1822 _route->input()->disconnect (this);
1826 RouteUI::disconnect_output ()
1828 _route->output()->disconnect (this);
1832 RouteUI::is_track () const
1834 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1837 boost::shared_ptr<Track>
1838 RouteUI::track() const
1840 return boost::dynamic_pointer_cast<Track>(_route);
1844 RouteUI::is_audio_track () const
1846 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1849 boost::shared_ptr<AudioTrack>
1850 RouteUI::audio_track() const
1852 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1856 RouteUI::is_midi_track () const
1858 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1861 boost::shared_ptr<MidiTrack>
1862 RouteUI::midi_track() const
1864 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1868 RouteUI::has_audio_outputs () const
1870 return (_route->n_outputs().n_audio() > 0);
1874 RouteUI::name() const
1876 return _route->name();
1880 RouteUI::map_frozen ()
1882 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1884 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1887 check_rec_enable_sensitivity ();
1892 RouteUI::adjust_latency ()
1894 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1898 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1901 std::string safe_name;
1904 prompter.get_result (name, true);
1906 safe_name = legalize_for_path (name);
1907 safe_name += template_suffix;
1909 path = Glib::build_filename (dir, safe_name);
1911 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1912 bool overwrite = overwrite_file_dialog (prompter,
1913 _("Confirm Template Overwrite"),
1914 _("A template already exists with that name. Do you want to overwrite it?"));
1921 _route->save_as_template (path, name);
1927 RouteUI::save_as_template ()
1931 dir = ARDOUR::user_route_template_directory ();
1933 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1934 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1938 ArdourPrompter prompter (true); // modal
1940 prompter.set_title (_("Save As Template"));
1941 prompter.set_prompt (_("Template name:"));
1942 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1944 bool finished = false;
1946 switch (prompter.run()) {
1947 case RESPONSE_ACCEPT:
1948 finished = process_save_template_prompter (prompter, dir);
1958 RouteUI::check_rec_enable_sensitivity ()
1960 if (!rec_enable_button) {
1961 assert (0); // This should not happen
1964 if (!_session->writable()) {
1965 rec_enable_button->set_sensitive (false);
1969 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1970 rec_enable_button->set_sensitive (false);
1971 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1972 rec_enable_button->set_sensitive (false);
1974 rec_enable_button->set_sensitive (true);
1976 if (_route && _route->record_safe ()) {
1977 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1979 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1981 update_monitoring_display ();
1985 RouteUI::parameter_changed (string const & p)
1987 /* this handles RC and per-session parameter changes */
1989 if (p == "disable-disarm-during-roll") {
1990 check_rec_enable_sensitivity ();
1991 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1992 set_button_names ();
1993 } else if (p == "auto-input") {
1994 update_monitoring_display ();
1995 } else if (p == "blink-rec-arm") {
1996 if (UIConfiguration::instance().get_blink_rec_arm()) {
1997 rec_blink_connection.disconnect ();
1998 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2000 rec_blink_connection.disconnect ();
2001 RouteUI::blink_rec_display(false);
2007 RouteUI::step_gain_up ()
2009 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2013 RouteUI::page_gain_up ()
2015 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2019 RouteUI::step_gain_down ()
2021 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2025 RouteUI::page_gain_down ()
2027 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2031 RouteUI::open_remote_control_id_dialog ()
2033 ArdourDialog dialog (_("Remote Control ID"));
2034 SpinButton* spin = 0;
2036 dialog.get_vbox()->set_border_width (18);
2038 if (Config->get_remote_model() == UserOrdered) {
2039 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2041 HBox* hbox = manage (new HBox);
2042 hbox->set_spacing (6);
2043 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2044 spin = manage (new SpinButton);
2045 spin->set_digits (0);
2046 spin->set_increments (1, 10);
2047 spin->set_range (0, limit);
2048 spin->set_value (_route->remote_control_id());
2049 hbox->pack_start (*spin);
2050 dialog.get_vbox()->pack_start (*hbox);
2052 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2053 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2055 Label* l = manage (new Label());
2056 if (_route->is_master() || _route->is_monitor()) {
2057 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2058 "The remote control ID of %3 cannot be changed."),
2059 Gtkmm2ext::markup_escape_text (_route->name()),
2060 _route->remote_control_id(),
2061 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2063 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2064 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2065 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2066 (is_track() ? _("track") : _("bus")),
2067 _route->remote_control_id(),
2068 "<span size=\"small\" style=\"italic\">",
2070 Gtkmm2ext::markup_escape_text (_route->name()),
2073 dialog.get_vbox()->pack_start (*l);
2074 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2078 int const r = dialog.run ();
2080 if (r == RESPONSE_ACCEPT && spin) {
2081 _route->set_remote_control_id (spin->get_value_as_int ());
2086 RouteUI::setup_invert_buttons ()
2088 /* remove old invert buttons */
2089 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2090 _invert_button_box.remove (**i);
2093 _invert_buttons.clear ();
2095 if (!_route || !_route->input()) {
2099 uint32_t const N = _route->input()->n_ports().n_audio ();
2101 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2103 for (uint32_t i = 0; i < to_add; ++i) {
2104 ArdourButton* b = manage (new ArdourButton);
2105 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2106 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2108 b->set_name (X_("invert button"));
2111 b->set_text (string_compose (X_("Ø (%1)"), N));
2113 b->set_text (X_("Ø"));
2116 b->set_text (string_compose (X_("Ø%1"), i + 1));
2119 if (N <= _max_invert_buttons) {
2120 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));
2122 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2125 _invert_buttons.push_back (b);
2126 _invert_button_box.pack_start (*b);
2129 _invert_button_box.set_spacing (1);
2130 _invert_button_box.show_all ();
2134 RouteUI::set_invert_button_state ()
2136 uint32_t const N = _route->input()->n_ports().n_audio();
2137 if (N > _max_invert_buttons) {
2139 /* One button for many channels; explicit active if all channels are inverted,
2140 implicit active if some are, off if none are.
2143 ArdourButton* b = _invert_buttons.front ();
2145 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2146 b->set_active_state (Gtkmm2ext::ExplicitActive);
2147 } else if (_route->phase_control()->any()) {
2148 b->set_active_state (Gtkmm2ext::ImplicitActive);
2150 b->set_active_state (Gtkmm2ext::Off);
2155 /* One button per channel; just set active */
2158 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2159 (*i)->set_active (_route->phase_control()->inverted (j));
2166 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2168 if (ev->button == 1 && i < _invert_buttons.size()) {
2169 uint32_t const N = _route->input()->n_ports().n_audio ();
2170 if (N <= _max_invert_buttons) {
2171 /* left-click inverts phase so long as we have a button per channel */
2172 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2181 RouteUI::invert_press (GdkEventButton* ev)
2183 using namespace Menu_Helpers;
2185 uint32_t const N = _route->input()->n_ports().n_audio();
2186 if (N <= _max_invert_buttons && ev->button != 3) {
2187 /* If we have an invert button per channel, we only pop
2188 up a menu on right-click; left click is handled
2194 delete _invert_menu;
2195 _invert_menu = new Menu;
2196 _invert_menu->set_name ("ArdourContextMenu");
2197 MenuList& items = _invert_menu->items ();
2199 for (uint32_t i = 0; i < N; ++i) {
2200 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2201 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2202 ++_i_am_the_modifier;
2203 e->set_active (_route->phase_control()->inverted (i));
2204 --_i_am_the_modifier;
2207 _invert_menu->popup (0, ev->time);
2213 RouteUI::invert_menu_toggled (uint32_t c)
2215 if (_i_am_the_modifier) {
2220 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2224 RouteUI::set_invert_sensitive (bool yn)
2226 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2227 (*b)->set_sensitive (yn);
2232 RouteUI::request_redraw ()
2235 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2239 /** The Route's gui_changed signal has been emitted */
2241 RouteUI::route_gui_changed (string what_changed)
2243 if (what_changed == "color") {
2244 if (set_color_from_route () == 0) {
2245 route_color_changed ();
2251 RouteUI::track_mode_changed (void)
2254 switch (track()->mode()) {
2255 case ARDOUR::NonLayered:
2256 case ARDOUR::Normal:
2257 rec_enable_button->set_icon (ArdourIcon::RecButton);
2259 case ARDOUR::Destructive:
2260 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2263 rec_enable_button->queue_draw();
2266 /** @return the color that this route should use; it maybe its own,
2267 or it maybe that of its route group.
2270 RouteUI::color () const
2272 RouteGroup* g = _route->route_group ();
2274 if (g && g->is_color()) {
2276 set_color_from_rgba (c, GroupTabs::group_color (g));
2284 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2286 _showing_sends_to = send_to;
2287 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2291 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2293 if (_route == send_to) {
2294 show_sends_button->set_active (true);
2295 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2297 show_sends_button->set_active (false);
2298 send_blink_connection.disconnect ();
2303 RouteUI::route_group() const
2305 return _route->route_group();
2309 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2310 : WM::ProxyBase (name, string())
2311 , _route (boost::weak_ptr<Route> (route))
2313 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2316 RoutePinWindowProxy::~RoutePinWindowProxy()
2321 ARDOUR::SessionHandlePtr*
2322 RoutePinWindowProxy::session_handle ()
2324 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2325 if (aw) { return aw; }
2330 RoutePinWindowProxy::get (bool create)
2332 boost::shared_ptr<Route> r = _route.lock ();
2341 _window = new PluginPinDialog (r);
2342 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2344 aw->set_session (_session);
2346 _window->show_all ();
2352 RoutePinWindowProxy::route_going_away ()
2356 WM::Manager::instance().remove (this);
2357 going_away_connection.disconnect();
2361 RouteUI::maybe_add_route_print_mgr ()
2363 if (_route->pinmgr_proxy ()) {
2366 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2367 string_compose ("RPM-%1", _route->id()), _route);
2368 wp->set_session (_session);
2370 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2372 wp->set_state (*ui_xml, 0);
2376 void* existing_ui = _route->pinmgr_proxy ();
2378 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2381 _route->set_pingmgr_proxy (wp);
2383 WM::Manager::instance().register_window (wp);
2387 RouteUI::manage_pins ()
2389 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();