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_button.h"
54 #include "ardour_dialog.h"
55 #include "ardour_ui.h"
56 #include "automation_time_axis.h"
58 #include "group_tabs.h"
59 #include "gui_object.h"
60 #include "gui_thread.h"
62 #include "latency_gui.h"
63 #include "mixer_strip.h"
64 #include "plugin_pin_dialog.h"
66 #include "rgb_macros.h"
67 #include "route_time_axis.h"
70 #include "ui_config.h"
76 using namespace Gtkmm2ext;
77 using namespace ARDOUR;
78 using namespace ARDOUR_UI_UTILS;
82 uint32_t RouteUI::_max_invert_buttons = 3;
83 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
84 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
85 std::string RouteUI::program_port_prefix;
87 RouteUI::RouteUI (ARDOUR::Session* sess)
98 if (program_port_prefix.empty()) {
99 // compare to gtk2_ardour/port_group.cc
100 string lpn (PROGRAM_NAME);
101 boost::to_lower (lpn);
102 program_port_prefix = lpn + ":"; // e.g. "ardour:"
113 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
116 _route.reset (); /* drop reference to route, so that it can be cleaned up */
117 route_connections.drop_connections ();
123 delete comment_window;
124 delete input_selector;
125 delete output_selector;
128 send_blink_connection.disconnect ();
129 rec_blink_connection.disconnect ();
135 self_destruct = true;
141 pre_fader_mute_check = 0;
142 post_fader_mute_check = 0;
143 listen_mute_check = 0;
146 solo_isolated_check = 0;
147 solo_isolated_led = 0;
151 denormal_menu_item = 0;
154 multiple_mute_change = false;
155 multiple_solo_change = false;
156 _i_am_the_modifier = 0;
161 setup_invert_buttons ();
163 mute_button = manage (new ArdourButton);
164 mute_button->set_name ("mute button");
165 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
167 solo_button = manage (new ArdourButton);
168 solo_button->set_name ("solo button");
169 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
170 solo_button->set_no_show_all (true);
172 rec_enable_button = manage (new ArdourButton);
173 rec_enable_button->set_name ("record enable button");
174 rec_enable_button->set_icon (ArdourIcon::RecButton);
175 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
177 if (UIConfiguration::instance().get_blink_rec_arm()) {
178 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
181 show_sends_button = manage (new ArdourButton);
182 show_sends_button->set_name ("send alert button");
183 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
185 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
186 monitor_input_button->set_name ("monitor button");
187 monitor_input_button->set_text (_("In"));
188 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
189 monitor_input_button->set_no_show_all (true);
191 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
192 monitor_disk_button->set_name ("monitor button");
193 monitor_disk_button->set_text (_("Disk"));
194 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
195 monitor_disk_button->set_no_show_all (true);
197 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
198 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
199 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
201 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
202 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
204 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
205 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
207 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
208 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
210 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
211 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
212 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
213 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
215 monitor_input_button->set_distinct_led_click (false);
216 monitor_disk_button->set_distinct_led_click (false);
218 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
219 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
221 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
222 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
224 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
230 route_connections.drop_connections ();
238 denormal_menu_item = 0;
242 RouteUI::self_delete ()
248 RouteUI::set_route (boost::shared_ptr<Route> rp)
254 if (set_color_from_route()) {
255 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
259 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
262 delete input_selector;
265 delete output_selector;
268 mute_button->set_controllable (_route->mute_control());
269 solo_button->set_controllable (_route->solo_control());
271 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
273 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
275 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
276 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
277 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
278 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
279 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
282 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
283 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
284 track_mode_changed();
288 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
289 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
291 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
293 if (_session->writable() && is_track()) {
294 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
296 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
297 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
299 rec_enable_button->show();
300 rec_enable_button->set_controllable (t->rec_enable_control());
302 if (is_midi_track()) {
303 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
304 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
309 /* this will work for busses and tracks, and needs to be called to
310 set up the name entry/name label display.
314 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
315 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
317 update_monitoring_display ();
320 mute_button->unset_flags (Gtk::CAN_FOCUS);
321 solo_button->unset_flags (Gtk::CAN_FOCUS);
325 if (_route->is_monitor() || _route->is_master()) {
326 solo_button->hide ();
333 setup_invert_buttons ();
334 set_invert_button_state ();
336 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
337 bus_send_display_changed (s);
339 update_mute_display ();
340 update_solo_display ();
342 if (!UIConfiguration::instance().get_blink_rec_arm()) {
343 blink_rec_display(true); // set initial rec-en button state
346 check_rec_enable_sensitivity ();
347 maybe_add_route_print_mgr ();
348 route_color_changed();
349 route_gui_changed (PropertyChange (Properties::selected));
353 RouteUI::polarity_changed ()
359 set_invert_button_state ();
363 RouteUI::mute_press (GdkEventButton* ev)
365 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
369 //if this is a binding action, let the ArdourButton handle it
370 if ( BindingProxy::is_bind_action(ev) )
373 multiple_mute_change = false;
375 if (Keyboard::is_context_menu_event (ev)) {
381 mute_menu->popup(0,ev->time);
387 if (Keyboard::is_button2_event (ev)) {
388 // button2-click is "momentary"
390 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
393 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
395 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
397 /* toggle mute on everything (but
398 * exclude the master and monitor)
400 * because we are going to erase
401 * elements of the list we need to work
405 boost::shared_ptr<RouteList> copy (new RouteList);
407 *copy = *_session->get_routes ();
409 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
410 if ((*i)->is_master() || (*i)->is_monitor()) {
418 _mute_release->routes = copy;
422 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
424 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
426 /* Primary-button1 inverts the implication of
427 the group being active. If the group is
428 active (for mute), then this modifier means
429 "do not apply to mute". If the group is
430 inactive (for mute), then this modifier
431 means "apply to route". This is all
432 accomplished by passing just the actual
433 route, along with the InverseGroup group
436 NOTE: Primary-button2 is MIDI learn.
439 boost::shared_ptr<RouteList> rl;
441 if (ev->button == 1) {
443 rl.reset (new RouteList);
444 rl->push_back (_route);
447 _mute_release->routes = rl;
451 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
456 /* plain click applies change to this route */
458 boost::shared_ptr<RouteList> rl (new RouteList);
459 rl->push_back (_route);
462 _mute_release->routes = rl;
465 _session->set_control (_route->mute_control(), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
475 RouteUI::mute_release (GdkEventButton* /*ev*/)
479 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
480 delete _mute_release;
488 RouteUI::edit_output_configuration ()
490 if (output_selector == 0) {
492 boost::shared_ptr<Send> send;
493 boost::shared_ptr<IO> output;
495 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
496 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
497 output = send->output();
499 output = _route->output ();
502 output = _route->output ();
505 output_selector = new IOSelectorWindow (_session, output);
508 if (output_selector->is_visible()) {
509 output_selector->get_toplevel()->get_window()->raise();
511 output_selector->present ();
514 //output_selector->set_keep_above (true);
518 RouteUI::edit_input_configuration ()
520 if (input_selector == 0) {
521 input_selector = new IOSelectorWindow (_session, _route->input());
524 if (input_selector->is_visible()) {
525 input_selector->get_toplevel()->get_window()->raise();
527 input_selector->present ();
530 //input_selector->set_keep_above (true);
534 RouteUI::solo_press(GdkEventButton* ev)
536 /* ignore double/triple clicks */
538 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
542 //if this is a binding action, let the ArdourButton handle it
543 if ( BindingProxy::is_bind_action(ev) )
546 multiple_solo_change = false;
548 if (Keyboard::is_context_menu_event (ev)) {
550 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
551 ! (solo_safe_led && solo_safe_led->is_visible())) {
553 if (solo_menu == 0) {
557 solo_menu->popup (1, ev->time);
562 if (Keyboard::is_button2_event (ev)) {
564 // button2-click is "momentary"
565 _solo_release = new SoloMuteRelease (_route->self_soloed());
568 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
570 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
572 /* Primary-Tertiary-click applies change to all routes */
575 _solo_release->routes = _session->get_routes ();
579 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
581 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
583 // Primary-Secondary-click: exclusively solo this track
586 _solo_release->exclusive = true;
588 boost::shared_ptr<RouteList> routes = _session->get_routes();
590 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
591 if ((*i)->soloed ()) {
592 _solo_release->routes_on->push_back (*i);
594 _solo_release->routes_off->push_back (*i);
599 if (Config->get_solo_control_is_listen_control()) {
600 /* ??? we need a just_one_listen() method */
603 boost::shared_ptr<ControlList> cl (new ControlList);
604 cl->push_back (_route->solo_control());
605 _session->set_controls (cl, 1.0, Controllable::NoGroup);
608 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
610 // shift-click: toggle solo isolated status
612 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
613 delete _solo_release;
616 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
618 /* Primary-button1: solo mix group.
619 NOTE: Primary-button2 is MIDI learn.
622 /* Primary-button1 applies change to the mix group even if it is not active
623 NOTE: Primary-button2 is MIDI learn.
626 boost::shared_ptr<RouteList> rl;
628 if (ev->button == 1) {
630 /* Primary-button1 inverts the implication of
631 the group being active. If the group is
632 active (for solo), then this modifier means
633 "do not apply to solo". If the group is
634 inactive (for mute), then this modifier
635 means "apply to route". This is all
636 accomplished by passing just the actual
637 route, along with the InverseGroup group
640 NOTE: Primary-button2 is MIDI learn.
643 rl.reset (new RouteList);
644 rl->push_back (_route);
647 _solo_release->routes = rl;
652 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
655 delete _solo_release;
660 /* click: solo this route */
662 boost::shared_ptr<RouteList> rl (new RouteList);
663 rl->push_back (route());
666 _solo_release->routes = rl;
670 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
679 RouteUI::solo_release (GdkEventButton* /*ev*/)
683 if (_solo_release->exclusive) {
687 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
690 delete _solo_release;
698 RouteUI::rec_enable_press(GdkEventButton* ev)
700 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
704 //if this is a binding action, let the ArdourButton handle it
705 if ( BindingProxy::is_bind_action(ev) )
708 if (!_session->engine().connected()) {
709 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
714 if (is_midi_track()) {
716 /* rec-enable button exits from step editing */
718 if (midi_track()->step_editing()) {
719 midi_track()->set_step_editing (false);
724 if (is_track() && rec_enable_button) {
726 if (Keyboard::is_button2_event (ev)) {
728 //rec arm does not have a momentary mode
731 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
734 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
736 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
738 /* Primary-button1 applies change to the route group (even if it is not active)
739 NOTE: Primary-button2 is MIDI learn.
742 if (ev->button == 1) {
744 boost::shared_ptr<RouteList> rl;
746 rl.reset (new RouteList);
747 rl->push_back (_route);
750 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
753 } else if (Keyboard::is_context_menu_event (ev)) {
755 /* do this on release */
759 boost::shared_ptr<Track> trk = track();
760 _session->set_control (trk->rec_enable_control(), !trk->rec_enable_control()->get_value(), Controllable::UseGroup);
768 RouteUI::update_monitoring_display ()
774 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
780 MonitorState ms = t->monitoring_state();
782 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
783 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
785 if (ms & MonitoringInput) {
786 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
788 monitor_input_button->unset_active_state ();
792 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
793 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
795 if (ms & MonitoringDisk) {
796 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
798 monitor_disk_button->unset_active_state ();
804 RouteUI::monitor_input_press(GdkEventButton*)
810 RouteUI::monitor_input_release(GdkEventButton* ev)
812 return monitor_release (ev, MonitorInput);
816 RouteUI::monitor_disk_press (GdkEventButton*)
822 RouteUI::monitor_disk_release (GdkEventButton* ev)
824 return monitor_release (ev, MonitorDisk);
828 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
830 if (ev->button != 1) {
834 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
841 boost::shared_ptr<RouteList> rl;
843 /* XXX for now, monitoring choices are orthogonal. cue monitoring
844 will follow in 3.X but requires mixing the input and playback (disk)
845 signal together, which requires yet more buffers.
848 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
849 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
851 /* this line will change when the options are non-orthogonal */
852 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
856 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
857 rl = _session->get_routes ();
859 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
860 if (_route->route_group() && _route->route_group()->is_monitoring()) {
861 rl = _route->route_group()->route_list();
863 rl.reset (new RouteList);
864 rl->push_back (route());
867 rl.reset (new RouteList);
868 rl->push_back (route());
872 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
878 RouteUI::build_record_menu ()
881 record_menu = new Menu;
882 record_menu->set_name ("ArdourContextMenu");
883 using namespace Menu_Helpers;
884 MenuList& items = record_menu->items();
886 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
887 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
889 if (is_midi_track()) {
890 items.push_back (SeparatorElem());
891 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
892 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
896 if (step_edit_item) {
897 if (track()->rec_enable_control()->get_value()) {
898 step_edit_item->set_sensitive (false);
900 step_edit_item->set_active (midi_track()->step_editing());
903 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
904 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
909 RouteUI::toggle_step_edit ()
911 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
915 midi_track()->set_step_editing (step_edit_item->get_active());
919 RouteUI::toggle_rec_safe ()
921 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
927 /* This check is made inside the control too, but dong it here can't
931 if (_route->rec_enable_control()->get_value()) {
935 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
939 RouteUI::step_edit_changed (bool yn)
942 if (rec_enable_button) {
943 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
946 start_step_editing ();
948 if (step_edit_item) {
949 step_edit_item->set_active (true);
954 if (rec_enable_button) {
955 rec_enable_button->unset_active_state ();
958 stop_step_editing ();
960 if (step_edit_item) {
961 step_edit_item->set_active (false);
967 RouteUI::rec_enable_release (GdkEventButton* ev)
969 if (Keyboard::is_context_menu_event (ev)) {
970 build_record_menu ();
972 record_menu->popup (1, ev->time);
981 RouteUI::build_sends_menu ()
983 using namespace Menu_Helpers;
985 sends_menu = new Menu;
986 sends_menu->set_name ("ArdourContextMenu");
987 MenuList& items = sends_menu->items();
990 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
994 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
998 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1002 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1006 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1010 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1013 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1017 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1020 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1021 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1022 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1027 RouteUI::create_sends (Placement p, bool include_buses)
1029 _session->globally_add_internal_sends (_route, p, include_buses);
1033 RouteUI::create_selected_sends (Placement p, bool include_buses)
1035 boost::shared_ptr<RouteList> rlist (new RouteList);
1036 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1038 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1039 RouteTimeAxisView* rtv;
1041 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1042 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1043 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1044 rlist->push_back (rui->route());
1050 _session->add_internal_sends (_route, p, rlist);
1054 RouteUI::set_sends_gain_from_track ()
1056 _session->globally_set_send_gains_from_track (_route);
1060 RouteUI::set_sends_gain_to_zero ()
1062 _session->globally_set_send_gains_to_zero (_route);
1066 RouteUI::set_sends_gain_to_unity ()
1068 _session->globally_set_send_gains_to_unity (_route);
1072 RouteUI::show_sends_press(GdkEventButton* ev)
1074 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1078 if (!is_track() && show_sends_button) {
1080 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1082 // do nothing on midi sigc::bind event
1085 } else if (Keyboard::is_context_menu_event (ev)) {
1087 if (sends_menu == 0) {
1088 build_sends_menu ();
1091 sends_menu->popup (0, ev->time);
1095 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1098 set_showing_sends_to (boost::shared_ptr<Route> ());
1100 set_showing_sends_to (_route);
1109 RouteUI::show_sends_release (GdkEventButton*)
1115 RouteUI::send_blink (bool onoff)
1117 if (!show_sends_button) {
1122 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1124 show_sends_button->unset_active_state ();
1128 Gtkmm2ext::ActiveState
1129 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1131 boost::shared_ptr<SoloControl> sc = s->solo_control();
1134 return Gtkmm2ext::Off;
1137 if (!sc->can_solo()) {
1138 return Gtkmm2ext::Off;
1142 if (sc->self_soloed()) {
1143 return Gtkmm2ext::ExplicitActive;
1144 } else if (sc->soloed_by_others()) {
1145 return Gtkmm2ext::ImplicitActive;
1147 return Gtkmm2ext::Off;
1151 Gtkmm2ext::ActiveState
1152 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1154 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1157 return Gtkmm2ext::Off;
1160 if (s->is_master() || s->is_monitor()) {
1161 return Gtkmm2ext::Off;
1164 if (sc->solo_isolated()) {
1165 return Gtkmm2ext::ExplicitActive;
1167 return Gtkmm2ext::Off;
1171 Gtkmm2ext::ActiveState
1172 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1174 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1177 return Gtkmm2ext::Off;
1180 if (s->is_master() || s->is_monitor()) {
1181 return Gtkmm2ext::Off;
1184 if (sc->solo_safe()) {
1185 return Gtkmm2ext::ExplicitActive;
1187 return Gtkmm2ext::Off;
1192 RouteUI::update_solo_display ()
1194 bool yn = _route->solo_safe_control()->solo_safe ();
1196 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1197 solo_safe_check->set_active (yn);
1200 yn = _route->solo_isolate_control()->solo_isolated ();
1202 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1203 solo_isolated_check->set_active (yn);
1206 set_button_names ();
1208 if (solo_isolated_led) {
1209 if (_route->solo_isolate_control()->solo_isolated()) {
1210 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1212 solo_isolated_led->unset_active_state ();
1216 if (solo_safe_led) {
1217 if (_route->solo_safe_control()->solo_safe()) {
1218 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1220 solo_safe_led->unset_active_state ();
1224 solo_button->set_active_state (solo_active_state (_route));
1226 /* some changes to solo status can affect mute display, so catch up
1229 update_mute_display ();
1233 RouteUI::solo_changed_so_update_mute ()
1235 update_mute_display ();
1239 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1241 boost::shared_ptr<MuteControl> mc = s->mute_control();
1243 if (s->is_monitor()) {
1244 return Gtkmm2ext::Off;
1248 return Gtkmm2ext::Off;
1251 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1253 if (mc->muted_by_self ()) {
1255 return Gtkmm2ext::ExplicitActive;
1256 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1257 /* this will reflect both solo mutes AND master mutes */
1258 return Gtkmm2ext::ImplicitActive;
1260 /* no mute at all */
1261 return Gtkmm2ext::Off;
1266 if (mc->muted_by_self()) {
1268 return Gtkmm2ext::ExplicitActive;
1269 } else if (mc->muted_by_masters ()) {
1270 /* this shows only master mutes, not mute-by-others-soloing */
1271 return Gtkmm2ext::ImplicitActive;
1273 /* no mute at all */
1274 return Gtkmm2ext::Off;
1278 return ActiveState(0);
1282 RouteUI::update_mute_display ()
1288 mute_button->set_active_state (mute_active_state (_session, _route));
1293 RouteUI::route_rec_enable_changed ()
1295 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1296 update_monitoring_display ();
1300 RouteUI::session_rec_enable_changed ()
1302 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1303 update_monitoring_display ();
1307 RouteUI::blink_rec_display (bool blinkOn)
1309 if (!rec_enable_button || !_route) {
1313 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1321 if (track()->rec_enable_control()->get_value()) {
1322 switch (_session->record_status ()) {
1323 case Session::Recording:
1324 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1327 case Session::Disabled:
1328 case Session::Enabled:
1329 if (UIConfiguration::instance().get_blink_rec_arm()) {
1330 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1332 rec_enable_button->set_active_state ( ImplicitActive );
1337 if (step_edit_item) {
1338 step_edit_item->set_sensitive (false);
1342 rec_enable_button->unset_active_state ();
1344 if (step_edit_item) {
1345 step_edit_item->set_sensitive (true);
1349 check_rec_enable_sensitivity ();
1353 RouteUI::build_solo_menu (void)
1355 using namespace Menu_Helpers;
1357 solo_menu = new Menu;
1358 solo_menu->set_name ("ArdourContextMenu");
1359 MenuList& items = solo_menu->items();
1360 Gtk::CheckMenuItem* check;
1362 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1363 check->set_active (_route->solo_isolate_control()->solo_isolated());
1364 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1365 items.push_back (CheckMenuElem(*check));
1366 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1369 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1370 check->set_active (_route->solo_safe_control()->solo_safe());
1371 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1372 items.push_back (CheckMenuElem(*check));
1373 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1376 //items.push_back (SeparatorElem());
1377 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1382 RouteUI::build_mute_menu(void)
1384 using namespace Menu_Helpers;
1386 mute_menu = new Menu;
1387 mute_menu->set_name ("ArdourContextMenu");
1389 MenuList& items = mute_menu->items();
1391 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1392 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1393 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1394 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1395 pre_fader_mute_check->show_all();
1397 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1398 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1399 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1400 items.push_back (CheckMenuElem(*post_fader_mute_check));
1401 post_fader_mute_check->show_all();
1403 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1404 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1405 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1406 items.push_back (CheckMenuElem(*listen_mute_check));
1407 listen_mute_check->show_all();
1409 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1410 init_mute_menu(MuteMaster::Main, main_mute_check);
1411 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1412 items.push_back (CheckMenuElem(*main_mute_check));
1413 main_mute_check->show_all();
1415 //items.push_back (SeparatorElem());
1416 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1418 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1422 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1424 check->set_active (_route->mute_control()->mute_points() & mp);
1428 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1430 if (check->get_active()) {
1431 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1433 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1438 RouteUI::muting_change ()
1440 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1443 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1445 yn = (current & MuteMaster::PreFader);
1447 if (pre_fader_mute_check->get_active() != yn) {
1448 pre_fader_mute_check->set_active (yn);
1451 yn = (current & MuteMaster::PostFader);
1453 if (post_fader_mute_check->get_active() != yn) {
1454 post_fader_mute_check->set_active (yn);
1457 yn = (current & MuteMaster::Listen);
1459 if (listen_mute_check->get_active() != yn) {
1460 listen_mute_check->set_active (yn);
1463 yn = (current & MuteMaster::Main);
1465 if (main_mute_check->get_active() != yn) {
1466 main_mute_check->set_active (yn);
1471 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1473 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1477 bool view = solo_isolated_led->active_state();
1478 bool model = _route->solo_isolate_control()->solo_isolated();
1480 /* called BEFORE the view has changed */
1482 if (ev->button == 1) {
1483 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1486 /* disable isolate for all routes */
1487 DisplaySuspender ds;
1488 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1490 /* enable isolate for all routes */
1491 DisplaySuspender ds;
1492 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1497 if (model == view) {
1499 /* flip just this route */
1501 boost::shared_ptr<RouteList> rl (new RouteList);
1502 rl->push_back (_route);
1503 DisplaySuspender ds;
1504 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1513 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1515 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1519 bool view = solo_safe_led->active_state();
1520 bool model = _route->solo_safe_control()->solo_safe();
1522 if (ev->button == 1) {
1523 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1524 boost::shared_ptr<RouteList> rl (_session->get_routes());
1526 /* disable solo safe for all routes */
1527 DisplaySuspender ds;
1528 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1529 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1532 /* enable solo safe for all routes */
1533 DisplaySuspender ds;
1534 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1535 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1540 if (model == view) {
1541 /* flip just this route */
1542 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1551 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1553 bool view = check->get_active();
1554 bool model = _route->solo_isolate_control()->solo_isolated();
1556 /* called AFTER the view has changed */
1558 if (model != view) {
1559 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1564 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1566 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1569 /** Ask the user to choose a colour, and then apply that color to my route
1572 RouteUI::choose_color ()
1575 Gdk::Color c (gdk_color_from_rgb (_route->presentation_info().color()));
1576 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1579 set_color (gdk_color_to_rgba (color));
1583 /** Set the route's own color. This may not be used for display if
1584 * the route is in a group which shares its color with its routes.
1587 RouteUI::set_color (uint32_t c)
1589 _route->presentation_info().set_color (c);
1592 /** @return GUI state ID for things that are common to the route in all its representations */
1594 RouteUI::route_state_id () const
1596 return string_compose (X_("route %1"), _route->id().to_s());
1600 RouteUI::set_color_from_route ()
1602 if (_route->presentation_info().color_set()) {
1603 return 0; /* nothing to do */
1606 return 1; /* pick a color */
1609 /** @return true if this name should be used for the route, otherwise false */
1611 RouteUI::verify_new_route_name (const std::string& name)
1613 if (name.find (':') == string::npos) {
1617 MessageDialog colon_msg (
1618 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1619 false, MESSAGE_QUESTION, BUTTONS_NONE
1622 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1623 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1625 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1629 RouteUI::route_rename ()
1631 ArdourPrompter name_prompter (true);
1636 name_prompter.set_title (_("Rename Track"));
1638 name_prompter.set_title (_("Rename Bus"));
1640 name_prompter.set_prompt (_("New name:"));
1641 name_prompter.set_initial_text (_route->name());
1642 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1643 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1644 name_prompter.show_all ();
1647 switch (name_prompter.run ()) {
1648 case Gtk::RESPONSE_ACCEPT:
1649 name_prompter.get_result (result);
1650 name_prompter.hide ();
1651 if (result.length()) {
1652 if (verify_new_route_name (result)) {
1653 _route->set_name (result);
1656 /* back to name prompter */
1660 /* nothing entered, just get out of here */
1675 RouteUI::toggle_comment_editor ()
1677 // if (ignore_toggle) {
1681 if (comment_window && comment_window->is_visible ()) {
1682 comment_window->hide ();
1684 open_comment_editor ();
1690 RouteUI::open_comment_editor ()
1692 if (comment_window == 0) {
1693 setup_comment_editor ();
1697 title = _route->name();
1698 title += _(": comment editor");
1700 comment_window->set_title (title);
1701 comment_window->present();
1705 RouteUI::setup_comment_editor ()
1707 comment_window = new ArdourWindow (""); // title will be reset to show route
1708 comment_window->set_skip_taskbar_hint (true);
1709 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1710 comment_window->set_default_size (400, 200);
1712 comment_area = manage (new TextView());
1713 comment_area->set_name ("MixerTrackCommentArea");
1714 comment_area->set_wrap_mode (WRAP_WORD);
1715 comment_area->set_editable (true);
1716 comment_area->get_buffer()->set_text (_route->comment());
1717 comment_area->show ();
1719 comment_window->add (*comment_area);
1723 RouteUI::comment_changed ()
1725 ignore_comment_edit = true;
1727 comment_area->get_buffer()->set_text (_route->comment());
1729 ignore_comment_edit = false;
1733 RouteUI::comment_editor_done_editing ()
1735 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1737 string const str = comment_area->get_buffer()->get_text();
1738 if (str == _route->comment ()) {
1742 _route->set_comment (str, this);
1746 RouteUI::set_route_active (bool a, bool apply_to_selection)
1748 if (apply_to_selection) {
1749 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1751 _route->set_active (a, this);
1756 RouteUI::duplicate_selected_routes ()
1758 ARDOUR_UI::instance()->start_duplicate_routes();
1762 RouteUI::toggle_denormal_protection ()
1764 if (denormal_menu_item) {
1768 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1770 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1771 _route->set_denormal_protection (x);
1777 RouteUI::denormal_protection_changed ()
1779 if (denormal_menu_item) {
1780 denormal_menu_item->set_active (_route->denormal_protection());
1785 RouteUI::disconnect_input ()
1787 _route->input()->disconnect (this);
1791 RouteUI::disconnect_output ()
1793 _route->output()->disconnect (this);
1797 RouteUI::is_track () const
1799 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1802 boost::shared_ptr<Track>
1803 RouteUI::track() const
1805 return boost::dynamic_pointer_cast<Track>(_route);
1809 RouteUI::is_audio_track () const
1811 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1814 boost::shared_ptr<AudioTrack>
1815 RouteUI::audio_track() const
1817 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1821 RouteUI::is_midi_track () const
1823 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1826 boost::shared_ptr<MidiTrack>
1827 RouteUI::midi_track() const
1829 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1833 RouteUI::has_audio_outputs () const
1835 return (_route->n_outputs().n_audio() > 0);
1839 RouteUI::map_frozen ()
1841 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1843 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1846 check_rec_enable_sensitivity ();
1851 RouteUI::adjust_latency ()
1853 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1857 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1860 std::string safe_name;
1863 prompter.get_result (name, true);
1865 safe_name = legalize_for_path (name);
1866 safe_name += template_suffix;
1868 path = Glib::build_filename (dir, safe_name);
1870 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1871 bool overwrite = overwrite_file_dialog (prompter,
1872 _("Confirm Template Overwrite"),
1873 _("A template already exists with that name. Do you want to overwrite it?"));
1880 _route->save_as_template (path, name);
1886 RouteUI::save_as_template ()
1890 dir = ARDOUR::user_route_template_directory ();
1892 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1893 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1897 ArdourPrompter prompter (true); // modal
1899 prompter.set_title (_("Save As Template"));
1900 prompter.set_prompt (_("Template name:"));
1901 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1903 bool finished = false;
1905 switch (prompter.run()) {
1906 case RESPONSE_ACCEPT:
1907 finished = process_save_template_prompter (prompter, dir);
1917 RouteUI::check_rec_enable_sensitivity ()
1919 if (!rec_enable_button) {
1920 assert (0); // This should not happen
1923 if (!_session->writable()) {
1924 rec_enable_button->set_sensitive (false);
1928 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1929 rec_enable_button->set_sensitive (false);
1930 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1931 rec_enable_button->set_sensitive (false);
1933 rec_enable_button->set_sensitive (true);
1935 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1936 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1938 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1940 update_monitoring_display ();
1944 RouteUI::parameter_changed (string const & p)
1946 /* this handles RC and per-session parameter changes */
1948 if (p == "disable-disarm-during-roll") {
1949 check_rec_enable_sensitivity ();
1950 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1951 set_button_names ();
1952 } else if (p == "auto-input") {
1953 update_monitoring_display ();
1954 } else if (p == "blink-rec-arm") {
1955 if (UIConfiguration::instance().get_blink_rec_arm()) {
1956 rec_blink_connection.disconnect ();
1957 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1959 rec_blink_connection.disconnect ();
1960 RouteUI::blink_rec_display(false);
1966 RouteUI::step_gain_up ()
1968 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1972 RouteUI::page_gain_up ()
1974 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1978 RouteUI::step_gain_down ()
1980 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1984 RouteUI::page_gain_down ()
1986 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1990 RouteUI::setup_invert_buttons ()
1992 /* remove old invert buttons */
1993 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1994 _invert_button_box.remove (**i);
1997 _invert_buttons.clear ();
1999 if (!_route || !_route->input()) {
2003 uint32_t const N = _route->input()->n_ports().n_audio ();
2005 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2007 for (uint32_t i = 0; i < to_add; ++i) {
2008 ArdourButton* b = manage (new ArdourButton);
2009 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2010 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2012 b->set_name (X_("invert button"));
2015 b->set_text (string_compose (X_("Ø (%1)"), N));
2017 b->set_text (X_("Ø"));
2020 b->set_text (string_compose (X_("Ø%1"), i + 1));
2023 if (N <= _max_invert_buttons) {
2024 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert polarity of channel %1 of this track. Right-click to show menu."), i + 1));
2026 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2029 _invert_buttons.push_back (b);
2030 _invert_button_box.pack_start (*b);
2033 _invert_button_box.set_spacing (1);
2034 _invert_button_box.show_all ();
2038 RouteUI::set_invert_button_state ()
2040 uint32_t const N = _route->input()->n_ports().n_audio();
2041 if (N > _max_invert_buttons) {
2043 /* One button for many channels; explicit active if all channels are inverted,
2044 implicit active if some are, off if none are.
2047 ArdourButton* b = _invert_buttons.front ();
2049 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2050 b->set_active_state (Gtkmm2ext::ExplicitActive);
2051 } else if (_route->phase_control()->any()) {
2052 b->set_active_state (Gtkmm2ext::ImplicitActive);
2054 b->set_active_state (Gtkmm2ext::Off);
2059 /* One button per channel; just set active */
2062 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2063 (*i)->set_active (_route->phase_control()->inverted (j));
2070 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2072 if (ev->button == 1 && i < _invert_buttons.size()) {
2073 uint32_t const N = _route->input()->n_ports().n_audio ();
2074 if (N <= _max_invert_buttons) {
2075 /* left-click inverts phase so long as we have a button per channel */
2076 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2085 RouteUI::invert_press (GdkEventButton* ev)
2087 using namespace Menu_Helpers;
2089 uint32_t const N = _route->input()->n_ports().n_audio();
2090 if (N <= _max_invert_buttons && ev->button != 3) {
2091 /* If we have an invert button per channel, we only pop
2092 up a menu on right-click; left click is handled
2098 delete _invert_menu;
2099 _invert_menu = new Menu;
2100 _invert_menu->set_name ("ArdourContextMenu");
2101 MenuList& items = _invert_menu->items ();
2103 for (uint32_t i = 0; i < N; ++i) {
2104 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2105 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2106 ++_i_am_the_modifier;
2107 e->set_active (_route->phase_control()->inverted (i));
2108 --_i_am_the_modifier;
2111 _invert_menu->popup (0, ev->time);
2117 RouteUI::invert_menu_toggled (uint32_t c)
2119 if (_i_am_the_modifier) {
2124 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2128 RouteUI::set_invert_sensitive (bool yn)
2130 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2131 (*b)->set_sensitive (yn);
2136 RouteUI::request_redraw ()
2139 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2143 /** The Route's gui_changed signal has been emitted */
2145 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2147 if (what_changed.contains (Properties::color)) {
2148 if (set_color_from_route () == 0) {
2149 route_color_changed ();
2153 if (what_changed.contains (Properties::selected)) {
2159 RouteUI::set_selected (bool yn)
2161 Selectable::set_selected (yn);
2163 _route->presentation_info().set_selected (yn);
2168 RouteUI::selected () const
2170 /* XXX not sure if this is a wise design. Probably don't really want
2171 * the cached _selected value from Selectable.
2178 return _route->presentation_info().selected();
2182 RouteUI::track_mode_changed (void)
2185 switch (track()->mode()) {
2186 case ARDOUR::NonLayered:
2187 case ARDOUR::Normal:
2188 rec_enable_button->set_icon (ArdourIcon::RecButton);
2190 case ARDOUR::Destructive:
2191 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2194 rec_enable_button->queue_draw();
2197 /** @return the color that this route should use; it maybe its own,
2198 or it maybe that of its route group.
2202 RouteUI::route_color () const
2205 RouteGroup* g = _route->route_group ();
2208 if (g && g->is_color()) {
2209 set_color_from_rgba (c, GroupTabs::group_color (g));
2212 /* deal with older 4.x color, which was stored in the GUI object state */
2214 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2218 /* old v4.x or earlier session. Use this information */
2220 int red, green, blue;
2223 stringstream ss (p);
2225 /* old color format version was:
2227 16bit value for red:16 bit value for green:16 bit value for blue
2242 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
2245 set_color_from_rgba (c, _route->presentation_info().color());
2252 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2254 _showing_sends_to = send_to;
2255 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2259 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2261 if (_route == send_to) {
2262 show_sends_button->set_active (true);
2263 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2265 show_sends_button->set_active (false);
2266 send_blink_connection.disconnect ();
2271 RouteUI::route_group() const
2273 return _route->route_group();
2277 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2278 : WM::ProxyBase (name, string())
2279 , _route (boost::weak_ptr<Route> (route))
2281 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2284 RoutePinWindowProxy::~RoutePinWindowProxy()
2289 ARDOUR::SessionHandlePtr*
2290 RoutePinWindowProxy::session_handle ()
2292 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2293 if (aw) { return aw; }
2298 RoutePinWindowProxy::get (bool create)
2300 boost::shared_ptr<Route> r = _route.lock ();
2309 _window = new PluginPinDialog (r);
2310 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2312 aw->set_session (_session);
2314 _window->show_all ();
2320 RoutePinWindowProxy::route_going_away ()
2324 WM::Manager::instance().remove (this);
2325 going_away_connection.disconnect();
2329 RouteUI::maybe_add_route_print_mgr ()
2331 if (_route->pinmgr_proxy ()) {
2334 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2335 string_compose ("RPM-%1", _route->id()), _route);
2336 wp->set_session (_session);
2338 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2340 wp->set_state (*ui_xml, 0);
2344 void* existing_ui = _route->pinmgr_proxy ();
2346 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2349 _route->set_pingmgr_proxy (wp);
2351 WM::Manager::instance().register_window (wp);
2355 RouteUI::manage_pins ()
2357 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2365 RouteUI::mark_hidden (bool yn)
2367 if (yn != _route->presentation_info().hidden()) {
2368 _route->presentation_info().set_hidden (yn);
2369 return true; // things changed