2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <boost/algorithm/string.hpp>
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
35 #include "ardour/dB.h"
36 #include "ardour/route_group.h"
37 #include "ardour/vca.h"
38 #include "ardour/vca_manager.h"
40 #include "ardour_ui.h"
43 #include "ardour_button.h"
46 #include "plugin_pin_dialog.h"
48 #include "gui_thread.h"
49 #include "ardour_dialog.h"
50 #include "latency_gui.h"
51 #include "mixer_strip.h"
52 #include "automation_time_axis.h"
53 #include "route_time_axis.h"
54 #include "group_tabs.h"
56 #include "ui_config.h"
58 #include "ardour/audio_track.h"
59 #include "ardour/audioengine.h"
60 #include "ardour/filename_extensions.h"
61 #include "ardour/midi_track.h"
62 #include "ardour/internal_send.h"
63 #include "ardour/profile.h"
64 #include "ardour/send.h"
65 #include "ardour/route.h"
66 #include "ardour/session.h"
67 #include "ardour/template_utils.h"
71 using namespace Gtkmm2ext;
72 using namespace ARDOUR;
73 using namespace ARDOUR_UI_UTILS;
77 uint32_t RouteUI::_max_invert_buttons = 3;
78 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
79 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
80 std::string RouteUI::program_port_prefix;
82 RouteUI::RouteUI (ARDOUR::Session* sess)
94 if (program_port_prefix.empty()) {
95 // compare to gtk2_ardour/port_group.cc
96 string lpn (PROGRAM_NAME);
97 boost::to_lower (lpn);
98 program_port_prefix = lpn + ":"; // e.g. "ardour:"
106 gui_object_state().remove_node (route_state_id());
109 _route.reset (); /* drop reference to route, so that it can be cleaned up */
110 route_connections.drop_connections ();
116 delete comment_window;
117 delete input_selector;
118 delete output_selector;
121 send_blink_connection.disconnect ();
122 rec_blink_connection.disconnect ();
128 self_destruct = true;
134 pre_fader_mute_check = 0;
135 post_fader_mute_check = 0;
136 listen_mute_check = 0;
139 solo_isolated_check = 0;
140 solo_isolated_led = 0;
144 denormal_menu_item = 0;
147 multiple_mute_change = false;
148 multiple_solo_change = false;
149 _i_am_the_modifier = 0;
155 setup_invert_buttons ();
157 mute_button = manage (new ArdourButton);
158 mute_button->set_name ("mute button");
159 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
161 solo_button = manage (new ArdourButton);
162 solo_button->set_name ("solo button");
163 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
164 solo_button->set_no_show_all (true);
166 rec_enable_button = manage (new ArdourButton);
167 rec_enable_button->set_name ("record enable button");
168 rec_enable_button->set_icon (ArdourIcon::RecButton);
169 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
171 if (UIConfiguration::instance().get_blink_rec_arm()) {
172 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
175 show_sends_button = manage (new ArdourButton);
176 show_sends_button->set_name ("send alert button");
177 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
179 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
180 monitor_input_button->set_name ("monitor button");
181 monitor_input_button->set_text (_("In"));
182 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
183 monitor_input_button->set_no_show_all (true);
185 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
186 monitor_disk_button->set_name ("monitor button");
187 monitor_disk_button->set_text (_("Disk"));
188 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
189 monitor_disk_button->set_no_show_all (true);
191 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
192 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
193 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
195 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
196 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
198 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
199 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
201 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
202 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
204 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
205 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
206 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
207 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
209 monitor_input_button->set_distinct_led_click (false);
210 monitor_disk_button->set_distinct_led_click (false);
212 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
213 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
215 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
216 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
218 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
224 route_connections.drop_connections ();
232 denormal_menu_item = 0;
236 RouteUI::self_delete ()
242 RouteUI::set_route (boost::shared_ptr<Route> rp)
248 if (set_color_from_route()) {
249 set_color (unique_random_color());
253 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
256 delete input_selector;
259 delete output_selector;
262 mute_button->set_controllable (_route->mute_control());
263 solo_button->set_controllable (_route->solo_control());
265 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
266 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
268 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
270 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
271 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
272 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
273 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
275 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
276 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
277 track_mode_changed();
280 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
281 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
283 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
284 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
286 if (_session->writable() && is_track()) {
287 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
289 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
290 t->RecordSafeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
292 rec_enable_button->show();
293 rec_enable_button->set_controllable (t->rec_enable_control());
295 if (is_midi_track()) {
296 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
297 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
302 /* this will work for busses and tracks, and needs to be called to
303 set up the name entry/name label display.
307 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
308 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
310 update_monitoring_display ();
313 mute_button->unset_flags (Gtk::CAN_FOCUS);
314 solo_button->unset_flags (Gtk::CAN_FOCUS);
318 if (_route->is_monitor() || _route->is_master()) {
319 solo_button->hide ();
326 setup_invert_buttons ();
327 set_invert_button_state ();
329 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
330 bus_send_display_changed (s);
332 update_mute_display ();
333 update_solo_display ();
335 if (!UIConfiguration::instance().get_blink_rec_arm()) {
336 blink_rec_display(true); // set initial rec-en button state
339 check_rec_enable_sensitivity ();
340 maybe_add_route_print_mgr ();
341 route_color_changed();
345 RouteUI::polarity_changed ()
351 set_invert_button_state ();
355 RouteUI::mute_press (GdkEventButton* ev)
357 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
361 //if this is a binding action, let the ArdourButton handle it
362 if ( BindingProxy::is_bind_action(ev) )
365 multiple_mute_change = false;
367 if (Keyboard::is_context_menu_event (ev)) {
373 mute_menu->popup(0,ev->time);
379 if (Keyboard::is_button2_event (ev)) {
380 // button2-click is "momentary"
382 _mute_release = new SoloMuteRelease (_route->muted ());
385 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
387 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
389 /* toggle mute on everything (but
390 * exclude the master and monitor)
392 * because we are going to erase
393 * elements of the list we need to work
397 boost::shared_ptr<RouteList> copy (new RouteList);
399 *copy = *_session->get_routes ();
401 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
402 if ((*i)->is_master() || (*i)->is_monitor()) {
410 _mute_release->routes = copy;
414 _session->set_mute (copy, !_route->muted());
416 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
418 /* Primary-button1 inverts the implication of
419 the group being active. If the group is
420 active (for mute), then this modifier means
421 "do not apply to mute". If the group is
422 inactive (for mute), then this modifier
423 means "apply to route". This is all
424 accomplished by passing just the actual
425 route, along with the InverseGroup group
428 NOTE: Primary-button2 is MIDI learn.
431 boost::shared_ptr<RouteList> rl;
433 if (ev->button == 1) {
435 rl.reset (new RouteList);
436 rl->push_back (_route);
439 _mute_release->routes = rl;
443 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
448 /* plain click applies change to this route */
450 boost::shared_ptr<RouteList> rl (new RouteList);
451 rl->push_back (_route);
454 _mute_release->routes = rl;
457 _session->set_mute (rl, !_route->muted());
467 RouteUI::mute_release (GdkEventButton* /*ev*/)
471 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
472 delete _mute_release;
480 RouteUI::edit_output_configuration ()
482 if (output_selector == 0) {
484 boost::shared_ptr<Send> send;
485 boost::shared_ptr<IO> output;
487 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
488 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
489 output = send->output();
491 output = _route->output ();
494 output = _route->output ();
497 output_selector = new IOSelectorWindow (_session, output);
500 if (output_selector->is_visible()) {
501 output_selector->get_toplevel()->get_window()->raise();
503 output_selector->present ();
506 //output_selector->set_keep_above (true);
510 RouteUI::edit_input_configuration ()
512 if (input_selector == 0) {
513 input_selector = new IOSelectorWindow (_session, _route->input());
516 if (input_selector->is_visible()) {
517 input_selector->get_toplevel()->get_window()->raise();
519 input_selector->present ();
522 //input_selector->set_keep_above (true);
526 RouteUI::solo_press(GdkEventButton* ev)
528 /* ignore double/triple clicks */
530 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
534 //if this is a binding action, let the ArdourButton handle it
535 if ( BindingProxy::is_bind_action(ev) )
538 multiple_solo_change = false;
540 if (Keyboard::is_context_menu_event (ev)) {
542 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
543 ! (solo_safe_led && solo_safe_led->is_visible())) {
545 if (solo_menu == 0) {
549 solo_menu->popup (1, ev->time);
554 if (Keyboard::is_button2_event (ev)) {
556 // button2-click is "momentary"
557 _solo_release = new SoloMuteRelease (_route->self_soloed());
560 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
562 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
564 /* Primary-Tertiary-click applies change to all routes */
567 _solo_release->routes = _session->get_routes ();
571 if (Config->get_solo_control_is_listen_control()) {
572 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::UseGroup);
574 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, 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 _session->set_just_one_solo (_route, true);
602 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
604 // shift-click: toggle solo isolated status
606 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
607 delete _solo_release;
610 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
612 /* Primary-button1: solo mix group.
613 NOTE: Primary-button2 is MIDI learn.
616 /* Primary-button1 applies change to the mix group even if it is not active
617 NOTE: Primary-button2 is MIDI learn.
620 boost::shared_ptr<RouteList> rl;
622 if (ev->button == 1) {
624 /* Primary-button1 inverts the implication of
625 the group being active. If the group is
626 active (for solo), then this modifier means
627 "do not apply to solo". If the group is
628 inactive (for mute), then this modifier
629 means "apply to route". This is all
630 accomplished by passing just the actual
631 route, along with the InverseGroup group
634 NOTE: Primary-button2 is MIDI learn.
637 rl.reset (new RouteList);
638 rl->push_back (_route);
641 _solo_release->routes = rl;
646 if (Config->get_solo_control_is_listen_control()) {
647 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
649 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
653 delete _solo_release;
658 /* click: solo this route */
660 boost::shared_ptr<RouteList> rl (new RouteList);
661 rl->push_back (route());
664 _solo_release->routes = rl;
668 if (Config->get_solo_control_is_listen_control()) {
669 _session->set_listen (rl, !_route->listening_via_monitor());
671 _session->set_solo (rl, !_route->self_soloed());
681 RouteUI::solo_release (GdkEventButton* /*ev*/)
685 if (_solo_release->exclusive) {
689 if (Config->get_solo_control_is_listen_control()) {
690 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
692 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
696 delete _solo_release;
704 RouteUI::rec_enable_press(GdkEventButton* ev)
706 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
710 //if this is a binding action, let the ArdourButton handle it
711 if ( BindingProxy::is_bind_action(ev) )
714 if (!_session->engine().connected()) {
715 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
720 if (is_midi_track()) {
722 /* rec-enable button exits from step editing */
724 if (midi_track()->step_editing()) {
725 midi_track()->set_step_editing (false);
730 if (is_track() && rec_enable_button) {
732 if (Keyboard::is_button2_event (ev)) {
734 //rec arm does not have a momentary mode
737 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
740 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
742 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
744 /* Primary-button1 applies change to the route group (even if it is not active)
745 NOTE: Primary-button2 is MIDI learn.
748 if (ev->button == 1) {
750 boost::shared_ptr<RouteList> rl;
752 rl.reset (new RouteList);
753 rl->push_back (_route);
756 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
759 } else if (Keyboard::is_context_menu_event (ev)) {
761 /* do this on release */
765 boost::shared_ptr<RouteList> rl (new RouteList);
766 rl->push_back (route());
768 _session->set_record_enabled (rl, !_route->record_enabled());
776 RouteUI::monitoring_changed ()
778 update_monitoring_display ();
782 RouteUI::update_monitoring_display ()
788 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
794 MonitorState ms = t->monitoring_state();
796 if (t->monitoring_choice() & MonitorInput) {
797 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
799 if (ms & MonitoringInput) {
800 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
802 monitor_input_button->unset_active_state ();
806 if (t->monitoring_choice() & MonitorDisk) {
807 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
809 if (ms & MonitoringDisk) {
810 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
812 monitor_disk_button->unset_active_state ();
818 RouteUI::monitor_input_press(GdkEventButton*)
824 RouteUI::monitor_input_release(GdkEventButton* ev)
826 return monitor_release (ev, MonitorInput);
830 RouteUI::monitor_disk_press (GdkEventButton*)
836 RouteUI::monitor_disk_release (GdkEventButton* ev)
838 return monitor_release (ev, MonitorDisk);
842 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
844 if (ev->button != 1) {
848 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
855 boost::shared_ptr<RouteList> rl;
857 /* XXX for now, monitoring choices are orthogonal. cue monitoring
858 will follow in 3.X but requires mixing the input and playback (disk)
859 signal together, which requires yet more buffers.
862 if (t->monitoring_choice() & monitor_choice) {
863 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
865 /* this line will change when the options are non-orthogonal */
866 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
870 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
871 rl = _session->get_routes ();
873 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
874 if (_route->route_group() && _route->route_group()->is_monitoring()) {
875 rl = _route->route_group()->route_list();
877 rl.reset (new RouteList);
878 rl->push_back (route());
881 rl.reset (new RouteList);
882 rl->push_back (route());
886 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
892 RouteUI::build_record_menu ()
895 record_menu = new Menu;
896 record_menu->set_name ("ArdourContextMenu");
897 using namespace Menu_Helpers;
898 MenuList& items = record_menu->items();
900 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
901 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
903 if (is_midi_track()) {
904 items.push_back (SeparatorElem());
905 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
906 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
910 if (step_edit_item) {
911 step_edit_item->set_sensitive (!_route->record_enabled());
912 step_edit_item->set_active (midi_track()->step_editing());
915 rec_safe_item->set_sensitive (!_route->record_enabled());
916 rec_safe_item->set_active (_route->record_safe());
921 RouteUI::toggle_step_edit ()
923 if (!is_midi_track() || _route->record_enabled()) {
927 midi_track()->set_step_editing (step_edit_item->get_active());
931 RouteUI::toggle_rec_safe ()
933 if (_route->record_enabled()) {
937 boost::shared_ptr<RouteList> rl (new RouteList);
938 rl->push_back (_route);
939 _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
943 RouteUI::step_edit_changed (bool yn)
946 if (rec_enable_button) {
947 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
950 start_step_editing ();
952 if (step_edit_item) {
953 step_edit_item->set_active (true);
958 if (rec_enable_button) {
959 rec_enable_button->unset_active_state ();
962 stop_step_editing ();
964 if (step_edit_item) {
965 step_edit_item->set_active (false);
971 RouteUI::rec_enable_release (GdkEventButton* ev)
973 if (Keyboard::is_context_menu_event (ev)) {
974 build_record_menu ();
976 record_menu->popup (1, ev->time);
985 RouteUI::build_sends_menu ()
987 using namespace Menu_Helpers;
989 sends_menu = new Menu;
990 sends_menu->set_name ("ArdourContextMenu");
991 MenuList& items = sends_menu->items();
994 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
998 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1002 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1006 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1010 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1014 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1017 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1021 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1024 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1025 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1026 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1031 RouteUI::create_sends (Placement p, bool include_buses)
1033 _session->globally_add_internal_sends (_route, p, include_buses);
1037 RouteUI::create_selected_sends (Placement p, bool include_buses)
1039 boost::shared_ptr<RouteList> rlist (new RouteList);
1040 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1042 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1043 RouteTimeAxisView* rtv;
1045 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1046 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1047 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1048 rlist->push_back (rui->route());
1054 _session->add_internal_sends (_route, p, rlist);
1058 RouteUI::set_sends_gain_from_track ()
1060 _session->globally_set_send_gains_from_track (_route);
1064 RouteUI::set_sends_gain_to_zero ()
1066 _session->globally_set_send_gains_to_zero (_route);
1070 RouteUI::set_sends_gain_to_unity ()
1072 _session->globally_set_send_gains_to_unity (_route);
1076 RouteUI::show_sends_press(GdkEventButton* ev)
1078 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1082 if (!is_track() && show_sends_button) {
1084 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1086 // do nothing on midi sigc::bind event
1089 } else if (Keyboard::is_context_menu_event (ev)) {
1091 if (sends_menu == 0) {
1092 build_sends_menu ();
1095 sends_menu->popup (0, ev->time);
1099 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1102 set_showing_sends_to (boost::shared_ptr<Route> ());
1104 set_showing_sends_to (_route);
1113 RouteUI::show_sends_release (GdkEventButton*)
1119 RouteUI::send_blink (bool onoff)
1121 if (!show_sends_button) {
1126 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1128 show_sends_button->unset_active_state ();
1132 Gtkmm2ext::ActiveState
1133 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1135 if (r->is_master() || r->is_monitor()) {
1136 return Gtkmm2ext::Off;
1139 if (Config->get_solo_control_is_listen_control()) {
1141 if (r->listening_via_monitor()) {
1142 return Gtkmm2ext::ExplicitActive;
1144 return Gtkmm2ext::Off;
1150 if (!r->self_soloed()) {
1151 return Gtkmm2ext::ImplicitActive;
1153 return Gtkmm2ext::ExplicitActive;
1156 return Gtkmm2ext::Off;
1160 Gtkmm2ext::ActiveState
1161 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1163 if (r->is_master() || r->is_monitor()) {
1164 return Gtkmm2ext::Off;
1167 if (r->solo_isolated()) {
1168 return Gtkmm2ext::ExplicitActive;
1170 return Gtkmm2ext::Off;
1174 Gtkmm2ext::ActiveState
1175 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1177 if (r->is_master() || r->is_monitor()) {
1178 return Gtkmm2ext::Off;
1181 if (r->solo_safe()) {
1182 return Gtkmm2ext::ExplicitActive;
1184 return Gtkmm2ext::Off;
1189 RouteUI::update_solo_display ()
1191 bool yn = _route->solo_safe ();
1193 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1194 solo_safe_check->set_active (yn);
1197 yn = _route->solo_isolated ();
1199 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1200 solo_isolated_check->set_active (yn);
1203 set_button_names ();
1205 if (solo_isolated_led) {
1206 if (_route->solo_isolated()) {
1207 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1209 solo_isolated_led->unset_active_state ();
1213 if (solo_safe_led) {
1214 if (_route->solo_safe()) {
1215 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1217 solo_safe_led->unset_active_state ();
1221 solo_button->set_active_state (solo_active_state (_route));
1223 /* some changes to solo status can affect mute display, so catch up
1226 update_mute_display ();
1230 RouteUI::solo_changed_so_update_mute ()
1232 update_mute_display ();
1236 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1238 if (r->is_monitor()) {
1239 return ActiveState(0);
1243 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1247 return Gtkmm2ext::ExplicitActive;
1248 } else if (r->muted_by_others()) {
1249 return Gtkmm2ext::ImplicitActive;
1251 /* no mute at all */
1252 return Gtkmm2ext::Off;
1259 return Gtkmm2ext::ExplicitActive;
1261 /* no mute at all */
1262 return Gtkmm2ext::Off;
1266 return ActiveState(0);
1270 RouteUI::update_mute_display ()
1276 mute_button->set_active_state (mute_active_state (_session, _route));
1280 RouteUI::update_vca_display ()
1286 VCAList vcas (_session->vca_manager().vcas());
1289 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1290 if (_route->slaved_to (*v)) {
1291 if (!label.empty()) {
1294 label += PBD::to_string ((*v)->number(), std::dec);
1298 if (label.empty()) {
1300 vca_button->set_active_state (Gtkmm2ext::Off);
1302 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1305 vca_button->set_text (label);
1309 RouteUI::route_rec_enable_changed ()
1311 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1312 update_monitoring_display ();
1316 RouteUI::session_rec_enable_changed ()
1318 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1319 update_monitoring_display ();
1323 RouteUI::blink_rec_display (bool blinkOn)
1325 if (!rec_enable_button || !_route) {
1328 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1332 if (_route->record_enabled()) {
1333 switch (_session->record_status ()) {
1334 case Session::Recording:
1335 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1338 case Session::Disabled:
1339 case Session::Enabled:
1340 if ( UIConfiguration::instance().get_blink_rec_arm() )
1341 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1343 rec_enable_button->set_active_state ( ImplicitActive );
1348 if (step_edit_item) {
1349 step_edit_item->set_sensitive (false);
1353 rec_enable_button->unset_active_state ();
1355 if (step_edit_item) {
1356 step_edit_item->set_sensitive (true);
1360 check_rec_enable_sensitivity ();
1364 RouteUI::build_solo_menu (void)
1366 using namespace Menu_Helpers;
1368 solo_menu = new Menu;
1369 solo_menu->set_name ("ArdourContextMenu");
1370 MenuList& items = solo_menu->items();
1371 Gtk::CheckMenuItem* check;
1373 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1374 check->set_active (_route->solo_isolated());
1375 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1376 items.push_back (CheckMenuElem(*check));
1377 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1380 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1381 check->set_active (_route->solo_safe());
1382 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1383 items.push_back (CheckMenuElem(*check));
1384 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1387 //items.push_back (SeparatorElem());
1388 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1393 RouteUI::build_mute_menu(void)
1395 using namespace Menu_Helpers;
1397 mute_menu = new Menu;
1398 mute_menu->set_name ("ArdourContextMenu");
1400 MenuList& items = mute_menu->items();
1402 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1403 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1404 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1405 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1406 pre_fader_mute_check->show_all();
1408 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1409 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1410 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1411 items.push_back (CheckMenuElem(*post_fader_mute_check));
1412 post_fader_mute_check->show_all();
1414 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1415 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1416 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1417 items.push_back (CheckMenuElem(*listen_mute_check));
1418 listen_mute_check->show_all();
1420 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1421 init_mute_menu(MuteMaster::Main, main_mute_check);
1422 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1423 items.push_back (CheckMenuElem(*main_mute_check));
1424 main_mute_check->show_all();
1426 //items.push_back (SeparatorElem());
1427 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1429 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1433 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1435 check->set_active (_route->mute_points() & mp);
1439 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1441 if (check->get_active()) {
1442 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1444 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1449 RouteUI::muting_change ()
1451 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1454 MuteMaster::MutePoint current = _route->mute_points ();
1456 yn = (current & MuteMaster::PreFader);
1458 if (pre_fader_mute_check->get_active() != yn) {
1459 pre_fader_mute_check->set_active (yn);
1462 yn = (current & MuteMaster::PostFader);
1464 if (post_fader_mute_check->get_active() != yn) {
1465 post_fader_mute_check->set_active (yn);
1468 yn = (current & MuteMaster::Listen);
1470 if (listen_mute_check->get_active() != yn) {
1471 listen_mute_check->set_active (yn);
1474 yn = (current & MuteMaster::Main);
1476 if (main_mute_check->get_active() != yn) {
1477 main_mute_check->set_active (yn);
1482 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1484 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1488 bool view = solo_isolated_led->active_state();
1489 bool model = _route->solo_isolated();
1491 /* called BEFORE the view has changed */
1493 if (ev->button == 1) {
1494 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1497 /* disable isolate for all routes */
1498 DisplaySuspender ds;
1499 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1501 /* enable isolate for all routes */
1502 DisplaySuspender ds;
1503 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1508 if (model == view) {
1510 /* flip just this route */
1512 boost::shared_ptr<RouteList> rl (new RouteList);
1513 rl->push_back (_route);
1514 DisplaySuspender ds;
1515 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1524 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1526 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1530 bool view = solo_safe_led->active_state();
1531 bool model = _route->solo_safe();
1533 if (ev->button == 1) {
1534 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1535 boost::shared_ptr<RouteList> rl (_session->get_routes());
1537 /* disable solo safe for all routes */
1538 DisplaySuspender ds;
1539 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1540 (*i)->set_solo_safe (false, Controllable::NoGroup);
1543 /* enable solo safe for all routes */
1544 DisplaySuspender ds;
1545 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1546 (*i)->set_solo_safe (true, Controllable::NoGroup);
1551 if (model == view) {
1552 /* flip just this route */
1553 _route->set_solo_safe (!view, Controllable::NoGroup);
1562 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1564 bool view = check->get_active();
1565 bool model = _route->solo_isolated();
1567 /* called AFTER the view has changed */
1569 if (model != view) {
1570 _route->set_solo_isolated (view, Controllable::UseGroup);
1575 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1577 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1580 /** Ask the user to choose a colour, and then apply that color to my route
1583 RouteUI::choose_color ()
1586 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1593 /** Set the route's own color. This may not be used for display if
1594 * the route is in a group which shares its color with its routes.
1597 RouteUI::set_color (const Gdk::Color & c)
1599 /* leave _color alone in the group case so that tracks can retain their
1600 * own pre-group colors.
1605 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1607 /* note: we use the route state ID here so that color is the same for both
1608 the time axis view and the mixer strip
1611 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1612 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1615 /** @return GUI state ID for things that are common to the route in all its representations */
1617 RouteUI::route_state_id () const
1619 return string_compose (X_("route %1"), _route->id().to_s());
1623 RouteUI::set_color_from_route ()
1625 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1633 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1636 _color.set_green (g);
1637 _color.set_blue (b);
1642 /** @return true if this name should be used for the route, otherwise false */
1644 RouteUI::verify_new_route_name (const std::string& name)
1646 if (name.find (':') == string::npos) {
1650 MessageDialog colon_msg (
1651 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1652 false, MESSAGE_QUESTION, BUTTONS_NONE
1655 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1656 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1658 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1662 RouteUI::route_rename ()
1664 ArdourPrompter name_prompter (true);
1669 name_prompter.set_title (_("Rename Track"));
1671 name_prompter.set_title (_("Rename Bus"));
1673 name_prompter.set_prompt (_("New name:"));
1674 name_prompter.set_initial_text (_route->name());
1675 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1676 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1677 name_prompter.show_all ();
1680 switch (name_prompter.run ()) {
1681 case Gtk::RESPONSE_ACCEPT:
1682 name_prompter.get_result (result);
1683 name_prompter.hide ();
1684 if (result.length()) {
1685 if (verify_new_route_name (result)) {
1686 _route->set_name (result);
1689 /* back to name prompter */
1693 /* nothing entered, just get out of here */
1708 RouteUI::property_changed (const PropertyChange& what_changed)
1710 if (what_changed.contains (ARDOUR::Properties::name)) {
1711 name_label.set_text (_route->name());
1716 RouteUI::toggle_comment_editor ()
1718 // if (ignore_toggle) {
1722 if (comment_window && comment_window->is_visible ()) {
1723 comment_window->hide ();
1725 open_comment_editor ();
1731 RouteUI::open_comment_editor ()
1733 if (comment_window == 0) {
1734 setup_comment_editor ();
1738 title = _route->name();
1739 title += _(": comment editor");
1741 comment_window->set_title (title);
1742 comment_window->present();
1746 RouteUI::setup_comment_editor ()
1748 comment_window = new ArdourWindow (""); // title will be reset to show route
1749 comment_window->set_skip_taskbar_hint (true);
1750 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1751 comment_window->set_default_size (400, 200);
1753 comment_area = manage (new TextView());
1754 comment_area->set_name ("MixerTrackCommentArea");
1755 comment_area->set_wrap_mode (WRAP_WORD);
1756 comment_area->set_editable (true);
1757 comment_area->get_buffer()->set_text (_route->comment());
1758 comment_area->show ();
1760 comment_window->add (*comment_area);
1764 RouteUI::comment_changed ()
1766 ignore_comment_edit = true;
1768 comment_area->get_buffer()->set_text (_route->comment());
1770 ignore_comment_edit = false;
1774 RouteUI::comment_editor_done_editing ()
1776 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1778 string const str = comment_area->get_buffer()->get_text();
1779 if (str == _route->comment ()) {
1783 _route->set_comment (str, this);
1787 RouteUI::set_route_active (bool a, bool apply_to_selection)
1789 if (apply_to_selection) {
1790 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1792 _route->set_active (a, this);
1797 RouteUI::duplicate_selected_routes ()
1799 ARDOUR_UI::instance()->start_duplicate_routes();
1803 RouteUI::toggle_denormal_protection ()
1805 if (denormal_menu_item) {
1809 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1811 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1812 _route->set_denormal_protection (x);
1818 RouteUI::denormal_protection_changed ()
1820 if (denormal_menu_item) {
1821 denormal_menu_item->set_active (_route->denormal_protection());
1826 RouteUI::disconnect_input ()
1828 _route->input()->disconnect (this);
1832 RouteUI::disconnect_output ()
1834 _route->output()->disconnect (this);
1838 RouteUI::is_track () const
1840 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1843 boost::shared_ptr<Track>
1844 RouteUI::track() const
1846 return boost::dynamic_pointer_cast<Track>(_route);
1850 RouteUI::is_audio_track () const
1852 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1855 boost::shared_ptr<AudioTrack>
1856 RouteUI::audio_track() const
1858 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1862 RouteUI::is_midi_track () const
1864 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1867 boost::shared_ptr<MidiTrack>
1868 RouteUI::midi_track() const
1870 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1874 RouteUI::has_audio_outputs () const
1876 return (_route->n_outputs().n_audio() > 0);
1880 RouteUI::name() const
1882 return _route->name();
1886 RouteUI::map_frozen ()
1888 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1890 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1893 check_rec_enable_sensitivity ();
1898 RouteUI::adjust_latency ()
1900 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1904 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1907 std::string safe_name;
1910 prompter.get_result (name, true);
1912 safe_name = legalize_for_path (name);
1913 safe_name += template_suffix;
1915 path = Glib::build_filename (dir, safe_name);
1917 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1918 bool overwrite = overwrite_file_dialog (prompter,
1919 _("Confirm Template Overwrite"),
1920 _("A template already exists with that name. Do you want to overwrite it?"));
1927 _route->save_as_template (path, name);
1933 RouteUI::save_as_template ()
1937 dir = ARDOUR::user_route_template_directory ();
1939 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1940 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1944 ArdourPrompter prompter (true); // modal
1946 prompter.set_title (_("Save As Template"));
1947 prompter.set_prompt (_("Template name:"));
1948 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1950 bool finished = false;
1952 switch (prompter.run()) {
1953 case RESPONSE_ACCEPT:
1954 finished = process_save_template_prompter (prompter, dir);
1964 RouteUI::check_rec_enable_sensitivity ()
1966 if (!rec_enable_button) {
1967 assert (0); // This should not happen
1970 if (!_session->writable()) {
1971 rec_enable_button->set_sensitive (false);
1975 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1976 rec_enable_button->set_sensitive (false);
1977 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1978 rec_enable_button->set_sensitive (false);
1980 rec_enable_button->set_sensitive (true);
1982 if (_route && _route->record_safe ()) {
1983 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1985 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1987 update_monitoring_display ();
1991 RouteUI::parameter_changed (string const & p)
1993 /* this handles RC and per-session parameter changes */
1995 if (p == "disable-disarm-during-roll") {
1996 check_rec_enable_sensitivity ();
1997 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1998 set_button_names ();
1999 } else if (p == "auto-input") {
2000 update_monitoring_display ();
2001 } else if (p == "blink-rec-arm") {
2002 if (UIConfiguration::instance().get_blink_rec_arm()) {
2003 rec_blink_connection.disconnect ();
2004 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2006 rec_blink_connection.disconnect ();
2007 RouteUI::blink_rec_display(false);
2013 RouteUI::step_gain_up ()
2015 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2019 RouteUI::page_gain_up ()
2021 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2025 RouteUI::step_gain_down ()
2027 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2031 RouteUI::page_gain_down ()
2033 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2037 RouteUI::open_remote_control_id_dialog ()
2039 ArdourDialog dialog (_("Remote Control ID"));
2040 SpinButton* spin = 0;
2042 dialog.get_vbox()->set_border_width (18);
2044 if (Config->get_remote_model() == UserOrdered) {
2045 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2047 HBox* hbox = manage (new HBox);
2048 hbox->set_spacing (6);
2049 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2050 spin = manage (new SpinButton);
2051 spin->set_digits (0);
2052 spin->set_increments (1, 10);
2053 spin->set_range (0, limit);
2054 spin->set_value (_route->remote_control_id());
2055 hbox->pack_start (*spin);
2056 dialog.get_vbox()->pack_start (*hbox);
2058 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2059 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2061 Label* l = manage (new Label());
2062 if (_route->is_master() || _route->is_monitor()) {
2063 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2064 "The remote control ID of %3 cannot be changed."),
2065 Gtkmm2ext::markup_escape_text (_route->name()),
2066 _route->remote_control_id(),
2067 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2069 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2070 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2071 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2072 (is_track() ? _("track") : _("bus")),
2073 _route->remote_control_id(),
2074 "<span size=\"small\" style=\"italic\">",
2076 Gtkmm2ext::markup_escape_text (_route->name()),
2079 dialog.get_vbox()->pack_start (*l);
2080 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2084 int const r = dialog.run ();
2086 if (r == RESPONSE_ACCEPT && spin) {
2087 _route->set_remote_control_id (spin->get_value_as_int ());
2092 RouteUI::setup_invert_buttons ()
2094 /* remove old invert buttons */
2095 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2096 _invert_button_box.remove (**i);
2099 _invert_buttons.clear ();
2101 if (!_route || !_route->input()) {
2105 uint32_t const N = _route->input()->n_ports().n_audio ();
2107 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2109 for (uint32_t i = 0; i < to_add; ++i) {
2110 ArdourButton* b = manage (new ArdourButton);
2111 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2112 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2114 b->set_name (X_("invert button"));
2117 b->set_text (string_compose (X_("Ø (%1)"), N));
2119 b->set_text (X_("Ø"));
2122 b->set_text (string_compose (X_("Ø%1"), i + 1));
2125 if (N <= _max_invert_buttons) {
2126 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));
2128 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2131 _invert_buttons.push_back (b);
2132 _invert_button_box.pack_start (*b);
2135 _invert_button_box.set_spacing (1);
2136 _invert_button_box.show_all ();
2140 RouteUI::set_invert_button_state ()
2142 uint32_t const N = _route->input()->n_ports().n_audio();
2143 if (N > _max_invert_buttons) {
2145 /* One button for many channels; explicit active if all channels are inverted,
2146 implicit active if some are, off if none are.
2149 ArdourButton* b = _invert_buttons.front ();
2151 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2152 b->set_active_state (Gtkmm2ext::ExplicitActive);
2153 } else if (_route->phase_invert().any()) {
2154 b->set_active_state (Gtkmm2ext::ImplicitActive);
2156 b->set_active_state (Gtkmm2ext::Off);
2161 /* One button per channel; just set active */
2164 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2165 (*i)->set_active (_route->phase_invert (j));
2172 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2174 if (ev->button == 1 && i < _invert_buttons.size()) {
2175 uint32_t const N = _route->input()->n_ports().n_audio ();
2176 if (N <= _max_invert_buttons) {
2177 /* left-click inverts phase so long as we have a button per channel */
2178 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2187 RouteUI::invert_press (GdkEventButton* ev)
2189 using namespace Menu_Helpers;
2191 uint32_t const N = _route->input()->n_ports().n_audio();
2192 if (N <= _max_invert_buttons && ev->button != 3) {
2193 /* If we have an invert button per channel, we only pop
2194 up a menu on right-click; left click is handled
2200 delete _invert_menu;
2201 _invert_menu = new Menu;
2202 _invert_menu->set_name ("ArdourContextMenu");
2203 MenuList& items = _invert_menu->items ();
2205 for (uint32_t i = 0; i < N; ++i) {
2206 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2207 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2208 ++_i_am_the_modifier;
2209 e->set_active (_route->phase_invert (i));
2210 --_i_am_the_modifier;
2213 _invert_menu->popup (0, ev->time);
2219 RouteUI::invert_menu_toggled (uint32_t c)
2221 if (_i_am_the_modifier) {
2225 _route->set_phase_invert (c, !_route->phase_invert (c));
2229 RouteUI::set_invert_sensitive (bool yn)
2231 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2232 (*b)->set_sensitive (yn);
2237 RouteUI::request_redraw ()
2240 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2244 /** The Route's gui_changed signal has been emitted */
2246 RouteUI::route_gui_changed (string what_changed)
2248 if (what_changed == "color") {
2249 if (set_color_from_route () == 0) {
2250 route_color_changed ();
2256 RouteUI::track_mode_changed (void)
2259 switch (track()->mode()) {
2260 case ARDOUR::NonLayered:
2261 case ARDOUR::Normal:
2262 rec_enable_button->set_icon (ArdourIcon::RecButton);
2264 case ARDOUR::Destructive:
2265 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2268 rec_enable_button->queue_draw();
2271 /** @return the color that this route should use; it maybe its own,
2272 or it maybe that of its route group.
2275 RouteUI::color () const
2277 RouteGroup* g = _route->route_group ();
2279 if (g && g->is_color()) {
2281 set_color_from_rgba (c, GroupTabs::group_color (g));
2289 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2291 _showing_sends_to = send_to;
2292 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2296 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2298 if (_route == send_to) {
2299 show_sends_button->set_active (true);
2300 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2302 show_sends_button->set_active (false);
2303 send_blink_connection.disconnect ();
2308 RouteUI::route_group() const
2310 return _route->route_group();
2314 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2315 : WM::ProxyBase (name, string())
2316 , _route (boost::weak_ptr<Route> (route))
2318 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2321 RoutePinWindowProxy::~RoutePinWindowProxy()
2326 ARDOUR::SessionHandlePtr*
2327 RoutePinWindowProxy::session_handle ()
2329 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2330 if (aw) { return aw; }
2335 RoutePinWindowProxy::get (bool create)
2337 boost::shared_ptr<Route> r = _route.lock ();
2346 _window = new PluginPinDialog (r);
2347 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2349 aw->set_session (_session);
2351 _window->show_all ();
2357 RoutePinWindowProxy::route_going_away ()
2361 WM::Manager::instance().remove (this);
2362 going_away_connection.disconnect();
2366 RouteUI::maybe_add_route_print_mgr ()
2368 if (_route->pinmgr_proxy ()) {
2371 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2372 string_compose ("RPM-%1", _route->id()), _route);
2373 wp->set_session (_session);
2375 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2377 wp->set_state (*ui_xml, 0);
2381 void* existing_ui = _route->pinmgr_proxy ();
2383 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2386 _route->set_pingmgr_proxy (wp);
2388 WM::Manager::instance().register_window (wp);
2392 RouteUI::manage_pins ()
2394 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();