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.
21 #include <boost/algorithm/string.hpp>
23 #include <gtkmm2ext/gtk_ui.h>
24 #include <gtkmm2ext/choice.h>
25 #include <gtkmm2ext/doi.h>
26 #include <gtkmm2ext/bindable_button.h>
27 #include <gtkmm2ext/barcontroller.h>
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
31 #include "pbd/memento_command.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour/dB.h"
37 #include "ardour/route_group.h"
38 #include "ardour/solo_isolate_control.h"
39 #include "ardour/vca.h"
40 #include "ardour/vca_manager.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/filename_extensions.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/monitor_control.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/profile.h"
50 #include "ardour/phase_control.h"
51 #include "ardour/send.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/template_utils.h"
56 #include "ardour_button.h"
57 #include "ardour_dialog.h"
58 #include "ardour_ui.h"
59 #include "automation_time_axis.h"
61 #include "group_tabs.h"
62 #include "gui_object.h"
63 #include "gui_thread.h"
65 #include "latency_gui.h"
66 #include "mixer_strip.h"
67 #include "plugin_pin_dialog.h"
69 #include "rgb_macros.h"
70 #include "route_time_axis.h"
73 #include "ui_config.h"
79 using namespace Gtkmm2ext;
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
85 uint32_t RouteUI::_max_invert_buttons = 3;
86 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
87 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
88 std::string RouteUI::program_port_prefix;
90 RouteUI::RouteUI (ARDOUR::Session* sess)
91 : monitor_input_button (0)
92 , monitor_disk_button (0)
100 , output_selector (0)
103 if (program_port_prefix.empty()) {
104 // compare to gtk2_ardour/port_group.cc
105 string lpn (PROGRAM_NAME);
106 boost::to_lower (lpn);
107 program_port_prefix = lpn + ":"; // e.g. "ardour:"
118 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
121 _route.reset (); /* drop reference to route, so that it can be cleaned up */
122 route_connections.drop_connections ();
128 delete comment_window;
129 delete input_selector;
130 delete output_selector;
131 delete monitor_input_button;
132 delete monitor_disk_button;
135 send_blink_connection.disconnect ();
136 rec_blink_connection.disconnect ();
142 self_destruct = true;
148 pre_fader_mute_check = 0;
149 post_fader_mute_check = 0;
150 listen_mute_check = 0;
153 solo_isolated_check = 0;
154 solo_isolated_led = 0;
158 denormal_menu_item = 0;
161 multiple_mute_change = false;
162 multiple_solo_change = false;
163 _i_am_the_modifier = 0;
168 setup_invert_buttons ();
170 mute_button = manage (new ArdourButton);
171 mute_button->set_name ("mute button");
172 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
174 solo_button = manage (new ArdourButton);
175 solo_button->set_name ("solo button");
176 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
177 solo_button->set_no_show_all (true);
179 rec_enable_button = manage (new ArdourButton);
180 rec_enable_button->set_name ("record enable button");
181 rec_enable_button->set_icon (ArdourIcon::RecButton);
182 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
184 if (UIConfiguration::instance().get_blink_rec_arm()) {
185 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
188 show_sends_button = manage (new ArdourButton);
189 show_sends_button->set_name ("send alert button");
190 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
192 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
193 monitor_input_button->set_name ("monitor button");
194 monitor_input_button->set_text (_("In"));
195 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
196 monitor_input_button->set_no_show_all (true);
198 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_disk_button->set_name ("monitor button");
200 monitor_disk_button->set_text (_("Disk"));
201 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
202 monitor_disk_button->set_no_show_all (true);
204 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
205 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
206 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
208 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
209 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
212 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
213 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
215 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
216 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
218 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
219 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
220 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
221 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
223 monitor_input_button->set_distinct_led_click (false);
224 monitor_disk_button->set_distinct_led_click (false);
226 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
227 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
229 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
230 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
232 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
238 route_connections.drop_connections ();
246 denormal_menu_item = 0;
250 RouteUI::self_delete ()
256 RouteUI::set_route (boost::shared_ptr<Route> rp)
262 if (set_color_from_route()) {
263 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
267 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
270 delete input_selector;
273 delete output_selector;
276 mute_button->set_controllable (_route->mute_control());
277 solo_button->set_controllable (_route->solo_control());
279 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
281 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
283 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
284 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
285 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
286 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
287 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
290 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
291 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
292 track_mode_changed();
296 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
297 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
299 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
301 if (_session->writable() && is_track()) {
302 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
304 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
305 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
307 rec_enable_button->show();
308 rec_enable_button->set_controllable (t->rec_enable_control());
310 if (is_midi_track()) {
311 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
312 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
317 /* this will work for busses and tracks, and needs to be called to
318 set up the name entry/name label display.
322 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
323 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
325 update_monitoring_display ();
328 mute_button->unset_flags (Gtk::CAN_FOCUS);
329 solo_button->unset_flags (Gtk::CAN_FOCUS);
333 if (_route->is_monitor() || _route->is_master()) {
334 solo_button->hide ();
341 setup_invert_buttons ();
342 set_invert_button_state ();
344 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
345 bus_send_display_changed (s);
347 update_mute_display ();
348 update_solo_display ();
350 if (!UIConfiguration::instance().get_blink_rec_arm()) {
351 blink_rec_display(true); // set initial rec-en button state
354 check_rec_enable_sensitivity ();
355 maybe_add_route_print_mgr ();
356 route_color_changed();
357 route_gui_changed (PropertyChange (Properties::selected));
361 RouteUI::polarity_changed ()
367 set_invert_button_state ();
371 RouteUI::mute_press (GdkEventButton* ev)
373 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
377 //if this is a binding action, let the ArdourButton handle it
378 if ( BindingProxy::is_bind_action(ev) )
381 multiple_mute_change = false;
383 if (Keyboard::is_context_menu_event (ev)) {
389 mute_menu->popup(0,ev->time);
395 if (Keyboard::is_button2_event (ev)) {
396 // button2-click is "momentary"
398 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
401 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
403 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
405 /* toggle mute on everything (but
406 * exclude the master and monitor)
408 * because we are going to erase
409 * elements of the list we need to work
413 boost::shared_ptr<RouteList> copy (new RouteList);
415 *copy = *_session->get_routes ();
417 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
418 if ((*i)->is_master() || (*i)->is_monitor()) {
426 _mute_release->routes = copy;
429 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
431 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
433 /* Primary-button1 inverts the implication of
434 the group being active. If the group is
435 active (for mute), then this modifier means
436 "do not apply to mute". If the group is
437 inactive (for mute), then this modifier
438 means "apply to route". This is all
439 accomplished by passing just the actual
440 route, along with the InverseGroup group
443 NOTE: Primary-button2 is MIDI learn.
446 boost::shared_ptr<RouteList> rl;
448 if (ev->button == 1) {
450 rl.reset (new RouteList);
451 rl->push_back (_route);
454 _mute_release->routes = rl;
457 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
462 /* plain click applies change to this route */
464 boost::shared_ptr<RouteList> rl (new RouteList);
465 rl->push_back (_route);
468 _mute_release->routes = rl;
471 _route->mute_control()->set_value (!_route->muted_by_self(), Controllable::UseGroup);
480 RouteUI::mute_release (GdkEventButton* /*ev*/)
483 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
484 delete _mute_release;
492 RouteUI::edit_output_configuration ()
494 if (output_selector == 0) {
496 boost::shared_ptr<Send> send;
497 boost::shared_ptr<IO> output;
499 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
500 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
501 output = send->output();
503 output = _route->output ();
506 output = _route->output ();
509 output_selector = new IOSelectorWindow (_session, output);
512 if (output_selector->is_visible()) {
513 output_selector->get_toplevel()->get_window()->raise();
515 output_selector->present ();
518 //output_selector->set_keep_above (true);
522 RouteUI::edit_input_configuration ()
524 if (input_selector == 0) {
525 input_selector = new IOSelectorWindow (_session, _route->input());
528 if (input_selector->is_visible()) {
529 input_selector->get_toplevel()->get_window()->raise();
531 input_selector->present ();
534 //input_selector->set_keep_above (true);
538 RouteUI::solo_press(GdkEventButton* ev)
540 /* ignore double/triple clicks */
542 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
546 //if this is a binding action, let the ArdourButton handle it
547 if ( BindingProxy::is_bind_action(ev) )
550 multiple_solo_change = false;
552 if (Keyboard::is_context_menu_event (ev)) {
554 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
555 ! (solo_safe_led && solo_safe_led->is_visible())) {
557 if (solo_menu == 0) {
561 solo_menu->popup (1, ev->time);
566 if (Keyboard::is_button2_event (ev)) {
568 // button2-click is "momentary"
569 _solo_release = new SoloMuteRelease (_route->self_soloed());
572 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
574 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
576 /* Primary-Tertiary-click applies change to all routes */
579 _solo_release->routes = _session->get_routes ();
582 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
584 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
586 // Primary-Secondary-click: exclusively solo this track
589 _solo_release->exclusive = true;
591 boost::shared_ptr<RouteList> routes = _session->get_routes();
593 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
594 if ((*i)->soloed ()) {
595 _solo_release->routes_on->push_back (*i);
597 _solo_release->routes_off->push_back (*i);
602 if (Config->get_solo_control_is_listen_control()) {
603 /* ??? we need a just_one_listen() method */
606 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
609 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
611 // shift-click: toggle solo isolated status
613 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
614 delete _solo_release;
617 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
619 /* Primary-button1: solo mix group.
620 NOTE: Primary-button2 is MIDI learn.
623 /* Primary-button1 applies change to the mix group even if it is not active
624 NOTE: Primary-button2 is MIDI learn.
627 boost::shared_ptr<RouteList> rl;
629 if (ev->button == 1) {
631 /* Primary-button1 inverts the implication of
632 the group being active. If the group is
633 active (for solo), then this modifier means
634 "do not apply to solo". If the group is
635 inactive (for mute), then this modifier
636 means "apply to route". This is all
637 accomplished by passing just the actual
638 route, along with the InverseGroup group
641 NOTE: Primary-button2 is MIDI learn.
644 rl.reset (new RouteList);
645 rl->push_back (_route);
648 _solo_release->routes = rl;
651 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
654 delete _solo_release;
659 /* click: solo this route */
661 boost::shared_ptr<RouteList> rl (new RouteList);
662 rl->push_back (route());
665 _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) {
684 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
687 delete _solo_release;
695 RouteUI::rec_enable_press(GdkEventButton* ev)
697 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
701 //if this is a binding action, let the ArdourButton handle it
702 if ( BindingProxy::is_bind_action(ev) )
705 if (!_session->engine().connected()) {
706 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
711 if (is_midi_track()) {
713 /* rec-enable button exits from step editing */
715 if (midi_track()->step_editing()) {
716 midi_track()->set_step_editing (false);
721 if (is_track() && rec_enable_button) {
723 if (Keyboard::is_button2_event (ev)) {
725 //rec arm does not have a momentary mode
728 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
730 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
732 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
734 /* Primary-button1 applies change to the route group (even if it is not active)
735 NOTE: Primary-button2 is MIDI learn.
738 if (ev->button == 1) {
740 boost::shared_ptr<RouteList> rl;
742 rl.reset (new RouteList);
743 rl->push_back (_route);
745 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
748 } else if (Keyboard::is_context_menu_event (ev)) {
750 /* do this on release */
754 boost::shared_ptr<Track> trk = track();
755 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
763 RouteUI::update_monitoring_display ()
769 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
775 MonitorState ms = t->monitoring_state();
777 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
778 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
780 if (ms & MonitoringInput) {
781 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
783 monitor_input_button->unset_active_state ();
787 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
788 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
790 if (ms & MonitoringDisk) {
791 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
793 monitor_disk_button->unset_active_state ();
799 RouteUI::monitor_input_press(GdkEventButton*)
805 RouteUI::monitor_input_release(GdkEventButton* ev)
807 return monitor_release (ev, MonitorInput);
811 RouteUI::monitor_disk_press (GdkEventButton*)
817 RouteUI::monitor_disk_release (GdkEventButton* ev)
819 return monitor_release (ev, MonitorDisk);
823 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
825 if (ev->button != 1) {
829 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
836 boost::shared_ptr<RouteList> rl;
838 /* XXX for now, monitoring choices are orthogonal. cue monitoring
839 will follow in 3.X but requires mixing the input and playback (disk)
840 signal together, which requires yet more buffers.
843 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
844 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
846 /* this line will change when the options are non-orthogonal */
847 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
851 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
852 rl = _session->get_routes ();
854 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
855 if (_route->route_group() && _route->route_group()->is_monitoring()) {
856 rl = _route->route_group()->route_list();
858 rl.reset (new RouteList);
859 rl->push_back (route());
862 rl.reset (new RouteList);
863 rl->push_back (route());
866 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
872 RouteUI::build_record_menu ()
875 record_menu = new Menu;
876 record_menu->set_name ("ArdourContextMenu");
877 using namespace Menu_Helpers;
878 MenuList& items = record_menu->items();
880 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
881 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
883 if (is_midi_track()) {
884 items.push_back (SeparatorElem());
885 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
886 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
890 if (step_edit_item) {
891 if (track()->rec_enable_control()->get_value()) {
892 step_edit_item->set_sensitive (false);
894 step_edit_item->set_active (midi_track()->step_editing());
897 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
898 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
903 RouteUI::toggle_step_edit ()
905 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
909 midi_track()->set_step_editing (step_edit_item->get_active());
913 RouteUI::toggle_rec_safe ()
915 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
921 /* This check is made inside the control too, but dong it here can't
925 if (_route->rec_enable_control()->get_value()) {
929 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
933 RouteUI::step_edit_changed (bool yn)
936 if (rec_enable_button) {
937 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
940 start_step_editing ();
942 if (step_edit_item) {
943 step_edit_item->set_active (true);
948 if (rec_enable_button) {
949 rec_enable_button->unset_active_state ();
952 stop_step_editing ();
954 if (step_edit_item) {
955 step_edit_item->set_active (false);
961 RouteUI::rec_enable_release (GdkEventButton* ev)
963 if (Keyboard::is_context_menu_event (ev)) {
964 build_record_menu ();
966 record_menu->popup (1, ev->time);
975 RouteUI::build_sends_menu ()
977 using namespace Menu_Helpers;
979 sends_menu = new Menu;
980 sends_menu->set_name ("ArdourContextMenu");
981 MenuList& items = sends_menu->items();
984 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
988 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
992 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
996 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1000 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1004 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1007 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1011 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1014 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1015 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1016 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1021 RouteUI::create_sends (Placement p, bool include_buses)
1023 _session->globally_add_internal_sends (_route, p, include_buses);
1027 RouteUI::create_selected_sends (Placement p, bool include_buses)
1029 boost::shared_ptr<RouteList> rlist (new RouteList);
1030 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1032 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1033 RouteTimeAxisView* rtv;
1035 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1036 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1037 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1038 rlist->push_back (rui->route());
1044 _session->add_internal_sends (_route, p, rlist);
1048 RouteUI::set_sends_gain_from_track ()
1050 _session->globally_set_send_gains_from_track (_route);
1054 RouteUI::set_sends_gain_to_zero ()
1056 _session->globally_set_send_gains_to_zero (_route);
1060 RouteUI::set_sends_gain_to_unity ()
1062 _session->globally_set_send_gains_to_unity (_route);
1066 RouteUI::show_sends_press(GdkEventButton* ev)
1068 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1072 if (!is_track() && show_sends_button) {
1074 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1076 // do nothing on midi sigc::bind event
1079 } else if (Keyboard::is_context_menu_event (ev)) {
1081 if (sends_menu == 0) {
1082 build_sends_menu ();
1085 sends_menu->popup (0, ev->time);
1089 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1092 set_showing_sends_to (boost::shared_ptr<Route> ());
1094 set_showing_sends_to (_route);
1103 RouteUI::show_sends_release (GdkEventButton*)
1109 RouteUI::send_blink (bool onoff)
1111 if (!show_sends_button) {
1116 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1118 show_sends_button->unset_active_state ();
1122 Gtkmm2ext::ActiveState
1123 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1125 boost::shared_ptr<SoloControl> sc = s->solo_control();
1128 return Gtkmm2ext::Off;
1131 if (!sc->can_solo()) {
1132 return Gtkmm2ext::Off;
1136 if (sc->self_soloed()) {
1137 return Gtkmm2ext::ExplicitActive;
1138 } else if (sc->soloed_by_others()) {
1139 return Gtkmm2ext::ImplicitActive;
1141 return Gtkmm2ext::Off;
1145 Gtkmm2ext::ActiveState
1146 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1148 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1151 return Gtkmm2ext::Off;
1154 if (s->is_master() || s->is_monitor()) {
1155 return Gtkmm2ext::Off;
1158 if (sc->solo_isolated()) {
1159 return Gtkmm2ext::ExplicitActive;
1161 return Gtkmm2ext::Off;
1165 Gtkmm2ext::ActiveState
1166 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1168 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1171 return Gtkmm2ext::Off;
1174 if (s->is_master() || s->is_monitor()) {
1175 return Gtkmm2ext::Off;
1178 if (sc->solo_safe()) {
1179 return Gtkmm2ext::ExplicitActive;
1181 return Gtkmm2ext::Off;
1186 RouteUI::update_solo_display ()
1188 bool yn = _route->solo_safe_control()->solo_safe ();
1190 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1191 solo_safe_check->set_active (yn);
1194 yn = _route->solo_isolate_control()->solo_isolated ();
1196 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1197 solo_isolated_check->set_active (yn);
1200 set_button_names ();
1202 if (solo_isolated_led) {
1203 if (_route->solo_isolate_control()->solo_isolated()) {
1204 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1206 solo_isolated_led->unset_active_state ();
1210 if (solo_safe_led) {
1211 if (_route->solo_safe_control()->solo_safe()) {
1212 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1214 solo_safe_led->unset_active_state ();
1218 solo_button->set_active_state (solo_active_state (_route));
1220 /* some changes to solo status can affect mute display, so catch up
1223 update_mute_display ();
1227 RouteUI::solo_changed_so_update_mute ()
1229 update_mute_display ();
1233 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1235 boost::shared_ptr<MuteControl> mc = s->mute_control();
1237 if (s->is_monitor()) {
1238 return Gtkmm2ext::Off;
1242 return Gtkmm2ext::Off;
1245 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1247 if (mc->muted_by_self ()) {
1249 return Gtkmm2ext::ExplicitActive;
1250 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1251 /* this will reflect both solo mutes AND master mutes */
1252 return Gtkmm2ext::ImplicitActive;
1254 /* no mute at all */
1255 return Gtkmm2ext::Off;
1260 if (mc->muted_by_self()) {
1262 return Gtkmm2ext::ExplicitActive;
1263 } else if (mc->muted_by_masters ()) {
1264 /* this shows only master mutes, not mute-by-others-soloing */
1265 return Gtkmm2ext::ImplicitActive;
1267 /* no mute at all */
1268 return Gtkmm2ext::Off;
1272 return ActiveState(0);
1276 RouteUI::update_mute_display ()
1282 mute_button->set_active_state (mute_active_state (_session, _route));
1287 RouteUI::route_rec_enable_changed ()
1289 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1293 RouteUI::session_rec_enable_changed ()
1295 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1299 RouteUI::blink_rec_display (bool blinkOn)
1301 if (!rec_enable_button || !_route) {
1305 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1313 if (track()->rec_enable_control()->get_value()) {
1314 switch (_session->record_status ()) {
1315 case Session::Recording:
1316 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1319 case Session::Disabled:
1320 case Session::Enabled:
1321 if (UIConfiguration::instance().get_blink_rec_arm()) {
1322 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1324 rec_enable_button->set_active_state ( ImplicitActive );
1329 if (step_edit_item) {
1330 step_edit_item->set_sensitive (false);
1334 rec_enable_button->unset_active_state ();
1336 if (step_edit_item) {
1337 step_edit_item->set_sensitive (true);
1341 check_rec_enable_sensitivity ();
1345 RouteUI::build_solo_menu (void)
1347 using namespace Menu_Helpers;
1349 solo_menu = new Menu;
1350 solo_menu->set_name ("ArdourContextMenu");
1351 MenuList& items = solo_menu->items();
1352 Gtk::CheckMenuItem* check;
1354 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1355 check->set_active (_route->solo_isolate_control()->solo_isolated());
1356 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1357 items.push_back (CheckMenuElem(*check));
1358 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1361 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1362 check->set_active (_route->solo_safe_control()->solo_safe());
1363 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1364 items.push_back (CheckMenuElem(*check));
1365 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1368 //items.push_back (SeparatorElem());
1369 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1374 RouteUI::build_mute_menu(void)
1376 using namespace Menu_Helpers;
1378 mute_menu = new Menu;
1379 mute_menu->set_name ("ArdourContextMenu");
1381 MenuList& items = mute_menu->items();
1383 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1384 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1385 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1386 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1387 pre_fader_mute_check->show_all();
1389 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1390 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1391 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1392 items.push_back (CheckMenuElem(*post_fader_mute_check));
1393 post_fader_mute_check->show_all();
1395 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1396 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1397 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1398 items.push_back (CheckMenuElem(*listen_mute_check));
1399 listen_mute_check->show_all();
1401 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1402 init_mute_menu(MuteMaster::Main, main_mute_check);
1403 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1404 items.push_back (CheckMenuElem(*main_mute_check));
1405 main_mute_check->show_all();
1407 //items.push_back (SeparatorElem());
1408 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1410 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1414 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1416 check->set_active (_route->mute_control()->mute_points() & mp);
1420 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1422 if (check->get_active()) {
1423 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1425 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1430 RouteUI::muting_change ()
1432 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1435 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1437 yn = (current & MuteMaster::PreFader);
1439 if (pre_fader_mute_check->get_active() != yn) {
1440 pre_fader_mute_check->set_active (yn);
1443 yn = (current & MuteMaster::PostFader);
1445 if (post_fader_mute_check->get_active() != yn) {
1446 post_fader_mute_check->set_active (yn);
1449 yn = (current & MuteMaster::Listen);
1451 if (listen_mute_check->get_active() != yn) {
1452 listen_mute_check->set_active (yn);
1455 yn = (current & MuteMaster::Main);
1457 if (main_mute_check->get_active() != yn) {
1458 main_mute_check->set_active (yn);
1463 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1465 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1469 bool view = solo_isolated_led->active_state();
1470 bool model = _route->solo_isolate_control()->solo_isolated();
1472 /* called BEFORE the view has changed */
1474 if (ev->button == 1) {
1475 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1478 /* disable isolate for all routes */
1479 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1481 /* enable isolate for all routes */
1482 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1487 if (model == view) {
1489 /* flip just this route */
1491 boost::shared_ptr<RouteList> rl (new RouteList);
1492 rl->push_back (_route);
1493 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1502 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1504 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1508 bool view = solo_safe_led->active_state();
1509 bool model = _route->solo_safe_control()->solo_safe();
1511 if (ev->button == 1) {
1512 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1513 boost::shared_ptr<RouteList> rl (_session->get_routes());
1515 /* disable solo safe for all routes */
1516 DisplaySuspender ds;
1517 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1518 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1521 /* enable solo safe for all routes */
1522 DisplaySuspender ds;
1523 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1524 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1529 if (model == view) {
1530 /* flip just this route */
1531 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1540 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1542 bool view = check->get_active();
1543 bool model = _route->solo_isolate_control()->solo_isolated();
1545 /* called AFTER the view has changed */
1547 if (model != view) {
1548 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1553 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1555 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1558 /** Ask the user to choose a colour, and then apply that color to my route
1561 RouteUI::choose_color ()
1564 Gdk::Color c (gdk_color_from_rgb (_route->presentation_info().color()));
1565 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1568 set_color (gdk_color_to_rgba (color));
1572 /** Set the route's own color. This may not be used for display if
1573 * the route is in a group which shares its color with its routes.
1576 RouteUI::set_color (uint32_t c)
1578 _route->presentation_info().set_color (c);
1581 /** @return GUI state ID for things that are common to the route in all its representations */
1583 RouteUI::route_state_id () const
1585 return string_compose (X_("route %1"), _route->id().to_s());
1589 RouteUI::set_color_from_route ()
1591 if (_route->presentation_info().color_set()) {
1592 return 0; /* nothing to do */
1595 return 1; /* pick a color */
1598 /** @return true if this name should be used for the route, otherwise false */
1600 RouteUI::verify_new_route_name (const std::string& name)
1602 if (name.find (':') == string::npos) {
1606 MessageDialog colon_msg (
1607 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1608 false, MESSAGE_QUESTION, BUTTONS_NONE
1611 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1612 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1614 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1618 RouteUI::route_rename ()
1620 ArdourPrompter name_prompter (true);
1625 name_prompter.set_title (_("Rename Track"));
1627 name_prompter.set_title (_("Rename Bus"));
1629 name_prompter.set_prompt (_("New name:"));
1630 name_prompter.set_initial_text (_route->name());
1631 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1632 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1633 name_prompter.show_all ();
1636 switch (name_prompter.run ()) {
1637 case Gtk::RESPONSE_ACCEPT:
1638 name_prompter.get_result (result);
1639 name_prompter.hide ();
1640 if (result.length()) {
1641 if (verify_new_route_name (result)) {
1642 _route->set_name (result);
1645 /* back to name prompter */
1649 /* nothing entered, just get out of here */
1664 RouteUI::toggle_comment_editor ()
1666 // if (ignore_toggle) {
1670 if (comment_window && comment_window->is_visible ()) {
1671 comment_window->hide ();
1673 open_comment_editor ();
1679 RouteUI::open_comment_editor ()
1681 if (comment_window == 0) {
1682 setup_comment_editor ();
1686 title = _route->name();
1687 title += _(": comment editor");
1689 comment_window->set_title (title);
1690 comment_window->present();
1694 RouteUI::setup_comment_editor ()
1696 comment_window = new ArdourWindow (""); // title will be reset to show route
1697 comment_window->set_skip_taskbar_hint (true);
1698 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1699 comment_window->set_default_size (400, 200);
1701 comment_area = manage (new TextView());
1702 comment_area->set_name ("MixerTrackCommentArea");
1703 comment_area->set_wrap_mode (WRAP_WORD);
1704 comment_area->set_editable (true);
1705 comment_area->get_buffer()->set_text (_route->comment());
1706 comment_area->show ();
1708 comment_window->add (*comment_area);
1712 RouteUI::comment_changed ()
1714 ignore_comment_edit = true;
1716 comment_area->get_buffer()->set_text (_route->comment());
1718 ignore_comment_edit = false;
1722 RouteUI::comment_editor_done_editing ()
1724 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1726 string const str = comment_area->get_buffer()->get_text();
1727 if (str == _route->comment ()) {
1731 _route->set_comment (str, this);
1735 RouteUI::set_route_active (bool a, bool apply_to_selection)
1737 if (apply_to_selection) {
1738 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1740 _route->set_active (a, this);
1745 RouteUI::duplicate_selected_routes ()
1747 ARDOUR_UI::instance()->start_duplicate_routes();
1751 RouteUI::toggle_denormal_protection ()
1753 if (denormal_menu_item) {
1757 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1759 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1760 _route->set_denormal_protection (x);
1766 RouteUI::denormal_protection_changed ()
1768 if (denormal_menu_item) {
1769 denormal_menu_item->set_active (_route->denormal_protection());
1774 RouteUI::disconnect_input ()
1776 _route->input()->disconnect (this);
1780 RouteUI::disconnect_output ()
1782 _route->output()->disconnect (this);
1786 RouteUI::is_track () const
1788 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1791 boost::shared_ptr<Track>
1792 RouteUI::track() const
1794 return boost::dynamic_pointer_cast<Track>(_route);
1798 RouteUI::is_audio_track () const
1800 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1803 boost::shared_ptr<AudioTrack>
1804 RouteUI::audio_track() const
1806 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1810 RouteUI::is_midi_track () const
1812 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1815 boost::shared_ptr<MidiTrack>
1816 RouteUI::midi_track() const
1818 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1822 RouteUI::has_audio_outputs () const
1824 return (_route->n_outputs().n_audio() > 0);
1828 RouteUI::map_frozen ()
1830 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1832 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1835 check_rec_enable_sensitivity ();
1840 RouteUI::adjust_latency ()
1842 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1846 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1849 std::string safe_name;
1852 prompter.get_result (name, true);
1854 safe_name = legalize_for_path (name);
1855 safe_name += template_suffix;
1857 path = Glib::build_filename (dir, safe_name);
1859 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1860 bool overwrite = overwrite_file_dialog (prompter,
1861 _("Confirm Template Overwrite"),
1862 _("A template already exists with that name. Do you want to overwrite it?"));
1869 _route->save_as_template (path, name);
1875 RouteUI::save_as_template ()
1879 dir = ARDOUR::user_route_template_directory ();
1881 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1882 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1886 ArdourPrompter prompter (true); // modal
1888 prompter.set_title (_("Save As Template"));
1889 prompter.set_prompt (_("Template name:"));
1890 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1892 bool finished = false;
1894 switch (prompter.run()) {
1895 case RESPONSE_ACCEPT:
1896 finished = process_save_template_prompter (prompter, dir);
1906 RouteUI::check_rec_enable_sensitivity ()
1908 if (!rec_enable_button) {
1909 assert (0); // This should not happen
1912 if (!_session->writable()) {
1913 rec_enable_button->set_sensitive (false);
1917 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1918 rec_enable_button->set_sensitive (false);
1919 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1920 rec_enable_button->set_sensitive (false);
1922 rec_enable_button->set_sensitive (true);
1924 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1925 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1927 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1929 update_monitoring_display ();
1933 RouteUI::parameter_changed (string const & p)
1935 /* this handles RC and per-session parameter changes */
1937 if (p == "disable-disarm-during-roll") {
1938 check_rec_enable_sensitivity ();
1939 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1940 set_button_names ();
1941 } else if (p == "auto-input") {
1942 update_monitoring_display ();
1943 } else if (p == "blink-rec-arm") {
1944 if (UIConfiguration::instance().get_blink_rec_arm()) {
1945 rec_blink_connection.disconnect ();
1946 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1948 rec_blink_connection.disconnect ();
1949 RouteUI::blink_rec_display(false);
1955 RouteUI::step_gain_up ()
1957 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1961 RouteUI::page_gain_up ()
1963 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1967 RouteUI::step_gain_down ()
1969 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1973 RouteUI::page_gain_down ()
1975 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1979 RouteUI::setup_invert_buttons ()
1981 /* remove old invert buttons */
1982 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1983 _invert_button_box.remove (**i);
1986 _invert_buttons.clear ();
1988 if (!_route || !_route->input()) {
1992 uint32_t const N = _route->input()->n_ports().n_audio ();
1994 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1996 for (uint32_t i = 0; i < to_add; ++i) {
1997 ArdourButton* b = manage (new ArdourButton);
1998 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
1999 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2001 b->set_name (X_("invert button"));
2004 b->set_text (string_compose (X_("Ø (%1)"), N));
2006 b->set_text (X_("Ø"));
2009 b->set_text (string_compose (X_("Ø%1"), i + 1));
2012 if (N <= _max_invert_buttons) {
2013 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));
2015 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2018 _invert_buttons.push_back (b);
2019 _invert_button_box.pack_start (*b);
2022 _invert_button_box.set_spacing (1);
2023 _invert_button_box.show_all ();
2027 RouteUI::set_invert_button_state ()
2029 uint32_t const N = _route->input()->n_ports().n_audio();
2030 if (N > _max_invert_buttons) {
2032 /* One button for many channels; explicit active if all channels are inverted,
2033 implicit active if some are, off if none are.
2036 ArdourButton* b = _invert_buttons.front ();
2038 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2039 b->set_active_state (Gtkmm2ext::ExplicitActive);
2040 } else if (_route->phase_control()->any()) {
2041 b->set_active_state (Gtkmm2ext::ImplicitActive);
2043 b->set_active_state (Gtkmm2ext::Off);
2048 /* One button per channel; just set active */
2051 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2052 (*i)->set_active (_route->phase_control()->inverted (j));
2059 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2061 if (ev->button == 1 && i < _invert_buttons.size()) {
2062 uint32_t const N = _route->input()->n_ports().n_audio ();
2063 if (N <= _max_invert_buttons) {
2064 /* left-click inverts phase so long as we have a button per channel */
2065 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2074 RouteUI::invert_press (GdkEventButton* ev)
2076 using namespace Menu_Helpers;
2078 uint32_t const N = _route->input()->n_ports().n_audio();
2079 if (N <= _max_invert_buttons && ev->button != 3) {
2080 /* If we have an invert button per channel, we only pop
2081 up a menu on right-click; left click is handled
2087 delete _invert_menu;
2088 _invert_menu = new Menu;
2089 _invert_menu->set_name ("ArdourContextMenu");
2090 MenuList& items = _invert_menu->items ();
2092 for (uint32_t i = 0; i < N; ++i) {
2093 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2094 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2095 ++_i_am_the_modifier;
2096 e->set_active (_route->phase_control()->inverted (i));
2097 --_i_am_the_modifier;
2100 _invert_menu->popup (0, ev->time);
2106 RouteUI::invert_menu_toggled (uint32_t c)
2108 if (_i_am_the_modifier) {
2113 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2117 RouteUI::set_invert_sensitive (bool yn)
2119 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2120 (*b)->set_sensitive (yn);
2125 RouteUI::request_redraw ()
2128 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2132 /** The Route's gui_changed signal has been emitted */
2134 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2136 if (what_changed.contains (Properties::color)) {
2137 if (set_color_from_route () == 0) {
2138 route_color_changed ();
2144 RouteUI::track_mode_changed (void)
2147 switch (track()->mode()) {
2148 case ARDOUR::NonLayered:
2149 case ARDOUR::Normal:
2150 rec_enable_button->set_icon (ArdourIcon::RecButton);
2152 case ARDOUR::Destructive:
2153 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2156 rec_enable_button->queue_draw();
2159 /** @return the color that this route should use; it maybe its own,
2160 or it maybe that of its route group.
2164 RouteUI::route_color () const
2167 RouteGroup* g = _route->route_group ();
2170 if (g && g->is_color()) {
2171 set_color_from_rgba (c, GroupTabs::group_color (g));
2174 /* deal with older 4.x color, which was stored in the GUI object state */
2176 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2180 /* old v4.x or earlier session. Use this information */
2182 int red, green, blue;
2185 stringstream ss (p);
2187 /* old color format version was:
2189 16bit value for red:16 bit value for green:16 bit value for blue
2204 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
2207 set_color_from_rgba (c, _route->presentation_info().color());
2214 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2216 _showing_sends_to = send_to;
2217 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2221 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2223 if (_route == send_to) {
2224 show_sends_button->set_active (true);
2225 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2227 show_sends_button->set_active (false);
2228 send_blink_connection.disconnect ();
2233 RouteUI::route_group() const
2235 return _route->route_group();
2239 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2240 : WM::ProxyBase (name, string())
2241 , _route (boost::weak_ptr<Route> (route))
2243 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2246 RoutePinWindowProxy::~RoutePinWindowProxy()
2251 ARDOUR::SessionHandlePtr*
2252 RoutePinWindowProxy::session_handle ()
2254 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2255 if (aw) { return aw; }
2260 RoutePinWindowProxy::get (bool create)
2262 boost::shared_ptr<Route> r = _route.lock ();
2271 _window = new PluginPinDialog (r);
2272 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2274 aw->set_session (_session);
2276 _window->show_all ();
2282 RoutePinWindowProxy::route_going_away ()
2286 WM::Manager::instance().remove (this);
2287 going_away_connection.disconnect();
2291 RouteUI::maybe_add_route_print_mgr ()
2293 if (_route->pinmgr_proxy ()) {
2296 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2297 string_compose ("RPM-%1", _route->id()), _route);
2298 wp->set_session (_session);
2300 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2302 wp->set_state (*ui_xml, 0);
2306 void* existing_ui = _route->pinmgr_proxy ();
2308 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2311 _route->set_pingmgr_proxy (wp);
2313 WM::Manager::instance().register_window (wp);
2317 RouteUI::manage_pins ()
2319 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2327 RouteUI::fan_out (bool to_busses, bool group)
2329 DisplaySuspender ds;
2330 boost::shared_ptr<ARDOUR::Route> route = _route;
2331 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2334 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2335 if (route->n_outputs ().n_audio () != n_outputs) {
2336 MessageDialog msg (string_compose (
2337 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2338 n_outputs, route->n_outputs ().n_audio ()));
2343 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2345 /* count busses and channels/bus */
2346 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2347 std::map<std::string, uint32_t> busnames;
2348 for (uint32_t p = 0; p < n_outputs; ++p) {
2349 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2350 std::string bn = BUSNAME;
2354 if (busnames.size () < 2) {
2355 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2360 uint32_t outputs = 2;
2361 if (_session->master_out ()) {
2362 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2365 route->output ()->disconnect (this);
2366 route->panner_shell ()->set_bypassed (true);
2369 for (uint32_t p = 0; p < n_outputs; ++p) {
2370 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2371 std::string bn = BUSNAME;
2372 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2375 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2379 list<boost::shared_ptr<AudioTrack> > tl =
2380 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2384 boost::shared_ptr<ControlList> cl (new ControlList);
2385 cl->push_back (r->monitoring_control ());
2386 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2388 r->input ()->disconnect (this);
2390 to_group.push_back (r);
2391 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2396 RouteGroup* rg = NULL;
2397 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2398 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2399 if ((*i)->name () == pi->name ()) {
2405 rg = new RouteGroup (*_session, pi->name ());
2406 _session->add_route_group (rg);
2407 rg->set_gain (false);
2410 GroupTabs::set_group_color (rg, route->presentation_info().color());
2411 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2418 RouteUI::mark_hidden (bool yn)
2420 if (yn != _route->presentation_info().hidden()) {
2421 _route->presentation_info().set_hidden (yn);
2422 return true; // things changed
2427 boost::shared_ptr<Stripable>
2428 RouteUI::stripable () const