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());
208 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
209 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
211 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
212 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
214 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
215 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
216 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
217 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
219 monitor_input_button->set_distinct_led_click (false);
220 monitor_disk_button->set_distinct_led_click (false);
222 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
223 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
225 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
226 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
228 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
234 route_connections.drop_connections ();
242 denormal_menu_item = 0;
246 RouteUI::self_delete ()
252 RouteUI::set_route (boost::shared_ptr<Route> rp)
258 if (set_color_from_route()) {
259 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
263 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
266 delete input_selector;
269 delete output_selector;
272 mute_button->set_controllable (_route->mute_control());
273 solo_button->set_controllable (_route->solo_control());
275 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
277 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
279 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
280 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
281 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
282 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
283 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
286 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
287 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
288 track_mode_changed();
292 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
293 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
295 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
297 if (_session->writable() && is_track()) {
298 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
300 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
301 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
303 rec_enable_button->show();
304 rec_enable_button->set_controllable (t->rec_enable_control());
306 if (is_midi_track()) {
307 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
308 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
313 /* this will work for busses and tracks, and needs to be called to
314 set up the name entry/name label display.
318 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
319 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
321 update_monitoring_display ();
324 mute_button->unset_flags (Gtk::CAN_FOCUS);
325 solo_button->unset_flags (Gtk::CAN_FOCUS);
329 if (_route->is_monitor() || _route->is_master()) {
330 solo_button->hide ();
337 setup_invert_buttons ();
338 set_invert_button_state ();
340 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
341 bus_send_display_changed (s);
343 update_mute_display ();
344 update_solo_display ();
346 if (!UIConfiguration::instance().get_blink_rec_arm()) {
347 blink_rec_display(true); // set initial rec-en button state
350 check_rec_enable_sensitivity ();
351 maybe_add_route_print_mgr ();
352 route_color_changed();
353 route_gui_changed (PropertyChange (Properties::selected));
357 RouteUI::polarity_changed ()
363 set_invert_button_state ();
367 RouteUI::mute_press (GdkEventButton* ev)
369 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
373 //if this is a binding action, let the ArdourButton handle it
374 if ( BindingProxy::is_bind_action(ev) )
377 multiple_mute_change = false;
379 if (Keyboard::is_context_menu_event (ev)) {
385 mute_menu->popup(0,ev->time);
391 if (Keyboard::is_button2_event (ev)) {
392 // button2-click is "momentary"
394 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
397 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
399 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
401 /* toggle mute on everything (but
402 * exclude the master and monitor)
404 * because we are going to erase
405 * elements of the list we need to work
409 boost::shared_ptr<RouteList> copy (new RouteList);
411 *copy = *_session->get_routes ();
413 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
414 if ((*i)->is_master() || (*i)->is_monitor()) {
422 _mute_release->routes = copy;
426 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
428 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
430 /* Primary-button1 inverts the implication of
431 the group being active. If the group is
432 active (for mute), then this modifier means
433 "do not apply to mute". If the group is
434 inactive (for mute), then this modifier
435 means "apply to route". This is all
436 accomplished by passing just the actual
437 route, along with the InverseGroup group
440 NOTE: Primary-button2 is MIDI learn.
443 boost::shared_ptr<RouteList> rl;
445 if (ev->button == 1) {
447 rl.reset (new RouteList);
448 rl->push_back (_route);
451 _mute_release->routes = rl;
455 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
460 /* plain click applies change to this route */
462 boost::shared_ptr<RouteList> rl (new RouteList);
463 rl->push_back (_route);
466 _mute_release->routes = rl;
469 _route->mute_control()->set_value (!_route->muted_by_self(), Controllable::UseGroup);
478 RouteUI::mute_release (GdkEventButton* /*ev*/)
482 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
483 delete _mute_release;
491 RouteUI::edit_output_configuration ()
493 if (output_selector == 0) {
495 boost::shared_ptr<Send> send;
496 boost::shared_ptr<IO> output;
498 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
499 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
500 output = send->output();
502 output = _route->output ();
505 output = _route->output ();
508 output_selector = new IOSelectorWindow (_session, output);
511 if (output_selector->is_visible()) {
512 output_selector->get_toplevel()->get_window()->raise();
514 output_selector->present ();
517 //output_selector->set_keep_above (true);
521 RouteUI::edit_input_configuration ()
523 if (input_selector == 0) {
524 input_selector = new IOSelectorWindow (_session, _route->input());
527 if (input_selector->is_visible()) {
528 input_selector->get_toplevel()->get_window()->raise();
530 input_selector->present ();
533 //input_selector->set_keep_above (true);
537 RouteUI::solo_press(GdkEventButton* ev)
539 /* ignore double/triple clicks */
541 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
545 //if this is a binding action, let the ArdourButton handle it
546 if ( BindingProxy::is_bind_action(ev) )
549 multiple_solo_change = false;
551 if (Keyboard::is_context_menu_event (ev)) {
553 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
554 ! (solo_safe_led && solo_safe_led->is_visible())) {
556 if (solo_menu == 0) {
560 solo_menu->popup (1, ev->time);
565 if (Keyboard::is_button2_event (ev)) {
567 // button2-click is "momentary"
568 _solo_release = new SoloMuteRelease (_route->self_soloed());
571 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
573 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
575 /* Primary-Tertiary-click applies change to all routes */
578 _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;
653 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
656 delete _solo_release;
661 /* click: solo this route */
663 boost::shared_ptr<RouteList> rl (new RouteList);
664 rl->push_back (route());
667 _solo_release->routes = rl;
671 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
680 RouteUI::solo_release (GdkEventButton* /*ev*/)
684 if (_solo_release->exclusive) {
688 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
691 delete _solo_release;
699 RouteUI::rec_enable_press(GdkEventButton* ev)
701 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
705 //if this is a binding action, let the ArdourButton handle it
706 if ( BindingProxy::is_bind_action(ev) )
709 if (!_session->engine().connected()) {
710 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
715 if (is_midi_track()) {
717 /* rec-enable button exits from step editing */
719 if (midi_track()->step_editing()) {
720 midi_track()->set_step_editing (false);
725 if (is_track() && rec_enable_button) {
727 if (Keyboard::is_button2_event (ev)) {
729 //rec arm does not have a momentary mode
732 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
735 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
737 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
739 /* Primary-button1 applies change to the route group (even if it is not active)
740 NOTE: Primary-button2 is MIDI learn.
743 if (ev->button == 1) {
745 boost::shared_ptr<RouteList> rl;
747 rl.reset (new RouteList);
748 rl->push_back (_route);
751 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
754 } else if (Keyboard::is_context_menu_event (ev)) {
756 /* do this on release */
760 boost::shared_ptr<Track> trk = track();
761 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
769 RouteUI::update_monitoring_display ()
775 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
781 MonitorState ms = t->monitoring_state();
783 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
784 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
786 if (ms & MonitoringInput) {
787 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
789 monitor_input_button->unset_active_state ();
793 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
794 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
796 if (ms & MonitoringDisk) {
797 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
799 monitor_disk_button->unset_active_state ();
805 RouteUI::monitor_input_press(GdkEventButton*)
811 RouteUI::monitor_input_release(GdkEventButton* ev)
813 return monitor_release (ev, MonitorInput);
817 RouteUI::monitor_disk_press (GdkEventButton*)
823 RouteUI::monitor_disk_release (GdkEventButton* ev)
825 return monitor_release (ev, MonitorDisk);
829 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
831 if (ev->button != 1) {
835 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
842 boost::shared_ptr<RouteList> rl;
844 /* XXX for now, monitoring choices are orthogonal. cue monitoring
845 will follow in 3.X but requires mixing the input and playback (disk)
846 signal together, which requires yet more buffers.
849 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
850 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
852 /* this line will change when the options are non-orthogonal */
853 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
857 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
858 rl = _session->get_routes ();
860 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
861 if (_route->route_group() && _route->route_group()->is_monitoring()) {
862 rl = _route->route_group()->route_list();
864 rl.reset (new RouteList);
865 rl->push_back (route());
868 rl.reset (new RouteList);
869 rl->push_back (route());
873 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
879 RouteUI::build_record_menu ()
882 record_menu = new Menu;
883 record_menu->set_name ("ArdourContextMenu");
884 using namespace Menu_Helpers;
885 MenuList& items = record_menu->items();
887 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
888 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
890 if (is_midi_track()) {
891 items.push_back (SeparatorElem());
892 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
893 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
897 if (step_edit_item) {
898 if (track()->rec_enable_control()->get_value()) {
899 step_edit_item->set_sensitive (false);
901 step_edit_item->set_active (midi_track()->step_editing());
904 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
905 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
910 RouteUI::toggle_step_edit ()
912 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
916 midi_track()->set_step_editing (step_edit_item->get_active());
920 RouteUI::toggle_rec_safe ()
922 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
928 /* This check is made inside the control too, but dong it here can't
932 if (_route->rec_enable_control()->get_value()) {
936 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
940 RouteUI::step_edit_changed (bool yn)
943 if (rec_enable_button) {
944 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
947 start_step_editing ();
949 if (step_edit_item) {
950 step_edit_item->set_active (true);
955 if (rec_enable_button) {
956 rec_enable_button->unset_active_state ();
959 stop_step_editing ();
961 if (step_edit_item) {
962 step_edit_item->set_active (false);
968 RouteUI::rec_enable_release (GdkEventButton* ev)
970 if (Keyboard::is_context_menu_event (ev)) {
971 build_record_menu ();
973 record_menu->popup (1, ev->time);
982 RouteUI::build_sends_menu ()
984 using namespace Menu_Helpers;
986 sends_menu = new Menu;
987 sends_menu->set_name ("ArdourContextMenu");
988 MenuList& items = sends_menu->items();
991 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
995 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
999 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1003 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1007 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1011 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1014 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1018 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1021 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1022 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1023 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1028 RouteUI::create_sends (Placement p, bool include_buses)
1030 _session->globally_add_internal_sends (_route, p, include_buses);
1034 RouteUI::create_selected_sends (Placement p, bool include_buses)
1036 boost::shared_ptr<RouteList> rlist (new RouteList);
1037 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1039 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1040 RouteTimeAxisView* rtv;
1042 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1043 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1044 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1045 rlist->push_back (rui->route());
1051 _session->add_internal_sends (_route, p, rlist);
1055 RouteUI::set_sends_gain_from_track ()
1057 _session->globally_set_send_gains_from_track (_route);
1061 RouteUI::set_sends_gain_to_zero ()
1063 _session->globally_set_send_gains_to_zero (_route);
1067 RouteUI::set_sends_gain_to_unity ()
1069 _session->globally_set_send_gains_to_unity (_route);
1073 RouteUI::show_sends_press(GdkEventButton* ev)
1075 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1079 if (!is_track() && show_sends_button) {
1081 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1083 // do nothing on midi sigc::bind event
1086 } else if (Keyboard::is_context_menu_event (ev)) {
1088 if (sends_menu == 0) {
1089 build_sends_menu ();
1092 sends_menu->popup (0, ev->time);
1096 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1099 set_showing_sends_to (boost::shared_ptr<Route> ());
1101 set_showing_sends_to (_route);
1110 RouteUI::show_sends_release (GdkEventButton*)
1116 RouteUI::send_blink (bool onoff)
1118 if (!show_sends_button) {
1123 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1125 show_sends_button->unset_active_state ();
1129 Gtkmm2ext::ActiveState
1130 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1132 boost::shared_ptr<SoloControl> sc = s->solo_control();
1135 return Gtkmm2ext::Off;
1138 if (!sc->can_solo()) {
1139 return Gtkmm2ext::Off;
1143 if (sc->self_soloed()) {
1144 return Gtkmm2ext::ExplicitActive;
1145 } else if (sc->soloed_by_others()) {
1146 return Gtkmm2ext::ImplicitActive;
1148 return Gtkmm2ext::Off;
1152 Gtkmm2ext::ActiveState
1153 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1155 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1158 return Gtkmm2ext::Off;
1161 if (s->is_master() || s->is_monitor()) {
1162 return Gtkmm2ext::Off;
1165 if (sc->solo_isolated()) {
1166 return Gtkmm2ext::ExplicitActive;
1168 return Gtkmm2ext::Off;
1172 Gtkmm2ext::ActiveState
1173 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1175 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1178 return Gtkmm2ext::Off;
1181 if (s->is_master() || s->is_monitor()) {
1182 return Gtkmm2ext::Off;
1185 if (sc->solo_safe()) {
1186 return Gtkmm2ext::ExplicitActive;
1188 return Gtkmm2ext::Off;
1193 RouteUI::update_solo_display ()
1195 bool yn = _route->solo_safe_control()->solo_safe ();
1197 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1198 solo_safe_check->set_active (yn);
1201 yn = _route->solo_isolate_control()->solo_isolated ();
1203 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1204 solo_isolated_check->set_active (yn);
1207 set_button_names ();
1209 if (solo_isolated_led) {
1210 if (_route->solo_isolate_control()->solo_isolated()) {
1211 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1213 solo_isolated_led->unset_active_state ();
1217 if (solo_safe_led) {
1218 if (_route->solo_safe_control()->solo_safe()) {
1219 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1221 solo_safe_led->unset_active_state ();
1225 solo_button->set_active_state (solo_active_state (_route));
1227 /* some changes to solo status can affect mute display, so catch up
1230 update_mute_display ();
1234 RouteUI::solo_changed_so_update_mute ()
1236 update_mute_display ();
1240 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1242 boost::shared_ptr<MuteControl> mc = s->mute_control();
1244 if (s->is_monitor()) {
1245 return Gtkmm2ext::Off;
1249 return Gtkmm2ext::Off;
1252 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1254 if (mc->muted_by_self ()) {
1256 return Gtkmm2ext::ExplicitActive;
1257 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1258 /* this will reflect both solo mutes AND master mutes */
1259 return Gtkmm2ext::ImplicitActive;
1261 /* no mute at all */
1262 return Gtkmm2ext::Off;
1267 if (mc->muted_by_self()) {
1269 return Gtkmm2ext::ExplicitActive;
1270 } else if (mc->muted_by_masters ()) {
1271 /* this shows only master mutes, not mute-by-others-soloing */
1272 return Gtkmm2ext::ImplicitActive;
1274 /* no mute at all */
1275 return Gtkmm2ext::Off;
1279 return ActiveState(0);
1283 RouteUI::update_mute_display ()
1289 mute_button->set_active_state (mute_active_state (_session, _route));
1294 RouteUI::route_rec_enable_changed ()
1296 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1300 RouteUI::session_rec_enable_changed ()
1302 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1306 RouteUI::blink_rec_display (bool blinkOn)
1308 if (!rec_enable_button || !_route) {
1312 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1320 if (track()->rec_enable_control()->get_value()) {
1321 switch (_session->record_status ()) {
1322 case Session::Recording:
1323 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1326 case Session::Disabled:
1327 case Session::Enabled:
1328 if (UIConfiguration::instance().get_blink_rec_arm()) {
1329 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1331 rec_enable_button->set_active_state ( ImplicitActive );
1336 if (step_edit_item) {
1337 step_edit_item->set_sensitive (false);
1341 rec_enable_button->unset_active_state ();
1343 if (step_edit_item) {
1344 step_edit_item->set_sensitive (true);
1348 check_rec_enable_sensitivity ();
1352 RouteUI::build_solo_menu (void)
1354 using namespace Menu_Helpers;
1356 solo_menu = new Menu;
1357 solo_menu->set_name ("ArdourContextMenu");
1358 MenuList& items = solo_menu->items();
1359 Gtk::CheckMenuItem* check;
1361 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1362 check->set_active (_route->solo_isolate_control()->solo_isolated());
1363 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1364 items.push_back (CheckMenuElem(*check));
1365 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1368 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1369 check->set_active (_route->solo_safe_control()->solo_safe());
1370 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1371 items.push_back (CheckMenuElem(*check));
1372 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1375 //items.push_back (SeparatorElem());
1376 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1381 RouteUI::build_mute_menu(void)
1383 using namespace Menu_Helpers;
1385 mute_menu = new Menu;
1386 mute_menu->set_name ("ArdourContextMenu");
1388 MenuList& items = mute_menu->items();
1390 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1391 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1392 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1393 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1394 pre_fader_mute_check->show_all();
1396 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1397 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1398 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1399 items.push_back (CheckMenuElem(*post_fader_mute_check));
1400 post_fader_mute_check->show_all();
1402 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1403 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1404 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1405 items.push_back (CheckMenuElem(*listen_mute_check));
1406 listen_mute_check->show_all();
1408 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1409 init_mute_menu(MuteMaster::Main, main_mute_check);
1410 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1411 items.push_back (CheckMenuElem(*main_mute_check));
1412 main_mute_check->show_all();
1414 //items.push_back (SeparatorElem());
1415 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1417 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1421 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1423 check->set_active (_route->mute_control()->mute_points() & mp);
1427 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1429 if (check->get_active()) {
1430 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1432 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1437 RouteUI::muting_change ()
1439 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1442 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1444 yn = (current & MuteMaster::PreFader);
1446 if (pre_fader_mute_check->get_active() != yn) {
1447 pre_fader_mute_check->set_active (yn);
1450 yn = (current & MuteMaster::PostFader);
1452 if (post_fader_mute_check->get_active() != yn) {
1453 post_fader_mute_check->set_active (yn);
1456 yn = (current & MuteMaster::Listen);
1458 if (listen_mute_check->get_active() != yn) {
1459 listen_mute_check->set_active (yn);
1462 yn = (current & MuteMaster::Main);
1464 if (main_mute_check->get_active() != yn) {
1465 main_mute_check->set_active (yn);
1470 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1472 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1476 bool view = solo_isolated_led->active_state();
1477 bool model = _route->solo_isolate_control()->solo_isolated();
1479 /* called BEFORE the view has changed */
1481 if (ev->button == 1) {
1482 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1485 /* disable isolate for all routes */
1486 DisplaySuspender ds;
1487 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1489 /* enable isolate for all routes */
1490 DisplaySuspender ds;
1491 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1496 if (model == view) {
1498 /* flip just this route */
1500 boost::shared_ptr<RouteList> rl (new RouteList);
1501 rl->push_back (_route);
1502 DisplaySuspender ds;
1503 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1512 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1514 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1518 bool view = solo_safe_led->active_state();
1519 bool model = _route->solo_safe_control()->solo_safe();
1521 if (ev->button == 1) {
1522 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1523 boost::shared_ptr<RouteList> rl (_session->get_routes());
1525 /* disable solo safe for all routes */
1526 DisplaySuspender ds;
1527 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1528 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1531 /* enable solo safe for all routes */
1532 DisplaySuspender ds;
1533 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1534 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1539 if (model == view) {
1540 /* flip just this route */
1541 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1550 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1552 bool view = check->get_active();
1553 bool model = _route->solo_isolate_control()->solo_isolated();
1555 /* called AFTER the view has changed */
1557 if (model != view) {
1558 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1563 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1565 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1568 /** Ask the user to choose a colour, and then apply that color to my route
1571 RouteUI::choose_color ()
1574 Gdk::Color c (gdk_color_from_rgb (_route->presentation_info().color()));
1575 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1578 set_color (gdk_color_to_rgba (color));
1582 /** Set the route's own color. This may not be used for display if
1583 * the route is in a group which shares its color with its routes.
1586 RouteUI::set_color (uint32_t c)
1588 _route->presentation_info().set_color (c);
1591 /** @return GUI state ID for things that are common to the route in all its representations */
1593 RouteUI::route_state_id () const
1595 return string_compose (X_("route %1"), _route->id().to_s());
1599 RouteUI::set_color_from_route ()
1601 if (_route->presentation_info().color_set()) {
1602 return 0; /* nothing to do */
1605 return 1; /* pick a color */
1608 /** @return true if this name should be used for the route, otherwise false */
1610 RouteUI::verify_new_route_name (const std::string& name)
1612 if (name.find (':') == string::npos) {
1616 MessageDialog colon_msg (
1617 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1618 false, MESSAGE_QUESTION, BUTTONS_NONE
1621 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1622 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1624 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1628 RouteUI::route_rename ()
1630 ArdourPrompter name_prompter (true);
1635 name_prompter.set_title (_("Rename Track"));
1637 name_prompter.set_title (_("Rename Bus"));
1639 name_prompter.set_prompt (_("New name:"));
1640 name_prompter.set_initial_text (_route->name());
1641 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1642 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1643 name_prompter.show_all ();
1646 switch (name_prompter.run ()) {
1647 case Gtk::RESPONSE_ACCEPT:
1648 name_prompter.get_result (result);
1649 name_prompter.hide ();
1650 if (result.length()) {
1651 if (verify_new_route_name (result)) {
1652 _route->set_name (result);
1655 /* back to name prompter */
1659 /* nothing entered, just get out of here */
1674 RouteUI::toggle_comment_editor ()
1676 // if (ignore_toggle) {
1680 if (comment_window && comment_window->is_visible ()) {
1681 comment_window->hide ();
1683 open_comment_editor ();
1689 RouteUI::open_comment_editor ()
1691 if (comment_window == 0) {
1692 setup_comment_editor ();
1696 title = _route->name();
1697 title += _(": comment editor");
1699 comment_window->set_title (title);
1700 comment_window->present();
1704 RouteUI::setup_comment_editor ()
1706 comment_window = new ArdourWindow (""); // title will be reset to show route
1707 comment_window->set_skip_taskbar_hint (true);
1708 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1709 comment_window->set_default_size (400, 200);
1711 comment_area = manage (new TextView());
1712 comment_area->set_name ("MixerTrackCommentArea");
1713 comment_area->set_wrap_mode (WRAP_WORD);
1714 comment_area->set_editable (true);
1715 comment_area->get_buffer()->set_text (_route->comment());
1716 comment_area->show ();
1718 comment_window->add (*comment_area);
1722 RouteUI::comment_changed ()
1724 ignore_comment_edit = true;
1726 comment_area->get_buffer()->set_text (_route->comment());
1728 ignore_comment_edit = false;
1732 RouteUI::comment_editor_done_editing ()
1734 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1736 string const str = comment_area->get_buffer()->get_text();
1737 if (str == _route->comment ()) {
1741 _route->set_comment (str, this);
1745 RouteUI::set_route_active (bool a, bool apply_to_selection)
1747 if (apply_to_selection) {
1748 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1750 _route->set_active (a, this);
1755 RouteUI::duplicate_selected_routes ()
1757 ARDOUR_UI::instance()->start_duplicate_routes();
1761 RouteUI::toggle_denormal_protection ()
1763 if (denormal_menu_item) {
1767 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1769 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1770 _route->set_denormal_protection (x);
1776 RouteUI::denormal_protection_changed ()
1778 if (denormal_menu_item) {
1779 denormal_menu_item->set_active (_route->denormal_protection());
1784 RouteUI::disconnect_input ()
1786 _route->input()->disconnect (this);
1790 RouteUI::disconnect_output ()
1792 _route->output()->disconnect (this);
1796 RouteUI::is_track () const
1798 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1801 boost::shared_ptr<Track>
1802 RouteUI::track() const
1804 return boost::dynamic_pointer_cast<Track>(_route);
1808 RouteUI::is_audio_track () const
1810 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1813 boost::shared_ptr<AudioTrack>
1814 RouteUI::audio_track() const
1816 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1820 RouteUI::is_midi_track () const
1822 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1825 boost::shared_ptr<MidiTrack>
1826 RouteUI::midi_track() const
1828 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1832 RouteUI::has_audio_outputs () const
1834 return (_route->n_outputs().n_audio() > 0);
1838 RouteUI::map_frozen ()
1840 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1842 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1845 check_rec_enable_sensitivity ();
1850 RouteUI::adjust_latency ()
1852 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1856 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1859 std::string safe_name;
1862 prompter.get_result (name, true);
1864 safe_name = legalize_for_path (name);
1865 safe_name += template_suffix;
1867 path = Glib::build_filename (dir, safe_name);
1869 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1870 bool overwrite = overwrite_file_dialog (prompter,
1871 _("Confirm Template Overwrite"),
1872 _("A template already exists with that name. Do you want to overwrite it?"));
1879 _route->save_as_template (path, name);
1885 RouteUI::save_as_template ()
1889 dir = ARDOUR::user_route_template_directory ();
1891 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1892 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1896 ArdourPrompter prompter (true); // modal
1898 prompter.set_title (_("Save As Template"));
1899 prompter.set_prompt (_("Template name:"));
1900 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1902 bool finished = false;
1904 switch (prompter.run()) {
1905 case RESPONSE_ACCEPT:
1906 finished = process_save_template_prompter (prompter, dir);
1916 RouteUI::check_rec_enable_sensitivity ()
1918 if (!rec_enable_button) {
1919 assert (0); // This should not happen
1922 if (!_session->writable()) {
1923 rec_enable_button->set_sensitive (false);
1927 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1928 rec_enable_button->set_sensitive (false);
1929 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1930 rec_enable_button->set_sensitive (false);
1932 rec_enable_button->set_sensitive (true);
1934 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1935 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1937 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1939 update_monitoring_display ();
1943 RouteUI::parameter_changed (string const & p)
1945 /* this handles RC and per-session parameter changes */
1947 if (p == "disable-disarm-during-roll") {
1948 check_rec_enable_sensitivity ();
1949 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1950 set_button_names ();
1951 } else if (p == "auto-input") {
1952 update_monitoring_display ();
1953 } else if (p == "blink-rec-arm") {
1954 if (UIConfiguration::instance().get_blink_rec_arm()) {
1955 rec_blink_connection.disconnect ();
1956 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1958 rec_blink_connection.disconnect ();
1959 RouteUI::blink_rec_display(false);
1965 RouteUI::step_gain_up ()
1967 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1971 RouteUI::page_gain_up ()
1973 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1977 RouteUI::step_gain_down ()
1979 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1983 RouteUI::page_gain_down ()
1985 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1989 RouteUI::setup_invert_buttons ()
1991 /* remove old invert buttons */
1992 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1993 _invert_button_box.remove (**i);
1996 _invert_buttons.clear ();
1998 if (!_route || !_route->input()) {
2002 uint32_t const N = _route->input()->n_ports().n_audio ();
2004 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2006 for (uint32_t i = 0; i < to_add; ++i) {
2007 ArdourButton* b = manage (new ArdourButton);
2008 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2009 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2011 b->set_name (X_("invert button"));
2014 b->set_text (string_compose (X_("Ø (%1)"), N));
2016 b->set_text (X_("Ø"));
2019 b->set_text (string_compose (X_("Ø%1"), i + 1));
2022 if (N <= _max_invert_buttons) {
2023 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));
2025 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2028 _invert_buttons.push_back (b);
2029 _invert_button_box.pack_start (*b);
2032 _invert_button_box.set_spacing (1);
2033 _invert_button_box.show_all ();
2037 RouteUI::set_invert_button_state ()
2039 uint32_t const N = _route->input()->n_ports().n_audio();
2040 if (N > _max_invert_buttons) {
2042 /* One button for many channels; explicit active if all channels are inverted,
2043 implicit active if some are, off if none are.
2046 ArdourButton* b = _invert_buttons.front ();
2048 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2049 b->set_active_state (Gtkmm2ext::ExplicitActive);
2050 } else if (_route->phase_control()->any()) {
2051 b->set_active_state (Gtkmm2ext::ImplicitActive);
2053 b->set_active_state (Gtkmm2ext::Off);
2058 /* One button per channel; just set active */
2061 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2062 (*i)->set_active (_route->phase_control()->inverted (j));
2069 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2071 if (ev->button == 1 && i < _invert_buttons.size()) {
2072 uint32_t const N = _route->input()->n_ports().n_audio ();
2073 if (N <= _max_invert_buttons) {
2074 /* left-click inverts phase so long as we have a button per channel */
2075 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2084 RouteUI::invert_press (GdkEventButton* ev)
2086 using namespace Menu_Helpers;
2088 uint32_t const N = _route->input()->n_ports().n_audio();
2089 if (N <= _max_invert_buttons && ev->button != 3) {
2090 /* If we have an invert button per channel, we only pop
2091 up a menu on right-click; left click is handled
2097 delete _invert_menu;
2098 _invert_menu = new Menu;
2099 _invert_menu->set_name ("ArdourContextMenu");
2100 MenuList& items = _invert_menu->items ();
2102 for (uint32_t i = 0; i < N; ++i) {
2103 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2104 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2105 ++_i_am_the_modifier;
2106 e->set_active (_route->phase_control()->inverted (i));
2107 --_i_am_the_modifier;
2110 _invert_menu->popup (0, ev->time);
2116 RouteUI::invert_menu_toggled (uint32_t c)
2118 if (_i_am_the_modifier) {
2123 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2127 RouteUI::set_invert_sensitive (bool yn)
2129 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2130 (*b)->set_sensitive (yn);
2135 RouteUI::request_redraw ()
2138 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2142 /** The Route's gui_changed signal has been emitted */
2144 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2146 if (what_changed.contains (Properties::color)) {
2147 if (set_color_from_route () == 0) {
2148 route_color_changed ();
2154 RouteUI::track_mode_changed (void)
2157 switch (track()->mode()) {
2158 case ARDOUR::NonLayered:
2159 case ARDOUR::Normal:
2160 rec_enable_button->set_icon (ArdourIcon::RecButton);
2162 case ARDOUR::Destructive:
2163 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2166 rec_enable_button->queue_draw();
2169 /** @return the color that this route should use; it maybe its own,
2170 or it maybe that of its route group.
2174 RouteUI::route_color () const
2177 RouteGroup* g = _route->route_group ();
2180 if (g && g->is_color()) {
2181 set_color_from_rgba (c, GroupTabs::group_color (g));
2184 /* deal with older 4.x color, which was stored in the GUI object state */
2186 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2190 /* old v4.x or earlier session. Use this information */
2192 int red, green, blue;
2195 stringstream ss (p);
2197 /* old color format version was:
2199 16bit value for red:16 bit value for green:16 bit value for blue
2214 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
2217 set_color_from_rgba (c, _route->presentation_info().color());
2224 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2226 _showing_sends_to = send_to;
2227 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2231 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2233 if (_route == send_to) {
2234 show_sends_button->set_active (true);
2235 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2237 show_sends_button->set_active (false);
2238 send_blink_connection.disconnect ();
2243 RouteUI::route_group() const
2245 return _route->route_group();
2249 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2250 : WM::ProxyBase (name, string())
2251 , _route (boost::weak_ptr<Route> (route))
2253 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2256 RoutePinWindowProxy::~RoutePinWindowProxy()
2261 ARDOUR::SessionHandlePtr*
2262 RoutePinWindowProxy::session_handle ()
2264 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2265 if (aw) { return aw; }
2270 RoutePinWindowProxy::get (bool create)
2272 boost::shared_ptr<Route> r = _route.lock ();
2281 _window = new PluginPinDialog (r);
2282 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2284 aw->set_session (_session);
2286 _window->show_all ();
2292 RoutePinWindowProxy::route_going_away ()
2296 WM::Manager::instance().remove (this);
2297 going_away_connection.disconnect();
2301 RouteUI::maybe_add_route_print_mgr ()
2303 if (_route->pinmgr_proxy ()) {
2306 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2307 string_compose ("RPM-%1", _route->id()), _route);
2308 wp->set_session (_session);
2310 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2312 wp->set_state (*ui_xml, 0);
2316 void* existing_ui = _route->pinmgr_proxy ();
2318 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2321 _route->set_pingmgr_proxy (wp);
2323 WM::Manager::instance().register_window (wp);
2327 RouteUI::manage_pins ()
2329 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2337 RouteUI::mark_hidden (bool yn)
2339 if (yn != _route->presentation_info().hidden()) {
2340 _route->presentation_info().set_hidden (yn);
2341 return true; // things changed
2346 boost::shared_ptr<Stripable>
2347 RouteUI::stripable () const