2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <boost/algorithm/string.hpp>
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
35 #include "ardour/dB.h"
36 #include "ardour/route_group.h"
37 #include "ardour/solo_isolate_control.h"
38 #include "ardour/vca.h"
39 #include "ardour/vca_manager.h"
40 #include "ardour/audio_track.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/filename_extensions.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/monitor_control.h"
45 #include "ardour/internal_send.h"
46 #include "ardour/profile.h"
47 #include "ardour/phase_control.h"
48 #include "ardour/send.h"
49 #include "ardour/route.h"
50 #include "ardour/session.h"
51 #include "ardour/template_utils.h"
53 #include "ardour_button.h"
54 #include "ardour_dialog.h"
55 #include "ardour_ui.h"
56 #include "automation_time_axis.h"
58 #include "group_tabs.h"
59 #include "gui_object.h"
60 #include "gui_thread.h"
62 #include "latency_gui.h"
63 #include "mixer_strip.h"
64 #include "plugin_pin_dialog.h"
66 #include "route_time_axis.h"
69 #include "ui_config.h"
75 using namespace Gtkmm2ext;
76 using namespace ARDOUR;
77 using namespace ARDOUR_UI_UTILS;
81 uint32_t RouteUI::_max_invert_buttons = 3;
82 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
83 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
84 std::string RouteUI::program_port_prefix;
86 RouteUI::RouteUI (ARDOUR::Session* sess)
97 if (program_port_prefix.empty()) {
98 // compare to gtk2_ardour/port_group.cc
99 string lpn (PROGRAM_NAME);
100 boost::to_lower (lpn);
101 program_port_prefix = lpn + ":"; // e.g. "ardour:"
112 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
115 _route.reset (); /* drop reference to route, so that it can be cleaned up */
116 route_connections.drop_connections ();
122 delete comment_window;
123 delete input_selector;
124 delete output_selector;
127 send_blink_connection.disconnect ();
128 rec_blink_connection.disconnect ();
134 self_destruct = true;
140 pre_fader_mute_check = 0;
141 post_fader_mute_check = 0;
142 listen_mute_check = 0;
145 solo_isolated_check = 0;
146 solo_isolated_led = 0;
150 denormal_menu_item = 0;
153 multiple_mute_change = false;
154 multiple_solo_change = false;
155 _i_am_the_modifier = 0;
161 setup_invert_buttons ();
163 mute_button = manage (new ArdourButton);
164 mute_button->set_name ("mute button");
165 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
167 solo_button = manage (new ArdourButton);
168 solo_button->set_name ("solo button");
169 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
170 solo_button->set_no_show_all (true);
172 rec_enable_button = manage (new ArdourButton);
173 rec_enable_button->set_name ("record enable button");
174 rec_enable_button->set_icon (ArdourIcon::RecButton);
175 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
177 if (UIConfiguration::instance().get_blink_rec_arm()) {
178 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
181 show_sends_button = manage (new ArdourButton);
182 show_sends_button->set_name ("send alert button");
183 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
185 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
186 monitor_input_button->set_name ("monitor button");
187 monitor_input_button->set_text (_("In"));
188 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
189 monitor_input_button->set_no_show_all (true);
191 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
192 monitor_disk_button->set_name ("monitor button");
193 monitor_disk_button->set_text (_("Disk"));
194 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
195 monitor_disk_button->set_no_show_all (true);
197 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
198 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
199 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
201 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
202 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
204 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
205 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
207 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
208 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
210 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
211 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
212 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
213 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
215 monitor_input_button->set_distinct_led_click (false);
216 monitor_disk_button->set_distinct_led_click (false);
218 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
219 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
221 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
222 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
224 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
230 route_connections.drop_connections ();
238 denormal_menu_item = 0;
242 RouteUI::self_delete ()
248 RouteUI::set_route (boost::shared_ptr<Route> rp)
254 if (set_color_from_route()) {
255 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
259 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
262 delete input_selector;
265 delete output_selector;
268 mute_button->set_controllable (_route->mute_control());
269 solo_button->set_controllable (_route->solo_control());
271 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
273 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
275 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
276 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
277 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
278 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
279 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
282 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
283 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
284 track_mode_changed();
288 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
289 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
291 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
293 if (_session->writable() && is_track()) {
294 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
296 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
297 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
299 rec_enable_button->show();
300 rec_enable_button->set_controllable (t->rec_enable_control());
302 if (is_midi_track()) {
303 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
304 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
309 /* this will work for busses and tracks, and needs to be called to
310 set up the name entry/name label display.
314 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
315 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
317 update_monitoring_display ();
320 mute_button->unset_flags (Gtk::CAN_FOCUS);
321 solo_button->unset_flags (Gtk::CAN_FOCUS);
325 if (_route->is_monitor() || _route->is_master()) {
326 solo_button->hide ();
333 setup_invert_buttons ();
334 set_invert_button_state ();
336 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
337 bus_send_display_changed (s);
339 update_mute_display ();
340 update_solo_display ();
342 if (!UIConfiguration::instance().get_blink_rec_arm()) {
343 blink_rec_display(true); // set initial rec-en button state
346 check_rec_enable_sensitivity ();
347 maybe_add_route_print_mgr ();
348 route_color_changed();
352 RouteUI::polarity_changed ()
358 set_invert_button_state ();
362 RouteUI::mute_press (GdkEventButton* ev)
364 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
368 //if this is a binding action, let the ArdourButton handle it
369 if ( BindingProxy::is_bind_action(ev) )
372 multiple_mute_change = false;
374 if (Keyboard::is_context_menu_event (ev)) {
380 mute_menu->popup(0,ev->time);
386 if (Keyboard::is_button2_event (ev)) {
387 // button2-click is "momentary"
389 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
392 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
394 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
396 /* toggle mute on everything (but
397 * exclude the master and monitor)
399 * because we are going to erase
400 * elements of the list we need to work
404 boost::shared_ptr<RouteList> copy (new RouteList);
406 *copy = *_session->get_routes ();
408 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
409 if ((*i)->is_master() || (*i)->is_monitor()) {
417 _mute_release->routes = copy;
421 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
423 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
425 /* Primary-button1 inverts the implication of
426 the group being active. If the group is
427 active (for mute), then this modifier means
428 "do not apply to mute". If the group is
429 inactive (for mute), then this modifier
430 means "apply to route". This is all
431 accomplished by passing just the actual
432 route, along with the InverseGroup group
435 NOTE: Primary-button2 is MIDI learn.
438 boost::shared_ptr<RouteList> rl;
440 if (ev->button == 1) {
442 rl.reset (new RouteList);
443 rl->push_back (_route);
446 _mute_release->routes = rl;
450 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
455 /* plain click applies change to this route */
457 boost::shared_ptr<RouteList> rl (new RouteList);
458 rl->push_back (_route);
461 _mute_release->routes = rl;
464 _session->set_control (_route->mute_control(), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
474 RouteUI::mute_release (GdkEventButton* /*ev*/)
478 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
479 delete _mute_release;
487 RouteUI::edit_output_configuration ()
489 if (output_selector == 0) {
491 boost::shared_ptr<Send> send;
492 boost::shared_ptr<IO> output;
494 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
495 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
496 output = send->output();
498 output = _route->output ();
501 output = _route->output ();
504 output_selector = new IOSelectorWindow (_session, output);
507 if (output_selector->is_visible()) {
508 output_selector->get_toplevel()->get_window()->raise();
510 output_selector->present ();
513 //output_selector->set_keep_above (true);
517 RouteUI::edit_input_configuration ()
519 if (input_selector == 0) {
520 input_selector = new IOSelectorWindow (_session, _route->input());
523 if (input_selector->is_visible()) {
524 input_selector->get_toplevel()->get_window()->raise();
526 input_selector->present ();
529 //input_selector->set_keep_above (true);
533 RouteUI::solo_press(GdkEventButton* ev)
535 /* ignore double/triple clicks */
537 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
541 //if this is a binding action, let the ArdourButton handle it
542 if ( BindingProxy::is_bind_action(ev) )
545 multiple_solo_change = false;
547 if (Keyboard::is_context_menu_event (ev)) {
549 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
550 ! (solo_safe_led && solo_safe_led->is_visible())) {
552 if (solo_menu == 0) {
556 solo_menu->popup (1, ev->time);
561 if (Keyboard::is_button2_event (ev)) {
563 // button2-click is "momentary"
564 _solo_release = new SoloMuteRelease (_route->self_soloed());
567 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
569 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
571 /* Primary-Tertiary-click applies change to all routes */
574 _solo_release->routes = _session->get_routes ();
578 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
580 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
582 // Primary-Secondary-click: exclusively solo this track
585 _solo_release->exclusive = true;
587 boost::shared_ptr<RouteList> routes = _session->get_routes();
589 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
590 if ((*i)->soloed ()) {
591 _solo_release->routes_on->push_back (*i);
593 _solo_release->routes_off->push_back (*i);
598 if (Config->get_solo_control_is_listen_control()) {
599 /* ??? we need a just_one_listen() method */
602 boost::shared_ptr<ControlList> cl (new ControlList);
603 cl->push_back (_route->solo_control());
604 _session->set_controls (cl, 1.0, Controllable::NoGroup);
607 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
609 // shift-click: toggle solo isolated status
611 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
612 delete _solo_release;
615 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
617 /* Primary-button1: solo mix group.
618 NOTE: Primary-button2 is MIDI learn.
621 /* Primary-button1 applies change to the mix group even if it is not active
622 NOTE: Primary-button2 is MIDI learn.
625 boost::shared_ptr<RouteList> rl;
627 if (ev->button == 1) {
629 /* Primary-button1 inverts the implication of
630 the group being active. If the group is
631 active (for solo), then this modifier means
632 "do not apply to solo". If the group is
633 inactive (for mute), then this modifier
634 means "apply to route". This is all
635 accomplished by passing just the actual
636 route, along with the InverseGroup group
639 NOTE: Primary-button2 is MIDI learn.
642 rl.reset (new RouteList);
643 rl->push_back (_route);
646 _solo_release->routes = rl;
651 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
654 delete _solo_release;
659 /* click: solo this route */
661 boost::shared_ptr<RouteList> rl (new RouteList);
662 rl->push_back (route());
665 _solo_release->routes = rl;
669 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
678 RouteUI::solo_release (GdkEventButton* /*ev*/)
682 if (_solo_release->exclusive) {
686 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
689 delete _solo_release;
697 RouteUI::rec_enable_press(GdkEventButton* ev)
699 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
703 //if this is a binding action, let the ArdourButton handle it
704 if ( BindingProxy::is_bind_action(ev) )
707 if (!_session->engine().connected()) {
708 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
713 if (is_midi_track()) {
715 /* rec-enable button exits from step editing */
717 if (midi_track()->step_editing()) {
718 midi_track()->set_step_editing (false);
723 if (is_track() && rec_enable_button) {
725 if (Keyboard::is_button2_event (ev)) {
727 //rec arm does not have a momentary mode
730 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
733 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
735 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
737 /* Primary-button1 applies change to the route group (even if it is not active)
738 NOTE: Primary-button2 is MIDI learn.
741 if (ev->button == 1) {
743 boost::shared_ptr<RouteList> rl;
745 rl.reset (new RouteList);
746 rl->push_back (_route);
749 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
752 } else if (Keyboard::is_context_menu_event (ev)) {
754 /* do this on release */
758 boost::shared_ptr<Track> trk = track();
759 _session->set_control (trk->rec_enable_control(), !trk->rec_enable_control()->get_value(), Controllable::UseGroup);
767 RouteUI::update_monitoring_display ()
773 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
779 MonitorState ms = t->monitoring_state();
781 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
782 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
784 if (ms & MonitoringInput) {
785 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
787 monitor_input_button->unset_active_state ();
791 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
792 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
794 if (ms & MonitoringDisk) {
795 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
797 monitor_disk_button->unset_active_state ();
803 RouteUI::monitor_input_press(GdkEventButton*)
809 RouteUI::monitor_input_release(GdkEventButton* ev)
811 return monitor_release (ev, MonitorInput);
815 RouteUI::monitor_disk_press (GdkEventButton*)
821 RouteUI::monitor_disk_release (GdkEventButton* ev)
823 return monitor_release (ev, MonitorDisk);
827 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
829 if (ev->button != 1) {
833 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
840 boost::shared_ptr<RouteList> rl;
842 /* XXX for now, monitoring choices are orthogonal. cue monitoring
843 will follow in 3.X but requires mixing the input and playback (disk)
844 signal together, which requires yet more buffers.
847 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
848 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
850 /* this line will change when the options are non-orthogonal */
851 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
855 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
856 rl = _session->get_routes ();
858 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
859 if (_route->route_group() && _route->route_group()->is_monitoring()) {
860 rl = _route->route_group()->route_list();
862 rl.reset (new RouteList);
863 rl->push_back (route());
866 rl.reset (new RouteList);
867 rl->push_back (route());
871 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
877 RouteUI::build_record_menu ()
880 record_menu = new Menu;
881 record_menu->set_name ("ArdourContextMenu");
882 using namespace Menu_Helpers;
883 MenuList& items = record_menu->items();
885 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
886 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
888 if (is_midi_track()) {
889 items.push_back (SeparatorElem());
890 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
891 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
895 if (step_edit_item) {
896 if (track()->rec_enable_control()->get_value()) {
897 step_edit_item->set_sensitive (false);
899 step_edit_item->set_active (midi_track()->step_editing());
902 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
903 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
908 RouteUI::toggle_step_edit ()
910 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
914 midi_track()->set_step_editing (step_edit_item->get_active());
918 RouteUI::toggle_rec_safe ()
920 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
926 /* This check is made inside the control too, but dong it here can't
930 if (_route->rec_enable_control()->get_value()) {
934 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
938 RouteUI::step_edit_changed (bool yn)
941 if (rec_enable_button) {
942 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
945 start_step_editing ();
947 if (step_edit_item) {
948 step_edit_item->set_active (true);
953 if (rec_enable_button) {
954 rec_enable_button->unset_active_state ();
957 stop_step_editing ();
959 if (step_edit_item) {
960 step_edit_item->set_active (false);
966 RouteUI::rec_enable_release (GdkEventButton* ev)
968 if (Keyboard::is_context_menu_event (ev)) {
969 build_record_menu ();
971 record_menu->popup (1, ev->time);
980 RouteUI::build_sends_menu ()
982 using namespace Menu_Helpers;
984 sends_menu = new Menu;
985 sends_menu->set_name ("ArdourContextMenu");
986 MenuList& items = sends_menu->items();
989 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
993 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
997 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1001 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1005 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1009 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1012 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1016 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1019 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1020 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1021 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1026 RouteUI::create_sends (Placement p, bool include_buses)
1028 _session->globally_add_internal_sends (_route, p, include_buses);
1032 RouteUI::create_selected_sends (Placement p, bool include_buses)
1034 boost::shared_ptr<RouteList> rlist (new RouteList);
1035 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1037 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1038 RouteTimeAxisView* rtv;
1040 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1041 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1042 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1043 rlist->push_back (rui->route());
1049 _session->add_internal_sends (_route, p, rlist);
1053 RouteUI::set_sends_gain_from_track ()
1055 _session->globally_set_send_gains_from_track (_route);
1059 RouteUI::set_sends_gain_to_zero ()
1061 _session->globally_set_send_gains_to_zero (_route);
1065 RouteUI::set_sends_gain_to_unity ()
1067 _session->globally_set_send_gains_to_unity (_route);
1071 RouteUI::show_sends_press(GdkEventButton* ev)
1073 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1077 if (!is_track() && show_sends_button) {
1079 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1081 // do nothing on midi sigc::bind event
1084 } else if (Keyboard::is_context_menu_event (ev)) {
1086 if (sends_menu == 0) {
1087 build_sends_menu ();
1090 sends_menu->popup (0, ev->time);
1094 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1097 set_showing_sends_to (boost::shared_ptr<Route> ());
1099 set_showing_sends_to (_route);
1108 RouteUI::show_sends_release (GdkEventButton*)
1114 RouteUI::send_blink (bool onoff)
1116 if (!show_sends_button) {
1121 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1123 show_sends_button->unset_active_state ();
1127 Gtkmm2ext::ActiveState
1128 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1130 boost::shared_ptr<SoloControl> sc = s->solo_control();
1133 return Gtkmm2ext::Off;
1136 if (!sc->can_solo()) {
1137 return Gtkmm2ext::Off;
1141 if (sc->self_soloed()) {
1142 return Gtkmm2ext::ExplicitActive;
1143 } else if (sc->soloed_by_others()) {
1144 return Gtkmm2ext::ImplicitActive;
1146 return Gtkmm2ext::Off;
1150 Gtkmm2ext::ActiveState
1151 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1153 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1156 return Gtkmm2ext::Off;
1159 if (s->is_master() || s->is_monitor()) {
1160 return Gtkmm2ext::Off;
1163 if (sc->solo_isolated()) {
1164 return Gtkmm2ext::ExplicitActive;
1166 return Gtkmm2ext::Off;
1170 Gtkmm2ext::ActiveState
1171 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1173 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1176 return Gtkmm2ext::Off;
1179 if (s->is_master() || s->is_monitor()) {
1180 return Gtkmm2ext::Off;
1183 if (sc->solo_safe()) {
1184 return Gtkmm2ext::ExplicitActive;
1186 return Gtkmm2ext::Off;
1191 RouteUI::update_solo_display ()
1193 bool yn = _route->solo_safe_control()->solo_safe ();
1195 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1196 solo_safe_check->set_active (yn);
1199 yn = _route->solo_isolate_control()->solo_isolated ();
1201 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1202 solo_isolated_check->set_active (yn);
1205 set_button_names ();
1207 if (solo_isolated_led) {
1208 if (_route->solo_isolate_control()->solo_isolated()) {
1209 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1211 solo_isolated_led->unset_active_state ();
1215 if (solo_safe_led) {
1216 if (_route->solo_safe_control()->solo_safe()) {
1217 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1219 solo_safe_led->unset_active_state ();
1223 solo_button->set_active_state (solo_active_state (_route));
1225 /* some changes to solo status can affect mute display, so catch up
1228 update_mute_display ();
1232 RouteUI::solo_changed_so_update_mute ()
1234 update_mute_display ();
1238 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1240 boost::shared_ptr<MuteControl> mc = s->mute_control();
1242 if (s->is_monitor()) {
1243 return Gtkmm2ext::Off;
1247 return Gtkmm2ext::Off;
1250 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1252 if (mc->muted_by_self ()) {
1254 return Gtkmm2ext::ExplicitActive;
1255 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1256 /* this will reflect both solo mutes AND master mutes */
1257 return Gtkmm2ext::ImplicitActive;
1259 /* no mute at all */
1260 return Gtkmm2ext::Off;
1265 if (mc->muted_by_self()) {
1267 return Gtkmm2ext::ExplicitActive;
1268 } else if (mc->muted_by_masters ()) {
1269 /* this shows only master mutes, not mute-by-others-soloing */
1270 return Gtkmm2ext::ImplicitActive;
1272 /* no mute at all */
1273 return Gtkmm2ext::Off;
1277 return ActiveState(0);
1281 RouteUI::update_mute_display ()
1287 mute_button->set_active_state (mute_active_state (_session, _route));
1291 RouteUI::update_vca_display ()
1297 VCAList vcas (_session->vca_manager().vcas());
1300 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1301 if (_route->slaved_to (*v)) {
1302 if (!label.empty()) {
1305 label += PBD::to_string ((*v)->number(), std::dec);
1309 if (label.empty()) {
1311 vca_button->set_active_state (Gtkmm2ext::Off);
1313 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1316 vca_button->set_text (label);
1320 RouteUI::route_rec_enable_changed ()
1322 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1323 update_monitoring_display ();
1327 RouteUI::session_rec_enable_changed ()
1329 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1330 update_monitoring_display ();
1334 RouteUI::blink_rec_display (bool blinkOn)
1336 if (!rec_enable_button || !_route) {
1340 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1348 if (track()->rec_enable_control()->get_value()) {
1349 switch (_session->record_status ()) {
1350 case Session::Recording:
1351 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1354 case Session::Disabled:
1355 case Session::Enabled:
1356 if (UIConfiguration::instance().get_blink_rec_arm()) {
1357 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1359 rec_enable_button->set_active_state ( ImplicitActive );
1364 if (step_edit_item) {
1365 step_edit_item->set_sensitive (false);
1369 rec_enable_button->unset_active_state ();
1371 if (step_edit_item) {
1372 step_edit_item->set_sensitive (true);
1376 check_rec_enable_sensitivity ();
1380 RouteUI::build_solo_menu (void)
1382 using namespace Menu_Helpers;
1384 solo_menu = new Menu;
1385 solo_menu->set_name ("ArdourContextMenu");
1386 MenuList& items = solo_menu->items();
1387 Gtk::CheckMenuItem* check;
1389 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1390 check->set_active (_route->solo_isolate_control()->solo_isolated());
1391 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1392 items.push_back (CheckMenuElem(*check));
1393 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1396 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1397 check->set_active (_route->solo_safe_control()->solo_safe());
1398 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1399 items.push_back (CheckMenuElem(*check));
1400 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1403 //items.push_back (SeparatorElem());
1404 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1409 RouteUI::build_mute_menu(void)
1411 using namespace Menu_Helpers;
1413 mute_menu = new Menu;
1414 mute_menu->set_name ("ArdourContextMenu");
1416 MenuList& items = mute_menu->items();
1418 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1419 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1420 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1421 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1422 pre_fader_mute_check->show_all();
1424 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1425 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1426 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1427 items.push_back (CheckMenuElem(*post_fader_mute_check));
1428 post_fader_mute_check->show_all();
1430 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1431 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1432 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1433 items.push_back (CheckMenuElem(*listen_mute_check));
1434 listen_mute_check->show_all();
1436 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1437 init_mute_menu(MuteMaster::Main, main_mute_check);
1438 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1439 items.push_back (CheckMenuElem(*main_mute_check));
1440 main_mute_check->show_all();
1442 //items.push_back (SeparatorElem());
1443 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1445 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1449 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1451 check->set_active (_route->mute_control()->mute_points() & mp);
1455 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1457 if (check->get_active()) {
1458 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1460 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1465 RouteUI::muting_change ()
1467 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1470 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1472 yn = (current & MuteMaster::PreFader);
1474 if (pre_fader_mute_check->get_active() != yn) {
1475 pre_fader_mute_check->set_active (yn);
1478 yn = (current & MuteMaster::PostFader);
1480 if (post_fader_mute_check->get_active() != yn) {
1481 post_fader_mute_check->set_active (yn);
1484 yn = (current & MuteMaster::Listen);
1486 if (listen_mute_check->get_active() != yn) {
1487 listen_mute_check->set_active (yn);
1490 yn = (current & MuteMaster::Main);
1492 if (main_mute_check->get_active() != yn) {
1493 main_mute_check->set_active (yn);
1498 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1500 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1504 bool view = solo_isolated_led->active_state();
1505 bool model = _route->solo_isolate_control()->solo_isolated();
1507 /* called BEFORE the view has changed */
1509 if (ev->button == 1) {
1510 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1513 /* disable isolate for all routes */
1514 DisplaySuspender ds;
1515 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1517 /* enable isolate for all routes */
1518 DisplaySuspender ds;
1519 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1524 if (model == view) {
1526 /* flip just this route */
1528 boost::shared_ptr<RouteList> rl (new RouteList);
1529 rl->push_back (_route);
1530 DisplaySuspender ds;
1531 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1540 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1542 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1546 bool view = solo_safe_led->active_state();
1547 bool model = _route->solo_safe_control()->solo_safe();
1549 if (ev->button == 1) {
1550 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1551 boost::shared_ptr<RouteList> rl (_session->get_routes());
1553 /* disable solo safe for all routes */
1554 DisplaySuspender ds;
1555 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1556 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1559 /* enable solo safe for all routes */
1560 DisplaySuspender ds;
1561 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1562 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1567 if (model == view) {
1568 /* flip just this route */
1569 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1578 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1580 bool view = check->get_active();
1581 bool model = _route->solo_isolate_control()->solo_isolated();
1583 /* called AFTER the view has changed */
1585 if (model != view) {
1586 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1591 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1593 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1596 /** Ask the user to choose a colour, and then apply that color to my route
1599 RouteUI::choose_color ()
1602 Gdk::Color c (gdk_color_from_rgb (_route->presentation_info().color()));
1603 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1606 set_color (gdk_color_to_rgba (color));
1610 /** Set the route's own color. This may not be used for display if
1611 * the route is in a group which shares its color with its routes.
1614 RouteUI::set_color (uint32_t c)
1616 _route->presentation_info().set_color (c);
1619 /** @return GUI state ID for things that are common to the route in all its representations */
1621 RouteUI::route_state_id () const
1623 return string_compose (X_("route %1"), _route->id().to_s());
1627 RouteUI::set_color_from_route ()
1632 /** @return true if this name should be used for the route, otherwise false */
1634 RouteUI::verify_new_route_name (const std::string& name)
1636 if (name.find (':') == string::npos) {
1640 MessageDialog colon_msg (
1641 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1642 false, MESSAGE_QUESTION, BUTTONS_NONE
1645 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1646 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1648 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1652 RouteUI::route_rename ()
1654 ArdourPrompter name_prompter (true);
1659 name_prompter.set_title (_("Rename Track"));
1661 name_prompter.set_title (_("Rename Bus"));
1663 name_prompter.set_prompt (_("New name:"));
1664 name_prompter.set_initial_text (_route->name());
1665 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1666 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1667 name_prompter.show_all ();
1670 switch (name_prompter.run ()) {
1671 case Gtk::RESPONSE_ACCEPT:
1672 name_prompter.get_result (result);
1673 name_prompter.hide ();
1674 if (result.length()) {
1675 if (verify_new_route_name (result)) {
1676 _route->set_name (result);
1679 /* back to name prompter */
1683 /* nothing entered, just get out of here */
1698 RouteUI::toggle_comment_editor ()
1700 // if (ignore_toggle) {
1704 if (comment_window && comment_window->is_visible ()) {
1705 comment_window->hide ();
1707 open_comment_editor ();
1713 RouteUI::open_comment_editor ()
1715 if (comment_window == 0) {
1716 setup_comment_editor ();
1720 title = _route->name();
1721 title += _(": comment editor");
1723 comment_window->set_title (title);
1724 comment_window->present();
1728 RouteUI::setup_comment_editor ()
1730 comment_window = new ArdourWindow (""); // title will be reset to show route
1731 comment_window->set_skip_taskbar_hint (true);
1732 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1733 comment_window->set_default_size (400, 200);
1735 comment_area = manage (new TextView());
1736 comment_area->set_name ("MixerTrackCommentArea");
1737 comment_area->set_wrap_mode (WRAP_WORD);
1738 comment_area->set_editable (true);
1739 comment_area->get_buffer()->set_text (_route->comment());
1740 comment_area->show ();
1742 comment_window->add (*comment_area);
1746 RouteUI::comment_changed ()
1748 ignore_comment_edit = true;
1750 comment_area->get_buffer()->set_text (_route->comment());
1752 ignore_comment_edit = false;
1756 RouteUI::comment_editor_done_editing ()
1758 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1760 string const str = comment_area->get_buffer()->get_text();
1761 if (str == _route->comment ()) {
1765 _route->set_comment (str, this);
1769 RouteUI::set_route_active (bool a, bool apply_to_selection)
1771 if (apply_to_selection) {
1772 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1774 _route->set_active (a, this);
1779 RouteUI::duplicate_selected_routes ()
1781 ARDOUR_UI::instance()->start_duplicate_routes();
1785 RouteUI::toggle_denormal_protection ()
1787 if (denormal_menu_item) {
1791 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1793 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1794 _route->set_denormal_protection (x);
1800 RouteUI::denormal_protection_changed ()
1802 if (denormal_menu_item) {
1803 denormal_menu_item->set_active (_route->denormal_protection());
1808 RouteUI::disconnect_input ()
1810 _route->input()->disconnect (this);
1814 RouteUI::disconnect_output ()
1816 _route->output()->disconnect (this);
1820 RouteUI::is_track () const
1822 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1825 boost::shared_ptr<Track>
1826 RouteUI::track() const
1828 return boost::dynamic_pointer_cast<Track>(_route);
1832 RouteUI::is_audio_track () const
1834 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1837 boost::shared_ptr<AudioTrack>
1838 RouteUI::audio_track() const
1840 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1844 RouteUI::is_midi_track () const
1846 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1849 boost::shared_ptr<MidiTrack>
1850 RouteUI::midi_track() const
1852 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1856 RouteUI::has_audio_outputs () const
1858 return (_route->n_outputs().n_audio() > 0);
1862 RouteUI::map_frozen ()
1864 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1866 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1869 check_rec_enable_sensitivity ();
1874 RouteUI::adjust_latency ()
1876 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1880 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1883 std::string safe_name;
1886 prompter.get_result (name, true);
1888 safe_name = legalize_for_path (name);
1889 safe_name += template_suffix;
1891 path = Glib::build_filename (dir, safe_name);
1893 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1894 bool overwrite = overwrite_file_dialog (prompter,
1895 _("Confirm Template Overwrite"),
1896 _("A template already exists with that name. Do you want to overwrite it?"));
1903 _route->save_as_template (path, name);
1909 RouteUI::save_as_template ()
1913 dir = ARDOUR::user_route_template_directory ();
1915 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1916 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1920 ArdourPrompter prompter (true); // modal
1922 prompter.set_title (_("Save As Template"));
1923 prompter.set_prompt (_("Template name:"));
1924 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1926 bool finished = false;
1928 switch (prompter.run()) {
1929 case RESPONSE_ACCEPT:
1930 finished = process_save_template_prompter (prompter, dir);
1940 RouteUI::check_rec_enable_sensitivity ()
1942 if (!rec_enable_button) {
1943 assert (0); // This should not happen
1946 if (!_session->writable()) {
1947 rec_enable_button->set_sensitive (false);
1951 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1952 rec_enable_button->set_sensitive (false);
1953 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1954 rec_enable_button->set_sensitive (false);
1956 rec_enable_button->set_sensitive (true);
1958 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1959 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1961 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1963 update_monitoring_display ();
1967 RouteUI::parameter_changed (string const & p)
1969 /* this handles RC and per-session parameter changes */
1971 if (p == "disable-disarm-during-roll") {
1972 check_rec_enable_sensitivity ();
1973 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1974 set_button_names ();
1975 } else if (p == "auto-input") {
1976 update_monitoring_display ();
1977 } else if (p == "blink-rec-arm") {
1978 if (UIConfiguration::instance().get_blink_rec_arm()) {
1979 rec_blink_connection.disconnect ();
1980 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1982 rec_blink_connection.disconnect ();
1983 RouteUI::blink_rec_display(false);
1989 RouteUI::step_gain_up ()
1991 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1995 RouteUI::page_gain_up ()
1997 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2001 RouteUI::step_gain_down ()
2003 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2007 RouteUI::page_gain_down ()
2009 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2013 RouteUI::setup_invert_buttons ()
2015 /* remove old invert buttons */
2016 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2017 _invert_button_box.remove (**i);
2020 _invert_buttons.clear ();
2022 if (!_route || !_route->input()) {
2026 uint32_t const N = _route->input()->n_ports().n_audio ();
2028 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2030 for (uint32_t i = 0; i < to_add; ++i) {
2031 ArdourButton* b = manage (new ArdourButton);
2032 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2033 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2035 b->set_name (X_("invert button"));
2038 b->set_text (string_compose (X_("Ø (%1)"), N));
2040 b->set_text (X_("Ø"));
2043 b->set_text (string_compose (X_("Ø%1"), i + 1));
2046 if (N <= _max_invert_buttons) {
2047 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track. Right-click to show menu."), i + 1));
2049 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2052 _invert_buttons.push_back (b);
2053 _invert_button_box.pack_start (*b);
2056 _invert_button_box.set_spacing (1);
2057 _invert_button_box.show_all ();
2061 RouteUI::set_invert_button_state ()
2063 uint32_t const N = _route->input()->n_ports().n_audio();
2064 if (N > _max_invert_buttons) {
2066 /* One button for many channels; explicit active if all channels are inverted,
2067 implicit active if some are, off if none are.
2070 ArdourButton* b = _invert_buttons.front ();
2072 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2073 b->set_active_state (Gtkmm2ext::ExplicitActive);
2074 } else if (_route->phase_control()->any()) {
2075 b->set_active_state (Gtkmm2ext::ImplicitActive);
2077 b->set_active_state (Gtkmm2ext::Off);
2082 /* One button per channel; just set active */
2085 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2086 (*i)->set_active (_route->phase_control()->inverted (j));
2093 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2095 if (ev->button == 1 && i < _invert_buttons.size()) {
2096 uint32_t const N = _route->input()->n_ports().n_audio ();
2097 if (N <= _max_invert_buttons) {
2098 /* left-click inverts phase so long as we have a button per channel */
2099 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2108 RouteUI::invert_press (GdkEventButton* ev)
2110 using namespace Menu_Helpers;
2112 uint32_t const N = _route->input()->n_ports().n_audio();
2113 if (N <= _max_invert_buttons && ev->button != 3) {
2114 /* If we have an invert button per channel, we only pop
2115 up a menu on right-click; left click is handled
2121 delete _invert_menu;
2122 _invert_menu = new Menu;
2123 _invert_menu->set_name ("ArdourContextMenu");
2124 MenuList& items = _invert_menu->items ();
2126 for (uint32_t i = 0; i < N; ++i) {
2127 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2128 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2129 ++_i_am_the_modifier;
2130 e->set_active (_route->phase_control()->inverted (i));
2131 --_i_am_the_modifier;
2134 _invert_menu->popup (0, ev->time);
2140 RouteUI::invert_menu_toggled (uint32_t c)
2142 if (_i_am_the_modifier) {
2147 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2151 RouteUI::set_invert_sensitive (bool yn)
2153 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2154 (*b)->set_sensitive (yn);
2159 RouteUI::request_redraw ()
2162 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2166 /** The Route's gui_changed signal has been emitted */
2168 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2170 if (what_changed.contains (Properties::color)) {
2171 if (set_color_from_route () == 0) {
2172 route_color_changed ();
2176 if (what_changed.contains (Properties::selected)) {
2182 RouteUI::set_selected (bool yn)
2184 Selectable::set_selected (yn);
2186 _route->presentation_info().set_selected (yn);
2191 RouteUI::selected () const
2193 /* XXX not sure if this is a wise design. Probably don't really want
2194 * the cached _selected value from Selectable.
2201 return _route->presentation_info().selected();
2205 RouteUI::track_mode_changed (void)
2208 switch (track()->mode()) {
2209 case ARDOUR::NonLayered:
2210 case ARDOUR::Normal:
2211 rec_enable_button->set_icon (ArdourIcon::RecButton);
2213 case ARDOUR::Destructive:
2214 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2217 rec_enable_button->queue_draw();
2220 /** @return the color that this route should use; it maybe its own,
2221 or it maybe that of its route group.
2225 RouteUI::route_color () const
2228 RouteGroup* g = _route->route_group ();
2231 if (g && g->is_color()) {
2232 set_color_from_rgba (c, GroupTabs::group_color (g));
2235 /* deal with older 4.x color, which was stored in the GUI object state */
2237 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2241 /* old v4.x or earlier session. Use this information */
2245 PresentationInfo::color_t color = 0;
2247 stringstream ss (p);
2249 /* old color format version was:
2251 16bit value for red:16 bit value for green:16 bit value for blue
2258 color |= ((component >> 2) << 16);
2261 color |= ((component >> 2) << 8);
2263 color |= (component >> 2);
2265 _route->presentation_info().set_color (color);
2268 set_color_from_rgba (c, _route->presentation_info().color());
2275 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2277 _showing_sends_to = send_to;
2278 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2282 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2284 if (_route == send_to) {
2285 show_sends_button->set_active (true);
2286 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2288 show_sends_button->set_active (false);
2289 send_blink_connection.disconnect ();
2294 RouteUI::route_group() const
2296 return _route->route_group();
2300 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2301 : WM::ProxyBase (name, string())
2302 , _route (boost::weak_ptr<Route> (route))
2304 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2307 RoutePinWindowProxy::~RoutePinWindowProxy()
2312 ARDOUR::SessionHandlePtr*
2313 RoutePinWindowProxy::session_handle ()
2315 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2316 if (aw) { return aw; }
2321 RoutePinWindowProxy::get (bool create)
2323 boost::shared_ptr<Route> r = _route.lock ();
2332 _window = new PluginPinDialog (r);
2333 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2335 aw->set_session (_session);
2337 _window->show_all ();
2343 RoutePinWindowProxy::route_going_away ()
2347 WM::Manager::instance().remove (this);
2348 going_away_connection.disconnect();
2352 RouteUI::maybe_add_route_print_mgr ()
2354 if (_route->pinmgr_proxy ()) {
2357 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2358 string_compose ("RPM-%1", _route->id()), _route);
2359 wp->set_session (_session);
2361 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2363 wp->set_state (*ui_xml, 0);
2367 void* existing_ui = _route->pinmgr_proxy ();
2369 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2372 _route->set_pingmgr_proxy (wp);
2374 WM::Manager::instance().register_window (wp);
2378 RouteUI::manage_pins ()
2380 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2388 RouteUI::mark_hidden (bool yn)
2390 if (yn != _route->presentation_info().hidden()) {
2391 _route->presentation_info().set_hidden (yn);
2392 return true; // things changed