2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <boost/algorithm/string.hpp>
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
35 #include "ardour/dB.h"
36 #include "ardour/route_group.h"
37 #include "ardour/solo_isolate_control.h"
38 #include "ardour/vca.h"
39 #include "ardour/vca_manager.h"
40 #include "ardour/audio_track.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/filename_extensions.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/monitor_control.h"
45 #include "ardour/internal_send.h"
46 #include "ardour/profile.h"
47 #include "ardour/phase_control.h"
48 #include "ardour/send.h"
49 #include "ardour/route.h"
50 #include "ardour/session.h"
51 #include "ardour/template_utils.h"
53 #include "ardour_button.h"
54 #include "ardour_dialog.h"
55 #include "ardour_ui.h"
56 #include "automation_time_axis.h"
58 #include "group_tabs.h"
59 #include "gui_object.h"
60 #include "gui_thread.h"
62 #include "latency_gui.h"
63 #include "mixer_strip.h"
64 #include "plugin_pin_dialog.h"
66 #include "rgb_macros.h"
67 #include "route_time_axis.h"
70 #include "ui_config.h"
76 using namespace Gtkmm2ext;
77 using namespace ARDOUR;
78 using namespace ARDOUR_UI_UTILS;
82 uint32_t RouteUI::_max_invert_buttons = 3;
83 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
84 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
85 std::string RouteUI::program_port_prefix;
87 RouteUI::RouteUI (ARDOUR::Session* sess)
88 : monitor_input_button (0)
89 , monitor_disk_button (0)
100 if (program_port_prefix.empty()) {
101 // compare to gtk2_ardour/port_group.cc
102 string lpn (PROGRAM_NAME);
103 boost::to_lower (lpn);
104 program_port_prefix = lpn + ":"; // e.g. "ardour:"
115 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
118 _route.reset (); /* drop reference to route, so that it can be cleaned up */
119 route_connections.drop_connections ();
125 delete comment_window;
126 delete input_selector;
127 delete output_selector;
128 delete monitor_input_button;
129 delete monitor_disk_button;
132 send_blink_connection.disconnect ();
133 rec_blink_connection.disconnect ();
139 self_destruct = true;
145 pre_fader_mute_check = 0;
146 post_fader_mute_check = 0;
147 listen_mute_check = 0;
150 solo_isolated_check = 0;
151 solo_isolated_led = 0;
155 denormal_menu_item = 0;
158 multiple_mute_change = false;
159 multiple_solo_change = false;
160 _i_am_the_modifier = 0;
165 setup_invert_buttons ();
167 mute_button = manage (new ArdourButton);
168 mute_button->set_name ("mute button");
169 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
171 solo_button = manage (new ArdourButton);
172 solo_button->set_name ("solo button");
173 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
174 solo_button->set_no_show_all (true);
176 rec_enable_button = manage (new ArdourButton);
177 rec_enable_button->set_name ("record enable button");
178 rec_enable_button->set_icon (ArdourIcon::RecButton);
179 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
181 if (UIConfiguration::instance().get_blink_rec_arm()) {
182 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
185 show_sends_button = manage (new ArdourButton);
186 show_sends_button->set_name ("send alert button");
187 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
189 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
190 monitor_input_button->set_name ("monitor button");
191 monitor_input_button->set_text (_("In"));
192 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
193 monitor_input_button->set_no_show_all (true);
195 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
196 monitor_disk_button->set_name ("monitor button");
197 monitor_disk_button->set_text (_("Disk"));
198 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
199 monitor_disk_button->set_no_show_all (true);
201 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
202 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
203 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
205 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
206 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
207 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
209 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
210 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
212 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
213 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
215 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
216 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
217 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
218 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
220 monitor_input_button->set_distinct_led_click (false);
221 monitor_disk_button->set_distinct_led_click (false);
223 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
224 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
226 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
227 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
229 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
235 route_connections.drop_connections ();
243 denormal_menu_item = 0;
247 RouteUI::self_delete ()
253 RouteUI::set_route (boost::shared_ptr<Route> rp)
259 if (set_color_from_route()) {
260 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
264 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
267 delete input_selector;
270 delete output_selector;
273 mute_button->set_controllable (_route->mute_control());
274 solo_button->set_controllable (_route->solo_control());
276 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
278 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
280 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
281 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
282 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
283 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
284 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
287 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
288 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
289 track_mode_changed();
293 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
294 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
296 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
298 if (_session->writable() && is_track()) {
299 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
301 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
302 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
304 rec_enable_button->show();
305 rec_enable_button->set_controllable (t->rec_enable_control());
307 if (is_midi_track()) {
308 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
309 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
314 /* this will work for busses and tracks, and needs to be called to
315 set up the name entry/name label display.
319 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
320 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
322 update_monitoring_display ();
325 mute_button->unset_flags (Gtk::CAN_FOCUS);
326 solo_button->unset_flags (Gtk::CAN_FOCUS);
330 if (_route->is_monitor() || _route->is_master()) {
331 solo_button->hide ();
338 setup_invert_buttons ();
339 set_invert_button_state ();
341 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
342 bus_send_display_changed (s);
344 update_mute_display ();
345 update_solo_display ();
347 if (!UIConfiguration::instance().get_blink_rec_arm()) {
348 blink_rec_display(true); // set initial rec-en button state
351 check_rec_enable_sensitivity ();
352 maybe_add_route_print_mgr ();
353 route_color_changed();
354 route_gui_changed (PropertyChange (Properties::selected));
358 RouteUI::polarity_changed ()
364 set_invert_button_state ();
368 RouteUI::mute_press (GdkEventButton* ev)
370 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
374 //if this is a binding action, let the ArdourButton handle it
375 if ( BindingProxy::is_bind_action(ev) )
378 multiple_mute_change = false;
380 if (Keyboard::is_context_menu_event (ev)) {
386 mute_menu->popup(0,ev->time);
392 if (Keyboard::is_button2_event (ev)) {
393 // button2-click is "momentary"
395 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
398 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
400 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
402 /* toggle mute on everything (but
403 * exclude the master and monitor)
405 * because we are going to erase
406 * elements of the list we need to work
410 boost::shared_ptr<RouteList> copy (new RouteList);
412 *copy = *_session->get_routes ();
414 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
415 if ((*i)->is_master() || (*i)->is_monitor()) {
423 _mute_release->routes = copy;
427 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
429 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
431 /* Primary-button1 inverts the implication of
432 the group being active. If the group is
433 active (for mute), then this modifier means
434 "do not apply to mute". If the group is
435 inactive (for mute), then this modifier
436 means "apply to route". This is all
437 accomplished by passing just the actual
438 route, along with the InverseGroup group
441 NOTE: Primary-button2 is MIDI learn.
444 boost::shared_ptr<RouteList> rl;
446 if (ev->button == 1) {
448 rl.reset (new RouteList);
449 rl->push_back (_route);
452 _mute_release->routes = rl;
456 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
461 /* plain click applies change to this route */
463 boost::shared_ptr<RouteList> rl (new RouteList);
464 rl->push_back (_route);
467 _mute_release->routes = rl;
470 _route->mute_control()->set_value (!_route->muted_by_self(), Controllable::UseGroup);
479 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 ();
583 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
585 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
587 // Primary-Secondary-click: exclusively solo this track
590 _solo_release->exclusive = true;
592 boost::shared_ptr<RouteList> routes = _session->get_routes();
594 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
595 if ((*i)->soloed ()) {
596 _solo_release->routes_on->push_back (*i);
598 _solo_release->routes_off->push_back (*i);
603 if (Config->get_solo_control_is_listen_control()) {
604 /* ??? we need a just_one_listen() method */
607 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
610 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
612 // shift-click: toggle solo isolated status
614 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
615 delete _solo_release;
618 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
620 /* Primary-button1: solo mix group.
621 NOTE: Primary-button2 is MIDI learn.
624 /* Primary-button1 applies change to the mix group even if it is not active
625 NOTE: Primary-button2 is MIDI learn.
628 boost::shared_ptr<RouteList> rl;
630 if (ev->button == 1) {
632 /* Primary-button1 inverts the implication of
633 the group being active. If the group is
634 active (for solo), then this modifier means
635 "do not apply to solo". If the group is
636 inactive (for mute), then this modifier
637 means "apply to route". This is all
638 accomplished by passing just the actual
639 route, along with the InverseGroup group
642 NOTE: Primary-button2 is MIDI learn.
645 rl.reset (new RouteList);
646 rl->push_back (_route);
649 _solo_release->routes = rl;
654 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
657 delete _solo_release;
662 /* click: solo this route */
664 boost::shared_ptr<RouteList> rl (new RouteList);
665 rl->push_back (route());
668 _solo_release->routes = rl;
672 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
681 RouteUI::solo_release (GdkEventButton* /*ev*/)
685 if (_solo_release->exclusive) {
689 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
692 delete _solo_release;
700 RouteUI::rec_enable_press(GdkEventButton* ev)
702 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
706 //if this is a binding action, let the ArdourButton handle it
707 if ( BindingProxy::is_bind_action(ev) )
710 if (!_session->engine().connected()) {
711 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
716 if (is_midi_track()) {
718 /* rec-enable button exits from step editing */
720 if (midi_track()->step_editing()) {
721 midi_track()->set_step_editing (false);
726 if (is_track() && rec_enable_button) {
728 if (Keyboard::is_button2_event (ev)) {
730 //rec arm does not have a momentary mode
733 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
736 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
738 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
740 /* Primary-button1 applies change to the route group (even if it is not active)
741 NOTE: Primary-button2 is MIDI learn.
744 if (ev->button == 1) {
746 boost::shared_ptr<RouteList> rl;
748 rl.reset (new RouteList);
749 rl->push_back (_route);
752 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
755 } else if (Keyboard::is_context_menu_event (ev)) {
757 /* do this on release */
761 boost::shared_ptr<Track> trk = track();
762 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
770 RouteUI::update_monitoring_display ()
776 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
782 MonitorState ms = t->monitoring_state();
784 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
785 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
787 if (ms & MonitoringInput) {
788 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
790 monitor_input_button->unset_active_state ();
794 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
795 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
797 if (ms & MonitoringDisk) {
798 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
800 monitor_disk_button->unset_active_state ();
806 RouteUI::monitor_input_press(GdkEventButton*)
812 RouteUI::monitor_input_release(GdkEventButton* ev)
814 return monitor_release (ev, MonitorInput);
818 RouteUI::monitor_disk_press (GdkEventButton*)
824 RouteUI::monitor_disk_release (GdkEventButton* ev)
826 return monitor_release (ev, MonitorDisk);
830 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
832 if (ev->button != 1) {
836 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
843 boost::shared_ptr<RouteList> rl;
845 /* XXX for now, monitoring choices are orthogonal. cue monitoring
846 will follow in 3.X but requires mixing the input and playback (disk)
847 signal together, which requires yet more buffers.
850 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
851 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
853 /* this line will change when the options are non-orthogonal */
854 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
858 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
859 rl = _session->get_routes ();
861 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
862 if (_route->route_group() && _route->route_group()->is_monitoring()) {
863 rl = _route->route_group()->route_list();
865 rl.reset (new RouteList);
866 rl->push_back (route());
869 rl.reset (new RouteList);
870 rl->push_back (route());
874 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
880 RouteUI::build_record_menu ()
883 record_menu = new Menu;
884 record_menu->set_name ("ArdourContextMenu");
885 using namespace Menu_Helpers;
886 MenuList& items = record_menu->items();
888 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
889 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
891 if (is_midi_track()) {
892 items.push_back (SeparatorElem());
893 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
894 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
898 if (step_edit_item) {
899 if (track()->rec_enable_control()->get_value()) {
900 step_edit_item->set_sensitive (false);
902 step_edit_item->set_active (midi_track()->step_editing());
905 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
906 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
911 RouteUI::toggle_step_edit ()
913 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
917 midi_track()->set_step_editing (step_edit_item->get_active());
921 RouteUI::toggle_rec_safe ()
923 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
929 /* This check is made inside the control too, but dong it here can't
933 if (_route->rec_enable_control()->get_value()) {
937 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
941 RouteUI::step_edit_changed (bool yn)
944 if (rec_enable_button) {
945 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
948 start_step_editing ();
950 if (step_edit_item) {
951 step_edit_item->set_active (true);
956 if (rec_enable_button) {
957 rec_enable_button->unset_active_state ();
960 stop_step_editing ();
962 if (step_edit_item) {
963 step_edit_item->set_active (false);
969 RouteUI::rec_enable_release (GdkEventButton* ev)
971 if (Keyboard::is_context_menu_event (ev)) {
972 build_record_menu ();
974 record_menu->popup (1, ev->time);
983 RouteUI::build_sends_menu ()
985 using namespace Menu_Helpers;
987 sends_menu = new Menu;
988 sends_menu->set_name ("ArdourContextMenu");
989 MenuList& items = sends_menu->items();
992 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
996 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1000 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1004 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1008 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1012 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1015 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1019 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1022 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1023 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1024 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1029 RouteUI::create_sends (Placement p, bool include_buses)
1031 _session->globally_add_internal_sends (_route, p, include_buses);
1035 RouteUI::create_selected_sends (Placement p, bool include_buses)
1037 boost::shared_ptr<RouteList> rlist (new RouteList);
1038 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1040 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1041 RouteTimeAxisView* rtv;
1043 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1044 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1045 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1046 rlist->push_back (rui->route());
1052 _session->add_internal_sends (_route, p, rlist);
1056 RouteUI::set_sends_gain_from_track ()
1058 _session->globally_set_send_gains_from_track (_route);
1062 RouteUI::set_sends_gain_to_zero ()
1064 _session->globally_set_send_gains_to_zero (_route);
1068 RouteUI::set_sends_gain_to_unity ()
1070 _session->globally_set_send_gains_to_unity (_route);
1074 RouteUI::show_sends_press(GdkEventButton* ev)
1076 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1080 if (!is_track() && show_sends_button) {
1082 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1084 // do nothing on midi sigc::bind event
1087 } else if (Keyboard::is_context_menu_event (ev)) {
1089 if (sends_menu == 0) {
1090 build_sends_menu ();
1093 sends_menu->popup (0, ev->time);
1097 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1100 set_showing_sends_to (boost::shared_ptr<Route> ());
1102 set_showing_sends_to (_route);
1111 RouteUI::show_sends_release (GdkEventButton*)
1117 RouteUI::send_blink (bool onoff)
1119 if (!show_sends_button) {
1124 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1126 show_sends_button->unset_active_state ();
1130 Gtkmm2ext::ActiveState
1131 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1133 boost::shared_ptr<SoloControl> sc = s->solo_control();
1136 return Gtkmm2ext::Off;
1139 if (!sc->can_solo()) {
1140 return Gtkmm2ext::Off;
1144 if (sc->self_soloed()) {
1145 return Gtkmm2ext::ExplicitActive;
1146 } else if (sc->soloed_by_others()) {
1147 return Gtkmm2ext::ImplicitActive;
1149 return Gtkmm2ext::Off;
1153 Gtkmm2ext::ActiveState
1154 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1156 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1159 return Gtkmm2ext::Off;
1162 if (s->is_master() || s->is_monitor()) {
1163 return Gtkmm2ext::Off;
1166 if (sc->solo_isolated()) {
1167 return Gtkmm2ext::ExplicitActive;
1169 return Gtkmm2ext::Off;
1173 Gtkmm2ext::ActiveState
1174 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1176 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1179 return Gtkmm2ext::Off;
1182 if (s->is_master() || s->is_monitor()) {
1183 return Gtkmm2ext::Off;
1186 if (sc->solo_safe()) {
1187 return Gtkmm2ext::ExplicitActive;
1189 return Gtkmm2ext::Off;
1194 RouteUI::update_solo_display ()
1196 bool yn = _route->solo_safe_control()->solo_safe ();
1198 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1199 solo_safe_check->set_active (yn);
1202 yn = _route->solo_isolate_control()->solo_isolated ();
1204 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1205 solo_isolated_check->set_active (yn);
1208 set_button_names ();
1210 if (solo_isolated_led) {
1211 if (_route->solo_isolate_control()->solo_isolated()) {
1212 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1214 solo_isolated_led->unset_active_state ();
1218 if (solo_safe_led) {
1219 if (_route->solo_safe_control()->solo_safe()) {
1220 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1222 solo_safe_led->unset_active_state ();
1226 solo_button->set_active_state (solo_active_state (_route));
1228 /* some changes to solo status can affect mute display, so catch up
1231 update_mute_display ();
1235 RouteUI::solo_changed_so_update_mute ()
1237 update_mute_display ();
1241 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1243 boost::shared_ptr<MuteControl> mc = s->mute_control();
1245 if (s->is_monitor()) {
1246 return Gtkmm2ext::Off;
1250 return Gtkmm2ext::Off;
1253 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1255 if (mc->muted_by_self ()) {
1257 return Gtkmm2ext::ExplicitActive;
1258 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1259 /* this will reflect both solo mutes AND master mutes */
1260 return Gtkmm2ext::ImplicitActive;
1262 /* no mute at all */
1263 return Gtkmm2ext::Off;
1268 if (mc->muted_by_self()) {
1270 return Gtkmm2ext::ExplicitActive;
1271 } else if (mc->muted_by_masters ()) {
1272 /* this shows only master mutes, not mute-by-others-soloing */
1273 return Gtkmm2ext::ImplicitActive;
1275 /* no mute at all */
1276 return Gtkmm2ext::Off;
1280 return ActiveState(0);
1284 RouteUI::update_mute_display ()
1290 mute_button->set_active_state (mute_active_state (_session, _route));
1295 RouteUI::route_rec_enable_changed ()
1297 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1301 RouteUI::session_rec_enable_changed ()
1303 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1307 RouteUI::blink_rec_display (bool blinkOn)
1309 if (!rec_enable_button || !_route) {
1313 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1321 if (track()->rec_enable_control()->get_value()) {
1322 switch (_session->record_status ()) {
1323 case Session::Recording:
1324 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1327 case Session::Disabled:
1328 case Session::Enabled:
1329 if (UIConfiguration::instance().get_blink_rec_arm()) {
1330 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1332 rec_enable_button->set_active_state ( ImplicitActive );
1337 if (step_edit_item) {
1338 step_edit_item->set_sensitive (false);
1342 rec_enable_button->unset_active_state ();
1344 if (step_edit_item) {
1345 step_edit_item->set_sensitive (true);
1349 check_rec_enable_sensitivity ();
1353 RouteUI::build_solo_menu (void)
1355 using namespace Menu_Helpers;
1357 solo_menu = new Menu;
1358 solo_menu->set_name ("ArdourContextMenu");
1359 MenuList& items = solo_menu->items();
1360 Gtk::CheckMenuItem* check;
1362 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1363 check->set_active (_route->solo_isolate_control()->solo_isolated());
1364 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1365 items.push_back (CheckMenuElem(*check));
1366 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1369 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1370 check->set_active (_route->solo_safe_control()->solo_safe());
1371 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1372 items.push_back (CheckMenuElem(*check));
1373 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1376 //items.push_back (SeparatorElem());
1377 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1382 RouteUI::build_mute_menu(void)
1384 using namespace Menu_Helpers;
1386 mute_menu = new Menu;
1387 mute_menu->set_name ("ArdourContextMenu");
1389 MenuList& items = mute_menu->items();
1391 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1392 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1393 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1394 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1395 pre_fader_mute_check->show_all();
1397 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1398 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1399 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1400 items.push_back (CheckMenuElem(*post_fader_mute_check));
1401 post_fader_mute_check->show_all();
1403 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1404 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1405 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1406 items.push_back (CheckMenuElem(*listen_mute_check));
1407 listen_mute_check->show_all();
1409 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1410 init_mute_menu(MuteMaster::Main, main_mute_check);
1411 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1412 items.push_back (CheckMenuElem(*main_mute_check));
1413 main_mute_check->show_all();
1415 //items.push_back (SeparatorElem());
1416 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1418 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1422 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1424 check->set_active (_route->mute_control()->mute_points() & mp);
1428 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1430 if (check->get_active()) {
1431 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1433 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1438 RouteUI::muting_change ()
1440 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1443 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1445 yn = (current & MuteMaster::PreFader);
1447 if (pre_fader_mute_check->get_active() != yn) {
1448 pre_fader_mute_check->set_active (yn);
1451 yn = (current & MuteMaster::PostFader);
1453 if (post_fader_mute_check->get_active() != yn) {
1454 post_fader_mute_check->set_active (yn);
1457 yn = (current & MuteMaster::Listen);
1459 if (listen_mute_check->get_active() != yn) {
1460 listen_mute_check->set_active (yn);
1463 yn = (current & MuteMaster::Main);
1465 if (main_mute_check->get_active() != yn) {
1466 main_mute_check->set_active (yn);
1471 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1473 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1477 bool view = solo_isolated_led->active_state();
1478 bool model = _route->solo_isolate_control()->solo_isolated();
1480 /* called BEFORE the view has changed */
1482 if (ev->button == 1) {
1483 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1486 /* disable isolate for all routes */
1487 DisplaySuspender ds;
1488 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1490 /* enable isolate for all routes */
1491 DisplaySuspender ds;
1492 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1497 if (model == view) {
1499 /* flip just this route */
1501 boost::shared_ptr<RouteList> rl (new RouteList);
1502 rl->push_back (_route);
1503 DisplaySuspender ds;
1504 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1513 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1515 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1519 bool view = solo_safe_led->active_state();
1520 bool model = _route->solo_safe_control()->solo_safe();
1522 if (ev->button == 1) {
1523 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1524 boost::shared_ptr<RouteList> rl (_session->get_routes());
1526 /* disable solo safe for all routes */
1527 DisplaySuspender ds;
1528 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1529 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1532 /* enable solo safe for all routes */
1533 DisplaySuspender ds;
1534 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1535 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1540 if (model == view) {
1541 /* flip just this route */
1542 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1551 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1553 bool view = check->get_active();
1554 bool model = _route->solo_isolate_control()->solo_isolated();
1556 /* called AFTER the view has changed */
1558 if (model != view) {
1559 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1564 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1566 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1569 /** Ask the user to choose a colour, and then apply that color to my route
1572 RouteUI::choose_color ()
1575 Gdk::Color c (gdk_color_from_rgb (_route->presentation_info().color()));
1576 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1579 set_color (gdk_color_to_rgba (color));
1583 /** Set the route's own color. This may not be used for display if
1584 * the route is in a group which shares its color with its routes.
1587 RouteUI::set_color (uint32_t c)
1589 _route->presentation_info().set_color (c);
1592 /** @return GUI state ID for things that are common to the route in all its representations */
1594 RouteUI::route_state_id () const
1596 return string_compose (X_("route %1"), _route->id().to_s());
1600 RouteUI::set_color_from_route ()
1602 if (_route->presentation_info().color_set()) {
1603 return 0; /* nothing to do */
1606 return 1; /* pick a color */
1609 /** @return true if this name should be used for the route, otherwise false */
1611 RouteUI::verify_new_route_name (const std::string& name)
1613 if (name.find (':') == string::npos) {
1617 MessageDialog colon_msg (
1618 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1619 false, MESSAGE_QUESTION, BUTTONS_NONE
1622 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1623 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1625 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1629 RouteUI::route_rename ()
1631 ArdourPrompter name_prompter (true);
1636 name_prompter.set_title (_("Rename Track"));
1638 name_prompter.set_title (_("Rename Bus"));
1640 name_prompter.set_prompt (_("New name:"));
1641 name_prompter.set_initial_text (_route->name());
1642 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1643 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1644 name_prompter.show_all ();
1647 switch (name_prompter.run ()) {
1648 case Gtk::RESPONSE_ACCEPT:
1649 name_prompter.get_result (result);
1650 name_prompter.hide ();
1651 if (result.length()) {
1652 if (verify_new_route_name (result)) {
1653 _route->set_name (result);
1656 /* back to name prompter */
1660 /* nothing entered, just get out of here */
1675 RouteUI::toggle_comment_editor ()
1677 // if (ignore_toggle) {
1681 if (comment_window && comment_window->is_visible ()) {
1682 comment_window->hide ();
1684 open_comment_editor ();
1690 RouteUI::open_comment_editor ()
1692 if (comment_window == 0) {
1693 setup_comment_editor ();
1697 title = _route->name();
1698 title += _(": comment editor");
1700 comment_window->set_title (title);
1701 comment_window->present();
1705 RouteUI::setup_comment_editor ()
1707 comment_window = new ArdourWindow (""); // title will be reset to show route
1708 comment_window->set_skip_taskbar_hint (true);
1709 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1710 comment_window->set_default_size (400, 200);
1712 comment_area = manage (new TextView());
1713 comment_area->set_name ("MixerTrackCommentArea");
1714 comment_area->set_wrap_mode (WRAP_WORD);
1715 comment_area->set_editable (true);
1716 comment_area->get_buffer()->set_text (_route->comment());
1717 comment_area->show ();
1719 comment_window->add (*comment_area);
1723 RouteUI::comment_changed ()
1725 ignore_comment_edit = true;
1727 comment_area->get_buffer()->set_text (_route->comment());
1729 ignore_comment_edit = false;
1733 RouteUI::comment_editor_done_editing ()
1735 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1737 string const str = comment_area->get_buffer()->get_text();
1738 if (str == _route->comment ()) {
1742 _route->set_comment (str, this);
1746 RouteUI::set_route_active (bool a, bool apply_to_selection)
1748 if (apply_to_selection) {
1749 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1751 _route->set_active (a, this);
1756 RouteUI::duplicate_selected_routes ()
1758 ARDOUR_UI::instance()->start_duplicate_routes();
1762 RouteUI::toggle_denormal_protection ()
1764 if (denormal_menu_item) {
1768 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1770 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1771 _route->set_denormal_protection (x);
1777 RouteUI::denormal_protection_changed ()
1779 if (denormal_menu_item) {
1780 denormal_menu_item->set_active (_route->denormal_protection());
1785 RouteUI::disconnect_input ()
1787 _route->input()->disconnect (this);
1791 RouteUI::disconnect_output ()
1793 _route->output()->disconnect (this);
1797 RouteUI::is_track () const
1799 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1802 boost::shared_ptr<Track>
1803 RouteUI::track() const
1805 return boost::dynamic_pointer_cast<Track>(_route);
1809 RouteUI::is_audio_track () const
1811 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1814 boost::shared_ptr<AudioTrack>
1815 RouteUI::audio_track() const
1817 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1821 RouteUI::is_midi_track () const
1823 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1826 boost::shared_ptr<MidiTrack>
1827 RouteUI::midi_track() const
1829 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1833 RouteUI::has_audio_outputs () const
1835 return (_route->n_outputs().n_audio() > 0);
1839 RouteUI::map_frozen ()
1841 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1843 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1846 check_rec_enable_sensitivity ();
1851 RouteUI::adjust_latency ()
1853 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1857 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1860 std::string safe_name;
1863 prompter.get_result (name, true);
1865 safe_name = legalize_for_path (name);
1866 safe_name += template_suffix;
1868 path = Glib::build_filename (dir, safe_name);
1870 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1871 bool overwrite = overwrite_file_dialog (prompter,
1872 _("Confirm Template Overwrite"),
1873 _("A template already exists with that name. Do you want to overwrite it?"));
1880 _route->save_as_template (path, name);
1886 RouteUI::save_as_template ()
1890 dir = ARDOUR::user_route_template_directory ();
1892 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1893 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1897 ArdourPrompter prompter (true); // modal
1899 prompter.set_title (_("Save As Template"));
1900 prompter.set_prompt (_("Template name:"));
1901 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1903 bool finished = false;
1905 switch (prompter.run()) {
1906 case RESPONSE_ACCEPT:
1907 finished = process_save_template_prompter (prompter, dir);
1917 RouteUI::check_rec_enable_sensitivity ()
1919 if (!rec_enable_button) {
1920 assert (0); // This should not happen
1923 if (!_session->writable()) {
1924 rec_enable_button->set_sensitive (false);
1928 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1929 rec_enable_button->set_sensitive (false);
1930 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1931 rec_enable_button->set_sensitive (false);
1933 rec_enable_button->set_sensitive (true);
1935 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1936 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1938 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1940 update_monitoring_display ();
1944 RouteUI::parameter_changed (string const & p)
1946 /* this handles RC and per-session parameter changes */
1948 if (p == "disable-disarm-during-roll") {
1949 check_rec_enable_sensitivity ();
1950 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1951 set_button_names ();
1952 } else if (p == "auto-input") {
1953 update_monitoring_display ();
1954 } else if (p == "blink-rec-arm") {
1955 if (UIConfiguration::instance().get_blink_rec_arm()) {
1956 rec_blink_connection.disconnect ();
1957 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1959 rec_blink_connection.disconnect ();
1960 RouteUI::blink_rec_display(false);
1966 RouteUI::step_gain_up ()
1968 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1972 RouteUI::page_gain_up ()
1974 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1978 RouteUI::step_gain_down ()
1980 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1984 RouteUI::page_gain_down ()
1986 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1990 RouteUI::setup_invert_buttons ()
1992 /* remove old invert buttons */
1993 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1994 _invert_button_box.remove (**i);
1997 _invert_buttons.clear ();
1999 if (!_route || !_route->input()) {
2003 uint32_t const N = _route->input()->n_ports().n_audio ();
2005 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2007 for (uint32_t i = 0; i < to_add; ++i) {
2008 ArdourButton* b = manage (new ArdourButton);
2009 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2010 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2012 b->set_name (X_("invert button"));
2015 b->set_text (string_compose (X_("Ø (%1)"), N));
2017 b->set_text (X_("Ø"));
2020 b->set_text (string_compose (X_("Ø%1"), i + 1));
2023 if (N <= _max_invert_buttons) {
2024 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert polarity of channel %1 of this track. Right-click to show menu."), i + 1));
2026 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2029 _invert_buttons.push_back (b);
2030 _invert_button_box.pack_start (*b);
2033 _invert_button_box.set_spacing (1);
2034 _invert_button_box.show_all ();
2038 RouteUI::set_invert_button_state ()
2040 uint32_t const N = _route->input()->n_ports().n_audio();
2041 if (N > _max_invert_buttons) {
2043 /* One button for many channels; explicit active if all channels are inverted,
2044 implicit active if some are, off if none are.
2047 ArdourButton* b = _invert_buttons.front ();
2049 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2050 b->set_active_state (Gtkmm2ext::ExplicitActive);
2051 } else if (_route->phase_control()->any()) {
2052 b->set_active_state (Gtkmm2ext::ImplicitActive);
2054 b->set_active_state (Gtkmm2ext::Off);
2059 /* One button per channel; just set active */
2062 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2063 (*i)->set_active (_route->phase_control()->inverted (j));
2070 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2072 if (ev->button == 1 && i < _invert_buttons.size()) {
2073 uint32_t const N = _route->input()->n_ports().n_audio ();
2074 if (N <= _max_invert_buttons) {
2075 /* left-click inverts phase so long as we have a button per channel */
2076 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2085 RouteUI::invert_press (GdkEventButton* ev)
2087 using namespace Menu_Helpers;
2089 uint32_t const N = _route->input()->n_ports().n_audio();
2090 if (N <= _max_invert_buttons && ev->button != 3) {
2091 /* If we have an invert button per channel, we only pop
2092 up a menu on right-click; left click is handled
2098 delete _invert_menu;
2099 _invert_menu = new Menu;
2100 _invert_menu->set_name ("ArdourContextMenu");
2101 MenuList& items = _invert_menu->items ();
2103 for (uint32_t i = 0; i < N; ++i) {
2104 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2105 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2106 ++_i_am_the_modifier;
2107 e->set_active (_route->phase_control()->inverted (i));
2108 --_i_am_the_modifier;
2111 _invert_menu->popup (0, ev->time);
2117 RouteUI::invert_menu_toggled (uint32_t c)
2119 if (_i_am_the_modifier) {
2124 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2128 RouteUI::set_invert_sensitive (bool yn)
2130 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2131 (*b)->set_sensitive (yn);
2136 RouteUI::request_redraw ()
2139 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2143 /** The Route's gui_changed signal has been emitted */
2145 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2147 if (what_changed.contains (Properties::color)) {
2148 if (set_color_from_route () == 0) {
2149 route_color_changed ();
2155 RouteUI::track_mode_changed (void)
2158 switch (track()->mode()) {
2159 case ARDOUR::NonLayered:
2160 case ARDOUR::Normal:
2161 rec_enable_button->set_icon (ArdourIcon::RecButton);
2163 case ARDOUR::Destructive:
2164 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2167 rec_enable_button->queue_draw();
2170 /** @return the color that this route should use; it maybe its own,
2171 or it maybe that of its route group.
2175 RouteUI::route_color () const
2178 RouteGroup* g = _route->route_group ();
2181 if (g && g->is_color()) {
2182 set_color_from_rgba (c, GroupTabs::group_color (g));
2185 /* deal with older 4.x color, which was stored in the GUI object state */
2187 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2191 /* old v4.x or earlier session. Use this information */
2193 int red, green, blue;
2196 stringstream ss (p);
2198 /* old color format version was:
2200 16bit value for red:16 bit value for green:16 bit value for blue
2215 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
2218 set_color_from_rgba (c, _route->presentation_info().color());
2225 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2227 _showing_sends_to = send_to;
2228 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2232 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2234 if (_route == send_to) {
2235 show_sends_button->set_active (true);
2236 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2238 show_sends_button->set_active (false);
2239 send_blink_connection.disconnect ();
2244 RouteUI::route_group() const
2246 return _route->route_group();
2250 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2251 : WM::ProxyBase (name, string())
2252 , _route (boost::weak_ptr<Route> (route))
2254 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2257 RoutePinWindowProxy::~RoutePinWindowProxy()
2262 ARDOUR::SessionHandlePtr*
2263 RoutePinWindowProxy::session_handle ()
2265 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2266 if (aw) { return aw; }
2271 RoutePinWindowProxy::get (bool create)
2273 boost::shared_ptr<Route> r = _route.lock ();
2282 _window = new PluginPinDialog (r);
2283 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2285 aw->set_session (_session);
2287 _window->show_all ();
2293 RoutePinWindowProxy::route_going_away ()
2297 WM::Manager::instance().remove (this);
2298 going_away_connection.disconnect();
2302 RouteUI::maybe_add_route_print_mgr ()
2304 if (_route->pinmgr_proxy ()) {
2307 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2308 string_compose ("RPM-%1", _route->id()), _route);
2309 wp->set_session (_session);
2311 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2313 wp->set_state (*ui_xml, 0);
2317 void* existing_ui = _route->pinmgr_proxy ();
2319 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2322 _route->set_pingmgr_proxy (wp);
2324 WM::Manager::instance().register_window (wp);
2328 RouteUI::manage_pins ()
2330 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2338 RouteUI::mark_hidden (bool yn)
2340 if (yn != _route->presentation_info().hidden()) {
2341 _route->presentation_info().set_hidden (yn);
2342 return true; // things changed
2347 boost::shared_ptr<Stripable>
2348 RouteUI::stripable () const