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 "route_time_axis.h"
69 #include "ui_config.h"
75 using namespace Gtkmm2ext;
76 using namespace ARDOUR;
77 using namespace ARDOUR_UI_UTILS;
81 uint32_t RouteUI::_max_invert_buttons = 3;
82 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
83 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
84 std::string RouteUI::program_port_prefix;
86 RouteUI::RouteUI (ARDOUR::Session* sess)
97 if (program_port_prefix.empty()) {
98 // compare to gtk2_ardour/port_group.cc
99 string lpn (PROGRAM_NAME);
100 boost::to_lower (lpn);
101 program_port_prefix = lpn + ":"; // e.g. "ardour:"
112 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
115 _route.reset (); /* drop reference to route, so that it can be cleaned up */
116 route_connections.drop_connections ();
122 delete comment_window;
123 delete input_selector;
124 delete output_selector;
127 send_blink_connection.disconnect ();
128 rec_blink_connection.disconnect ();
134 self_destruct = true;
140 pre_fader_mute_check = 0;
141 post_fader_mute_check = 0;
142 listen_mute_check = 0;
145 solo_isolated_check = 0;
146 solo_isolated_led = 0;
150 denormal_menu_item = 0;
153 multiple_mute_change = false;
154 multiple_solo_change = false;
155 _i_am_the_modifier = 0;
160 setup_invert_buttons ();
162 mute_button = manage (new ArdourButton);
163 mute_button->set_name ("mute button");
164 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
166 solo_button = manage (new ArdourButton);
167 solo_button->set_name ("solo button");
168 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
169 solo_button->set_no_show_all (true);
171 rec_enable_button = manage (new ArdourButton);
172 rec_enable_button->set_name ("record enable button");
173 rec_enable_button->set_icon (ArdourIcon::RecButton);
174 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
176 if (UIConfiguration::instance().get_blink_rec_arm()) {
177 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
180 show_sends_button = manage (new ArdourButton);
181 show_sends_button->set_name ("send alert button");
182 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
184 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
185 monitor_input_button->set_name ("monitor button");
186 monitor_input_button->set_text (_("In"));
187 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
188 monitor_input_button->set_no_show_all (true);
190 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
191 monitor_disk_button->set_name ("monitor button");
192 monitor_disk_button->set_text (_("Disk"));
193 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
194 monitor_disk_button->set_no_show_all (true);
196 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
197 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
198 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
200 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
201 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
203 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
204 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
206 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
207 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
209 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
210 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
211 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
212 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
214 monitor_input_button->set_distinct_led_click (false);
215 monitor_disk_button->set_distinct_led_click (false);
217 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
218 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
220 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
221 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
223 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
229 route_connections.drop_connections ();
237 denormal_menu_item = 0;
241 RouteUI::self_delete ()
247 RouteUI::set_route (boost::shared_ptr<Route> rp)
253 if (set_color_from_route()) {
254 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
258 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
261 delete input_selector;
264 delete output_selector;
267 mute_button->set_controllable (_route->mute_control());
268 solo_button->set_controllable (_route->solo_control());
270 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
272 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
274 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
275 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
276 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
277 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
278 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
281 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
282 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
283 track_mode_changed();
287 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
288 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
290 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
292 if (_session->writable() && is_track()) {
293 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
295 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
296 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
298 rec_enable_button->show();
299 rec_enable_button->set_controllable (t->rec_enable_control());
301 if (is_midi_track()) {
302 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
303 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
308 /* this will work for busses and tracks, and needs to be called to
309 set up the name entry/name label display.
313 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
314 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
316 update_monitoring_display ();
319 mute_button->unset_flags (Gtk::CAN_FOCUS);
320 solo_button->unset_flags (Gtk::CAN_FOCUS);
324 if (_route->is_monitor() || _route->is_master()) {
325 solo_button->hide ();
332 setup_invert_buttons ();
333 set_invert_button_state ();
335 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
336 bus_send_display_changed (s);
338 update_mute_display ();
339 update_solo_display ();
341 if (!UIConfiguration::instance().get_blink_rec_arm()) {
342 blink_rec_display(true); // set initial rec-en button state
345 check_rec_enable_sensitivity ();
346 maybe_add_route_print_mgr ();
347 route_color_changed();
351 RouteUI::polarity_changed ()
357 set_invert_button_state ();
361 RouteUI::mute_press (GdkEventButton* ev)
363 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
367 //if this is a binding action, let the ArdourButton handle it
368 if ( BindingProxy::is_bind_action(ev) )
371 multiple_mute_change = false;
373 if (Keyboard::is_context_menu_event (ev)) {
379 mute_menu->popup(0,ev->time);
385 if (Keyboard::is_button2_event (ev)) {
386 // button2-click is "momentary"
388 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
391 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
393 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
395 /* toggle mute on everything (but
396 * exclude the master and monitor)
398 * because we are going to erase
399 * elements of the list we need to work
403 boost::shared_ptr<RouteList> copy (new RouteList);
405 *copy = *_session->get_routes ();
407 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
408 if ((*i)->is_master() || (*i)->is_monitor()) {
416 _mute_release->routes = copy;
420 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
422 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
424 /* Primary-button1 inverts the implication of
425 the group being active. If the group is
426 active (for mute), then this modifier means
427 "do not apply to mute". If the group is
428 inactive (for mute), then this modifier
429 means "apply to route". This is all
430 accomplished by passing just the actual
431 route, along with the InverseGroup group
434 NOTE: Primary-button2 is MIDI learn.
437 boost::shared_ptr<RouteList> rl;
439 if (ev->button == 1) {
441 rl.reset (new RouteList);
442 rl->push_back (_route);
445 _mute_release->routes = rl;
449 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
454 /* plain click applies change to this route */
456 boost::shared_ptr<RouteList> rl (new RouteList);
457 rl->push_back (_route);
460 _mute_release->routes = rl;
463 _session->set_control (_route->mute_control(), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
473 RouteUI::mute_release (GdkEventButton* /*ev*/)
477 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
478 delete _mute_release;
486 RouteUI::edit_output_configuration ()
488 if (output_selector == 0) {
490 boost::shared_ptr<Send> send;
491 boost::shared_ptr<IO> output;
493 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
494 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
495 output = send->output();
497 output = _route->output ();
500 output = _route->output ();
503 output_selector = new IOSelectorWindow (_session, output);
506 if (output_selector->is_visible()) {
507 output_selector->get_toplevel()->get_window()->raise();
509 output_selector->present ();
512 //output_selector->set_keep_above (true);
516 RouteUI::edit_input_configuration ()
518 if (input_selector == 0) {
519 input_selector = new IOSelectorWindow (_session, _route->input());
522 if (input_selector->is_visible()) {
523 input_selector->get_toplevel()->get_window()->raise();
525 input_selector->present ();
528 //input_selector->set_keep_above (true);
532 RouteUI::solo_press(GdkEventButton* ev)
534 /* ignore double/triple clicks */
536 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
540 //if this is a binding action, let the ArdourButton handle it
541 if ( BindingProxy::is_bind_action(ev) )
544 multiple_solo_change = false;
546 if (Keyboard::is_context_menu_event (ev)) {
548 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
549 ! (solo_safe_led && solo_safe_led->is_visible())) {
551 if (solo_menu == 0) {
555 solo_menu->popup (1, ev->time);
560 if (Keyboard::is_button2_event (ev)) {
562 // button2-click is "momentary"
563 _solo_release = new SoloMuteRelease (_route->self_soloed());
566 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
568 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
570 /* Primary-Tertiary-click applies change to all routes */
573 _solo_release->routes = _session->get_routes ();
577 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
579 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
581 // Primary-Secondary-click: exclusively solo this track
584 _solo_release->exclusive = true;
586 boost::shared_ptr<RouteList> routes = _session->get_routes();
588 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
589 if ((*i)->soloed ()) {
590 _solo_release->routes_on->push_back (*i);
592 _solo_release->routes_off->push_back (*i);
597 if (Config->get_solo_control_is_listen_control()) {
598 /* ??? we need a just_one_listen() method */
601 boost::shared_ptr<ControlList> cl (new ControlList);
602 cl->push_back (_route->solo_control());
603 _session->set_controls (cl, 1.0, Controllable::NoGroup);
606 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
608 // shift-click: toggle solo isolated status
610 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
611 delete _solo_release;
614 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
616 /* Primary-button1: solo mix group.
617 NOTE: Primary-button2 is MIDI learn.
620 /* Primary-button1 applies change to the mix group even if it is not active
621 NOTE: Primary-button2 is MIDI learn.
624 boost::shared_ptr<RouteList> rl;
626 if (ev->button == 1) {
628 /* Primary-button1 inverts the implication of
629 the group being active. If the group is
630 active (for solo), then this modifier means
631 "do not apply to solo". If the group is
632 inactive (for mute), then this modifier
633 means "apply to route". This is all
634 accomplished by passing just the actual
635 route, along with the InverseGroup group
638 NOTE: Primary-button2 is MIDI learn.
641 rl.reset (new RouteList);
642 rl->push_back (_route);
645 _solo_release->routes = rl;
650 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), 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 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
677 RouteUI::solo_release (GdkEventButton* /*ev*/)
681 if (_solo_release->exclusive) {
685 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
688 delete _solo_release;
696 RouteUI::rec_enable_press(GdkEventButton* ev)
698 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
702 //if this is a binding action, let the ArdourButton handle it
703 if ( BindingProxy::is_bind_action(ev) )
706 if (!_session->engine().connected()) {
707 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
712 if (is_midi_track()) {
714 /* rec-enable button exits from step editing */
716 if (midi_track()->step_editing()) {
717 midi_track()->set_step_editing (false);
722 if (is_track() && rec_enable_button) {
724 if (Keyboard::is_button2_event (ev)) {
726 //rec arm does not have a momentary mode
729 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
732 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
734 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
736 /* Primary-button1 applies change to the route group (even if it is not active)
737 NOTE: Primary-button2 is MIDI learn.
740 if (ev->button == 1) {
742 boost::shared_ptr<RouteList> rl;
744 rl.reset (new RouteList);
745 rl->push_back (_route);
748 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
751 } else if (Keyboard::is_context_menu_event (ev)) {
753 /* do this on release */
757 boost::shared_ptr<Track> trk = track();
758 _session->set_control (trk->rec_enable_control(), !trk->rec_enable_control()->get_value(), Controllable::UseGroup);
766 RouteUI::update_monitoring_display ()
772 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
778 MonitorState ms = t->monitoring_state();
780 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
781 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
783 if (ms & MonitoringInput) {
784 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
786 monitor_input_button->unset_active_state ();
790 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
791 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
793 if (ms & MonitoringDisk) {
794 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
796 monitor_disk_button->unset_active_state ();
802 RouteUI::monitor_input_press(GdkEventButton*)
808 RouteUI::monitor_input_release(GdkEventButton* ev)
810 return monitor_release (ev, MonitorInput);
814 RouteUI::monitor_disk_press (GdkEventButton*)
820 RouteUI::monitor_disk_release (GdkEventButton* ev)
822 return monitor_release (ev, MonitorDisk);
826 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
828 if (ev->button != 1) {
832 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
839 boost::shared_ptr<RouteList> rl;
841 /* XXX for now, monitoring choices are orthogonal. cue monitoring
842 will follow in 3.X but requires mixing the input and playback (disk)
843 signal together, which requires yet more buffers.
846 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
847 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
849 /* this line will change when the options are non-orthogonal */
850 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
854 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
855 rl = _session->get_routes ();
857 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
858 if (_route->route_group() && _route->route_group()->is_monitoring()) {
859 rl = _route->route_group()->route_list();
861 rl.reset (new RouteList);
862 rl->push_back (route());
865 rl.reset (new RouteList);
866 rl->push_back (route());
870 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
876 RouteUI::build_record_menu ()
879 record_menu = new Menu;
880 record_menu->set_name ("ArdourContextMenu");
881 using namespace Menu_Helpers;
882 MenuList& items = record_menu->items();
884 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
885 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
887 if (is_midi_track()) {
888 items.push_back (SeparatorElem());
889 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
890 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
894 if (step_edit_item) {
895 if (track()->rec_enable_control()->get_value()) {
896 step_edit_item->set_sensitive (false);
898 step_edit_item->set_active (midi_track()->step_editing());
901 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
902 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
907 RouteUI::toggle_step_edit ()
909 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
913 midi_track()->set_step_editing (step_edit_item->get_active());
917 RouteUI::toggle_rec_safe ()
919 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
925 /* This check is made inside the control too, but dong it here can't
929 if (_route->rec_enable_control()->get_value()) {
933 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
937 RouteUI::step_edit_changed (bool yn)
940 if (rec_enable_button) {
941 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
944 start_step_editing ();
946 if (step_edit_item) {
947 step_edit_item->set_active (true);
952 if (rec_enable_button) {
953 rec_enable_button->unset_active_state ();
956 stop_step_editing ();
958 if (step_edit_item) {
959 step_edit_item->set_active (false);
965 RouteUI::rec_enable_release (GdkEventButton* ev)
967 if (Keyboard::is_context_menu_event (ev)) {
968 build_record_menu ();
970 record_menu->popup (1, ev->time);
979 RouteUI::build_sends_menu ()
981 using namespace Menu_Helpers;
983 sends_menu = new Menu;
984 sends_menu->set_name ("ArdourContextMenu");
985 MenuList& items = sends_menu->items();
988 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
992 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
996 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1000 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1004 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1008 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1011 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1015 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1018 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1019 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1020 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1025 RouteUI::create_sends (Placement p, bool include_buses)
1027 _session->globally_add_internal_sends (_route, p, include_buses);
1031 RouteUI::create_selected_sends (Placement p, bool include_buses)
1033 boost::shared_ptr<RouteList> rlist (new RouteList);
1034 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1036 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1037 RouteTimeAxisView* rtv;
1039 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1040 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1041 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1042 rlist->push_back (rui->route());
1048 _session->add_internal_sends (_route, p, rlist);
1052 RouteUI::set_sends_gain_from_track ()
1054 _session->globally_set_send_gains_from_track (_route);
1058 RouteUI::set_sends_gain_to_zero ()
1060 _session->globally_set_send_gains_to_zero (_route);
1064 RouteUI::set_sends_gain_to_unity ()
1066 _session->globally_set_send_gains_to_unity (_route);
1070 RouteUI::show_sends_press(GdkEventButton* ev)
1072 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1076 if (!is_track() && show_sends_button) {
1078 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1080 // do nothing on midi sigc::bind event
1083 } else if (Keyboard::is_context_menu_event (ev)) {
1085 if (sends_menu == 0) {
1086 build_sends_menu ();
1089 sends_menu->popup (0, ev->time);
1093 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1096 set_showing_sends_to (boost::shared_ptr<Route> ());
1098 set_showing_sends_to (_route);
1107 RouteUI::show_sends_release (GdkEventButton*)
1113 RouteUI::send_blink (bool onoff)
1115 if (!show_sends_button) {
1120 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1122 show_sends_button->unset_active_state ();
1126 Gtkmm2ext::ActiveState
1127 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1129 boost::shared_ptr<SoloControl> sc = s->solo_control();
1132 return Gtkmm2ext::Off;
1135 if (!sc->can_solo()) {
1136 return Gtkmm2ext::Off;
1140 if (sc->self_soloed()) {
1141 return Gtkmm2ext::ExplicitActive;
1142 } else if (sc->soloed_by_others()) {
1143 return Gtkmm2ext::ImplicitActive;
1145 return Gtkmm2ext::Off;
1149 Gtkmm2ext::ActiveState
1150 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1152 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1155 return Gtkmm2ext::Off;
1158 if (s->is_master() || s->is_monitor()) {
1159 return Gtkmm2ext::Off;
1162 if (sc->solo_isolated()) {
1163 return Gtkmm2ext::ExplicitActive;
1165 return Gtkmm2ext::Off;
1169 Gtkmm2ext::ActiveState
1170 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1172 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1175 return Gtkmm2ext::Off;
1178 if (s->is_master() || s->is_monitor()) {
1179 return Gtkmm2ext::Off;
1182 if (sc->solo_safe()) {
1183 return Gtkmm2ext::ExplicitActive;
1185 return Gtkmm2ext::Off;
1190 RouteUI::update_solo_display ()
1192 bool yn = _route->solo_safe_control()->solo_safe ();
1194 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1195 solo_safe_check->set_active (yn);
1198 yn = _route->solo_isolate_control()->solo_isolated ();
1200 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1201 solo_isolated_check->set_active (yn);
1204 set_button_names ();
1206 if (solo_isolated_led) {
1207 if (_route->solo_isolate_control()->solo_isolated()) {
1208 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1210 solo_isolated_led->unset_active_state ();
1214 if (solo_safe_led) {
1215 if (_route->solo_safe_control()->solo_safe()) {
1216 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1218 solo_safe_led->unset_active_state ();
1222 solo_button->set_active_state (solo_active_state (_route));
1224 /* some changes to solo status can affect mute display, so catch up
1227 update_mute_display ();
1231 RouteUI::solo_changed_so_update_mute ()
1233 update_mute_display ();
1237 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1239 boost::shared_ptr<MuteControl> mc = s->mute_control();
1241 if (s->is_monitor()) {
1242 return Gtkmm2ext::Off;
1246 return Gtkmm2ext::Off;
1249 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1251 if (mc->muted_by_self ()) {
1253 return Gtkmm2ext::ExplicitActive;
1254 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1255 /* this will reflect both solo mutes AND master mutes */
1256 return Gtkmm2ext::ImplicitActive;
1258 /* no mute at all */
1259 return Gtkmm2ext::Off;
1264 if (mc->muted_by_self()) {
1266 return Gtkmm2ext::ExplicitActive;
1267 } else if (mc->muted_by_masters ()) {
1268 /* this shows only master mutes, not mute-by-others-soloing */
1269 return Gtkmm2ext::ImplicitActive;
1271 /* no mute at all */
1272 return Gtkmm2ext::Off;
1276 return ActiveState(0);
1280 RouteUI::update_mute_display ()
1286 mute_button->set_active_state (mute_active_state (_session, _route));
1291 RouteUI::route_rec_enable_changed ()
1293 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1294 update_monitoring_display ();
1298 RouteUI::session_rec_enable_changed ()
1300 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1301 update_monitoring_display ();
1305 RouteUI::blink_rec_display (bool blinkOn)
1307 if (!rec_enable_button || !_route) {
1311 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1319 if (track()->rec_enable_control()->get_value()) {
1320 switch (_session->record_status ()) {
1321 case Session::Recording:
1322 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1325 case Session::Disabled:
1326 case Session::Enabled:
1327 if (UIConfiguration::instance().get_blink_rec_arm()) {
1328 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1330 rec_enable_button->set_active_state ( ImplicitActive );
1335 if (step_edit_item) {
1336 step_edit_item->set_sensitive (false);
1340 rec_enable_button->unset_active_state ();
1342 if (step_edit_item) {
1343 step_edit_item->set_sensitive (true);
1347 check_rec_enable_sensitivity ();
1351 RouteUI::build_solo_menu (void)
1353 using namespace Menu_Helpers;
1355 solo_menu = new Menu;
1356 solo_menu->set_name ("ArdourContextMenu");
1357 MenuList& items = solo_menu->items();
1358 Gtk::CheckMenuItem* check;
1360 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1361 check->set_active (_route->solo_isolate_control()->solo_isolated());
1362 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1363 items.push_back (CheckMenuElem(*check));
1364 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1367 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1368 check->set_active (_route->solo_safe_control()->solo_safe());
1369 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1370 items.push_back (CheckMenuElem(*check));
1371 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1374 //items.push_back (SeparatorElem());
1375 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1380 RouteUI::build_mute_menu(void)
1382 using namespace Menu_Helpers;
1384 mute_menu = new Menu;
1385 mute_menu->set_name ("ArdourContextMenu");
1387 MenuList& items = mute_menu->items();
1389 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1390 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1391 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1392 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1393 pre_fader_mute_check->show_all();
1395 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1396 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1397 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1398 items.push_back (CheckMenuElem(*post_fader_mute_check));
1399 post_fader_mute_check->show_all();
1401 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1402 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1403 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1404 items.push_back (CheckMenuElem(*listen_mute_check));
1405 listen_mute_check->show_all();
1407 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1408 init_mute_menu(MuteMaster::Main, main_mute_check);
1409 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1410 items.push_back (CheckMenuElem(*main_mute_check));
1411 main_mute_check->show_all();
1413 //items.push_back (SeparatorElem());
1414 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1416 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1420 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1422 check->set_active (_route->mute_control()->mute_points() & mp);
1426 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1428 if (check->get_active()) {
1429 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1431 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1436 RouteUI::muting_change ()
1438 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1441 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1443 yn = (current & MuteMaster::PreFader);
1445 if (pre_fader_mute_check->get_active() != yn) {
1446 pre_fader_mute_check->set_active (yn);
1449 yn = (current & MuteMaster::PostFader);
1451 if (post_fader_mute_check->get_active() != yn) {
1452 post_fader_mute_check->set_active (yn);
1455 yn = (current & MuteMaster::Listen);
1457 if (listen_mute_check->get_active() != yn) {
1458 listen_mute_check->set_active (yn);
1461 yn = (current & MuteMaster::Main);
1463 if (main_mute_check->get_active() != yn) {
1464 main_mute_check->set_active (yn);
1469 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1471 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1475 bool view = solo_isolated_led->active_state();
1476 bool model = _route->solo_isolate_control()->solo_isolated();
1478 /* called BEFORE the view has changed */
1480 if (ev->button == 1) {
1481 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1484 /* disable isolate for all routes */
1485 DisplaySuspender ds;
1486 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1488 /* enable isolate for all routes */
1489 DisplaySuspender ds;
1490 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1495 if (model == view) {
1497 /* flip just this route */
1499 boost::shared_ptr<RouteList> rl (new RouteList);
1500 rl->push_back (_route);
1501 DisplaySuspender ds;
1502 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1511 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1513 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1517 bool view = solo_safe_led->active_state();
1518 bool model = _route->solo_safe_control()->solo_safe();
1520 if (ev->button == 1) {
1521 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1522 boost::shared_ptr<RouteList> rl (_session->get_routes());
1524 /* disable solo safe for all routes */
1525 DisplaySuspender ds;
1526 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1527 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1530 /* enable solo safe for all routes */
1531 DisplaySuspender ds;
1532 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1533 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1538 if (model == view) {
1539 /* flip just this route */
1540 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1549 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1551 bool view = check->get_active();
1552 bool model = _route->solo_isolate_control()->solo_isolated();
1554 /* called AFTER the view has changed */
1556 if (model != view) {
1557 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1562 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1564 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1567 /** Ask the user to choose a colour, and then apply that color to my route
1570 RouteUI::choose_color ()
1573 Gdk::Color c (gdk_color_from_rgb (_route->presentation_info().color()));
1574 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1577 set_color (gdk_color_to_rgba (color));
1581 /** Set the route's own color. This may not be used for display if
1582 * the route is in a group which shares its color with its routes.
1585 RouteUI::set_color (uint32_t c)
1587 _route->presentation_info().set_color (c);
1590 /** @return GUI state ID for things that are common to the route in all its representations */
1592 RouteUI::route_state_id () const
1594 return string_compose (X_("route %1"), _route->id().to_s());
1598 RouteUI::set_color_from_route ()
1603 /** @return true if this name should be used for the route, otherwise false */
1605 RouteUI::verify_new_route_name (const std::string& name)
1607 if (name.find (':') == string::npos) {
1611 MessageDialog colon_msg (
1612 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1613 false, MESSAGE_QUESTION, BUTTONS_NONE
1616 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1617 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1619 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1623 RouteUI::route_rename ()
1625 ArdourPrompter name_prompter (true);
1630 name_prompter.set_title (_("Rename Track"));
1632 name_prompter.set_title (_("Rename Bus"));
1634 name_prompter.set_prompt (_("New name:"));
1635 name_prompter.set_initial_text (_route->name());
1636 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1637 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1638 name_prompter.show_all ();
1641 switch (name_prompter.run ()) {
1642 case Gtk::RESPONSE_ACCEPT:
1643 name_prompter.get_result (result);
1644 name_prompter.hide ();
1645 if (result.length()) {
1646 if (verify_new_route_name (result)) {
1647 _route->set_name (result);
1650 /* back to name prompter */
1654 /* nothing entered, just get out of here */
1669 RouteUI::toggle_comment_editor ()
1671 // if (ignore_toggle) {
1675 if (comment_window && comment_window->is_visible ()) {
1676 comment_window->hide ();
1678 open_comment_editor ();
1684 RouteUI::open_comment_editor ()
1686 if (comment_window == 0) {
1687 setup_comment_editor ();
1691 title = _route->name();
1692 title += _(": comment editor");
1694 comment_window->set_title (title);
1695 comment_window->present();
1699 RouteUI::setup_comment_editor ()
1701 comment_window = new ArdourWindow (""); // title will be reset to show route
1702 comment_window->set_skip_taskbar_hint (true);
1703 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1704 comment_window->set_default_size (400, 200);
1706 comment_area = manage (new TextView());
1707 comment_area->set_name ("MixerTrackCommentArea");
1708 comment_area->set_wrap_mode (WRAP_WORD);
1709 comment_area->set_editable (true);
1710 comment_area->get_buffer()->set_text (_route->comment());
1711 comment_area->show ();
1713 comment_window->add (*comment_area);
1717 RouteUI::comment_changed ()
1719 ignore_comment_edit = true;
1721 comment_area->get_buffer()->set_text (_route->comment());
1723 ignore_comment_edit = false;
1727 RouteUI::comment_editor_done_editing ()
1729 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1731 string const str = comment_area->get_buffer()->get_text();
1732 if (str == _route->comment ()) {
1736 _route->set_comment (str, this);
1740 RouteUI::set_route_active (bool a, bool apply_to_selection)
1742 if (apply_to_selection) {
1743 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1745 _route->set_active (a, this);
1750 RouteUI::duplicate_selected_routes ()
1752 ARDOUR_UI::instance()->start_duplicate_routes();
1756 RouteUI::toggle_denormal_protection ()
1758 if (denormal_menu_item) {
1762 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1764 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1765 _route->set_denormal_protection (x);
1771 RouteUI::denormal_protection_changed ()
1773 if (denormal_menu_item) {
1774 denormal_menu_item->set_active (_route->denormal_protection());
1779 RouteUI::disconnect_input ()
1781 _route->input()->disconnect (this);
1785 RouteUI::disconnect_output ()
1787 _route->output()->disconnect (this);
1791 RouteUI::is_track () const
1793 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1796 boost::shared_ptr<Track>
1797 RouteUI::track() const
1799 return boost::dynamic_pointer_cast<Track>(_route);
1803 RouteUI::is_audio_track () const
1805 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1808 boost::shared_ptr<AudioTrack>
1809 RouteUI::audio_track() const
1811 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1815 RouteUI::is_midi_track () const
1817 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1820 boost::shared_ptr<MidiTrack>
1821 RouteUI::midi_track() const
1823 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1827 RouteUI::has_audio_outputs () const
1829 return (_route->n_outputs().n_audio() > 0);
1833 RouteUI::map_frozen ()
1835 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1837 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1840 check_rec_enable_sensitivity ();
1845 RouteUI::adjust_latency ()
1847 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1851 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1854 std::string safe_name;
1857 prompter.get_result (name, true);
1859 safe_name = legalize_for_path (name);
1860 safe_name += template_suffix;
1862 path = Glib::build_filename (dir, safe_name);
1864 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1865 bool overwrite = overwrite_file_dialog (prompter,
1866 _("Confirm Template Overwrite"),
1867 _("A template already exists with that name. Do you want to overwrite it?"));
1874 _route->save_as_template (path, name);
1880 RouteUI::save_as_template ()
1884 dir = ARDOUR::user_route_template_directory ();
1886 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1887 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1891 ArdourPrompter prompter (true); // modal
1893 prompter.set_title (_("Save As Template"));
1894 prompter.set_prompt (_("Template name:"));
1895 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1897 bool finished = false;
1899 switch (prompter.run()) {
1900 case RESPONSE_ACCEPT:
1901 finished = process_save_template_prompter (prompter, dir);
1911 RouteUI::check_rec_enable_sensitivity ()
1913 if (!rec_enable_button) {
1914 assert (0); // This should not happen
1917 if (!_session->writable()) {
1918 rec_enable_button->set_sensitive (false);
1922 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1923 rec_enable_button->set_sensitive (false);
1924 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1925 rec_enable_button->set_sensitive (false);
1927 rec_enable_button->set_sensitive (true);
1929 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1930 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1932 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1934 update_monitoring_display ();
1938 RouteUI::parameter_changed (string const & p)
1940 /* this handles RC and per-session parameter changes */
1942 if (p == "disable-disarm-during-roll") {
1943 check_rec_enable_sensitivity ();
1944 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1945 set_button_names ();
1946 } else if (p == "auto-input") {
1947 update_monitoring_display ();
1948 } else if (p == "blink-rec-arm") {
1949 if (UIConfiguration::instance().get_blink_rec_arm()) {
1950 rec_blink_connection.disconnect ();
1951 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1953 rec_blink_connection.disconnect ();
1954 RouteUI::blink_rec_display(false);
1960 RouteUI::step_gain_up ()
1962 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1966 RouteUI::page_gain_up ()
1968 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1972 RouteUI::step_gain_down ()
1974 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1978 RouteUI::page_gain_down ()
1980 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1984 RouteUI::setup_invert_buttons ()
1986 /* remove old invert buttons */
1987 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1988 _invert_button_box.remove (**i);
1991 _invert_buttons.clear ();
1993 if (!_route || !_route->input()) {
1997 uint32_t const N = _route->input()->n_ports().n_audio ();
1999 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2001 for (uint32_t i = 0; i < to_add; ++i) {
2002 ArdourButton* b = manage (new ArdourButton);
2003 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2004 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2006 b->set_name (X_("invert button"));
2009 b->set_text (string_compose (X_("Ø (%1)"), N));
2011 b->set_text (X_("Ø"));
2014 b->set_text (string_compose (X_("Ø%1"), i + 1));
2017 if (N <= _max_invert_buttons) {
2018 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));
2020 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2023 _invert_buttons.push_back (b);
2024 _invert_button_box.pack_start (*b);
2027 _invert_button_box.set_spacing (1);
2028 _invert_button_box.show_all ();
2032 RouteUI::set_invert_button_state ()
2034 uint32_t const N = _route->input()->n_ports().n_audio();
2035 if (N > _max_invert_buttons) {
2037 /* One button for many channels; explicit active if all channels are inverted,
2038 implicit active if some are, off if none are.
2041 ArdourButton* b = _invert_buttons.front ();
2043 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2044 b->set_active_state (Gtkmm2ext::ExplicitActive);
2045 } else if (_route->phase_control()->any()) {
2046 b->set_active_state (Gtkmm2ext::ImplicitActive);
2048 b->set_active_state (Gtkmm2ext::Off);
2053 /* One button per channel; just set active */
2056 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2057 (*i)->set_active (_route->phase_control()->inverted (j));
2064 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2066 if (ev->button == 1 && i < _invert_buttons.size()) {
2067 uint32_t const N = _route->input()->n_ports().n_audio ();
2068 if (N <= _max_invert_buttons) {
2069 /* left-click inverts phase so long as we have a button per channel */
2070 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2079 RouteUI::invert_press (GdkEventButton* ev)
2081 using namespace Menu_Helpers;
2083 uint32_t const N = _route->input()->n_ports().n_audio();
2084 if (N <= _max_invert_buttons && ev->button != 3) {
2085 /* If we have an invert button per channel, we only pop
2086 up a menu on right-click; left click is handled
2092 delete _invert_menu;
2093 _invert_menu = new Menu;
2094 _invert_menu->set_name ("ArdourContextMenu");
2095 MenuList& items = _invert_menu->items ();
2097 for (uint32_t i = 0; i < N; ++i) {
2098 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2099 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2100 ++_i_am_the_modifier;
2101 e->set_active (_route->phase_control()->inverted (i));
2102 --_i_am_the_modifier;
2105 _invert_menu->popup (0, ev->time);
2111 RouteUI::invert_menu_toggled (uint32_t c)
2113 if (_i_am_the_modifier) {
2118 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2122 RouteUI::set_invert_sensitive (bool yn)
2124 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2125 (*b)->set_sensitive (yn);
2130 RouteUI::request_redraw ()
2133 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2137 /** The Route's gui_changed signal has been emitted */
2139 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2141 if (what_changed.contains (Properties::color)) {
2142 if (set_color_from_route () == 0) {
2143 route_color_changed ();
2147 if (what_changed.contains (Properties::selected)) {
2153 RouteUI::set_selected (bool yn)
2155 Selectable::set_selected (yn);
2157 _route->presentation_info().set_selected (yn);
2162 RouteUI::selected () const
2164 /* XXX not sure if this is a wise design. Probably don't really want
2165 * the cached _selected value from Selectable.
2172 return _route->presentation_info().selected();
2176 RouteUI::track_mode_changed (void)
2179 switch (track()->mode()) {
2180 case ARDOUR::NonLayered:
2181 case ARDOUR::Normal:
2182 rec_enable_button->set_icon (ArdourIcon::RecButton);
2184 case ARDOUR::Destructive:
2185 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2188 rec_enable_button->queue_draw();
2191 /** @return the color that this route should use; it maybe its own,
2192 or it maybe that of its route group.
2196 RouteUI::route_color () const
2199 RouteGroup* g = _route->route_group ();
2202 if (g && g->is_color()) {
2203 set_color_from_rgba (c, GroupTabs::group_color (g));
2206 /* deal with older 4.x color, which was stored in the GUI object state */
2208 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2212 /* old v4.x or earlier session. Use this information */
2216 PresentationInfo::color_t color = 0;
2218 stringstream ss (p);
2220 /* old color format version was:
2222 16bit value for red:16 bit value for green:16 bit value for blue
2229 color |= ((component >> 2) << 16);
2232 color |= ((component >> 2) << 8);
2234 color |= (component >> 2);
2236 _route->presentation_info().set_color (color);
2239 set_color_from_rgba (c, _route->presentation_info().color());
2246 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2248 _showing_sends_to = send_to;
2249 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2253 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2255 if (_route == send_to) {
2256 show_sends_button->set_active (true);
2257 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2259 show_sends_button->set_active (false);
2260 send_blink_connection.disconnect ();
2265 RouteUI::route_group() const
2267 return _route->route_group();
2271 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2272 : WM::ProxyBase (name, string())
2273 , _route (boost::weak_ptr<Route> (route))
2275 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2278 RoutePinWindowProxy::~RoutePinWindowProxy()
2283 ARDOUR::SessionHandlePtr*
2284 RoutePinWindowProxy::session_handle ()
2286 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2287 if (aw) { return aw; }
2292 RoutePinWindowProxy::get (bool create)
2294 boost::shared_ptr<Route> r = _route.lock ();
2303 _window = new PluginPinDialog (r);
2304 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2306 aw->set_session (_session);
2308 _window->show_all ();
2314 RoutePinWindowProxy::route_going_away ()
2318 WM::Manager::instance().remove (this);
2319 going_away_connection.disconnect();
2323 RouteUI::maybe_add_route_print_mgr ()
2325 if (_route->pinmgr_proxy ()) {
2328 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2329 string_compose ("RPM-%1", _route->id()), _route);
2330 wp->set_session (_session);
2332 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2334 wp->set_state (*ui_xml, 0);
2338 void* existing_ui = _route->pinmgr_proxy ();
2340 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2343 _route->set_pingmgr_proxy (wp);
2345 WM::Manager::instance().register_window (wp);
2349 RouteUI::manage_pins ()
2351 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2359 RouteUI::mark_hidden (bool yn)
2361 if (yn != _route->presentation_info().hidden()) {
2362 _route->presentation_info().set_hidden (yn);
2363 return true; // things changed