2 Copyright (C) 2002-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <boost/algorithm/string.hpp>
23 #include <gtkmm2ext/gtk_ui.h>
24 #include <gtkmm2ext/choice.h>
25 #include <gtkmm2ext/doi.h>
26 #include <gtkmm2ext/bindable_button.h>
27 #include <gtkmm2ext/barcontroller.h>
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
31 #include "pbd/memento_command.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour/dB.h"
37 #include "ardour/route_group.h"
38 #include "ardour/solo_isolate_control.h"
39 #include "ardour/vca.h"
40 #include "ardour/vca_manager.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/filename_extensions.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/monitor_control.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/profile.h"
50 #include "ardour/phase_control.h"
51 #include "ardour/send.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/template_utils.h"
56 #include "ardour_button.h"
57 #include "ardour_dialog.h"
58 #include "ardour_ui.h"
59 #include "automation_time_axis.h"
61 #include "group_tabs.h"
62 #include "gui_object.h"
63 #include "gui_thread.h"
65 #include "latency_gui.h"
66 #include "mixer_strip.h"
67 #include "plugin_pin_dialog.h"
69 #include "rgb_macros.h"
70 #include "route_time_axis.h"
73 #include "ui_config.h"
79 using namespace Gtkmm2ext;
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
85 uint32_t RouteUI::_max_invert_buttons = 3;
86 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
87 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
88 std::string RouteUI::program_port_prefix;
90 RouteUI::RouteUI (ARDOUR::Session* sess)
91 : monitor_input_button (0)
92 , monitor_disk_button (0)
100 , output_selector (0)
103 if (program_port_prefix.empty()) {
104 // compare to gtk2_ardour/port_group.cc
105 string lpn (PROGRAM_NAME);
106 boost::to_lower (lpn);
107 program_port_prefix = lpn + ":"; // e.g. "ardour:"
118 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
121 _route.reset (); /* drop reference to route, so that it can be cleaned up */
122 route_connections.drop_connections ();
128 delete comment_window;
129 delete input_selector;
130 delete output_selector;
131 delete monitor_input_button;
132 delete monitor_disk_button;
135 send_blink_connection.disconnect ();
136 rec_blink_connection.disconnect ();
142 self_destruct = true;
148 pre_fader_mute_check = 0;
149 post_fader_mute_check = 0;
150 listen_mute_check = 0;
153 solo_isolated_check = 0;
154 solo_isolated_led = 0;
158 denormal_menu_item = 0;
161 multiple_mute_change = false;
162 multiple_solo_change = false;
163 _i_am_the_modifier = 0;
168 setup_invert_buttons ();
170 mute_button = manage (new ArdourButton);
171 mute_button->set_name ("mute button");
172 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
174 solo_button = manage (new ArdourButton);
175 solo_button->set_name ("solo button");
176 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
177 solo_button->set_no_show_all (true);
179 rec_enable_button = manage (new ArdourButton);
180 rec_enable_button->set_name ("record enable button");
181 rec_enable_button->set_icon (ArdourIcon::RecButton);
182 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
184 if (UIConfiguration::instance().get_blink_rec_arm()) {
185 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
188 show_sends_button = manage (new ArdourButton);
189 show_sends_button->set_name ("send alert button");
190 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
192 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
193 monitor_input_button->set_name ("monitor button");
194 monitor_input_button->set_text (_("In"));
195 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
196 monitor_input_button->set_no_show_all (true);
198 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_disk_button->set_name ("monitor button");
200 monitor_disk_button->set_text (_("Disk"));
201 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
202 monitor_disk_button->set_no_show_all (true);
204 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
205 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
206 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
208 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
209 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
212 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
213 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
215 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
216 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
218 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
219 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
220 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
221 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
223 monitor_input_button->set_distinct_led_click (false);
224 monitor_disk_button->set_distinct_led_click (false);
226 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
227 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
229 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
230 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
232 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
238 route_connections.drop_connections ();
246 _color_picker.reset ();
248 denormal_menu_item = 0;
252 RouteUI::self_delete ()
258 RouteUI::set_route (boost::shared_ptr<Route> rp)
264 if ( !_route->presentation_info().color_set() ) {
265 /* deal with older 4.x color, which was stored in the GUI object state */
267 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
271 /* old v4.x or earlier session. Use this information */
273 int red, green, blue;
278 /* old color format version was:
280 16bit value for red:16 bit value for green:16 bit value for blue
295 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
299 if (set_color_from_route()) {
300 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
304 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
307 delete input_selector;
310 delete output_selector;
313 mute_button->set_controllable (_route->mute_control());
314 solo_button->set_controllable (_route->solo_control());
316 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
318 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
320 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
321 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
322 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
323 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
324 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
325 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
328 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
329 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
330 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
332 track_mode_changed();
336 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
337 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
339 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
341 if (_session->writable() && is_track()) {
342 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
344 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
345 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
347 rec_enable_button->show();
348 rec_enable_button->set_controllable (t->rec_enable_control());
350 if (is_midi_track()) {
351 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
352 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
357 /* this will work for busses and tracks, and needs to be called to
358 set up the name entry/name label display.
362 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
363 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
365 update_monitoring_display ();
368 mute_button->unset_flags (Gtk::CAN_FOCUS);
369 solo_button->unset_flags (Gtk::CAN_FOCUS);
373 if (_route->is_monitor() || _route->is_master()) {
374 solo_button->hide ();
381 setup_invert_buttons ();
382 set_invert_button_state ();
384 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
385 bus_send_display_changed (s);
387 update_mute_display ();
388 update_solo_display ();
390 if (!UIConfiguration::instance().get_blink_rec_arm()) {
391 blink_rec_display(true); // set initial rec-en button state
394 check_rec_enable_sensitivity ();
395 maybe_add_route_print_mgr ();
396 route_color_changed();
397 route_gui_changed (PropertyChange (Properties::selected));
401 RouteUI::polarity_changed ()
407 set_invert_button_state ();
411 RouteUI::mute_press (GdkEventButton* ev)
413 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
417 //if this is a binding action, let the ArdourButton handle it
418 if ( BindingProxy::is_bind_action(ev) )
421 multiple_mute_change = false;
423 if (Keyboard::is_context_menu_event (ev)) {
429 mute_menu->popup(0,ev->time);
435 if (Keyboard::is_button2_event (ev)) {
436 // button2-click is "momentary"
438 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
441 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
443 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
445 /* toggle mute on everything (but
446 * exclude the master and monitor)
448 * because we are going to erase
449 * elements of the list we need to work
453 boost::shared_ptr<RouteList> copy (new RouteList);
455 *copy = *_session->get_routes ();
457 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
458 if ((*i)->is_master() || (*i)->is_monitor()) {
466 _mute_release->routes = copy;
469 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
471 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
473 /* Primary-button1 inverts the implication of
474 the group being active. If the group is
475 active (for mute), then this modifier means
476 "do not apply to mute". If the group is
477 inactive (for mute), then this modifier
478 means "apply to route". This is all
479 accomplished by passing just the actual
480 route, along with the InverseGroup group
483 NOTE: Primary-button2 is MIDI learn.
486 boost::shared_ptr<RouteList> rl;
488 if (ev->button == 1) {
490 rl.reset (new RouteList);
491 rl->push_back (_route);
494 _mute_release->routes = rl;
497 boost::shared_ptr<MuteControl> mc = _route->mute_control();
498 mc->start_touch (_session->audible_frame ());
499 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
504 /* plain click applies change to this route */
506 boost::shared_ptr<RouteList> rl (new RouteList);
507 rl->push_back (_route);
510 _mute_release->routes = rl;
513 boost::shared_ptr<MuteControl> mc = _route->mute_control();
514 mc->start_touch (_session->audible_frame ());
515 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
524 RouteUI::mute_release (GdkEventButton* /*ev*/)
527 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
528 delete _mute_release;
532 _route->mute_control()->stop_touch (false, _session->audible_frame ());
538 RouteUI::edit_output_configuration ()
540 if (output_selector == 0) {
542 boost::shared_ptr<Send> send;
543 boost::shared_ptr<IO> output;
545 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
546 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
547 output = send->output();
549 output = _route->output ();
552 output = _route->output ();
555 output_selector = new IOSelectorWindow (_session, output);
558 if (output_selector->is_visible()) {
559 output_selector->get_toplevel()->get_window()->raise();
561 output_selector->present ();
564 //output_selector->set_keep_above (true);
568 RouteUI::edit_input_configuration ()
570 if (input_selector == 0) {
571 input_selector = new IOSelectorWindow (_session, _route->input());
574 if (input_selector->is_visible()) {
575 input_selector->get_toplevel()->get_window()->raise();
577 input_selector->present ();
580 //input_selector->set_keep_above (true);
584 RouteUI::solo_press(GdkEventButton* ev)
586 /* ignore double/triple clicks */
588 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
592 //if this is a binding action, let the ArdourButton handle it
593 if ( BindingProxy::is_bind_action(ev) )
596 multiple_solo_change = false;
598 if (Keyboard::is_context_menu_event (ev)) {
600 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
601 ! (solo_safe_led && solo_safe_led->is_visible())) {
603 if (solo_menu == 0) {
607 solo_menu->popup (1, ev->time);
612 if (Keyboard::is_button2_event (ev)) {
614 // button2-click is "momentary"
615 _solo_release = new SoloMuteRelease (_route->self_soloed());
618 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
620 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
622 /* Primary-Tertiary-click applies change to all routes */
625 _solo_release->routes = _session->get_routes ();
628 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
630 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
632 /* Primary-Secondary-click: exclusively solo this track */
635 _solo_release->exclusive = true;
637 _solo_release->routes_on.reset (new RouteList);
638 _solo_release->routes_off.reset (new RouteList);
640 boost::shared_ptr<RouteList> routes = _session->get_routes();
641 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
643 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
647 if ((*i)->soloed ()) {
648 _solo_release->routes_on->push_back (*i);
650 _solo_release->routes_off->push_back (*i);
655 boost::shared_ptr<RouteList> rl (new RouteList);
656 boost::shared_ptr<RouteList> routes = _session->get_routes();
657 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
659 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
663 if ((*i)->soloed ()) {
667 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
669 if (Config->get_solo_control_is_listen_control()) {
670 /* ??? we need a just_one_listen() method */
673 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
676 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
678 // shift-click: toggle solo isolated status
680 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
681 delete _solo_release;
684 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
686 /* Primary-button1: solo mix group.
687 NOTE: Primary-button2 is MIDI learn.
690 /* Primary-button1 applies change to the mix group even if it is not active
691 NOTE: Primary-button2 is MIDI learn.
694 boost::shared_ptr<RouteList> rl;
696 if (ev->button == 1) {
698 /* Primary-button1 inverts the implication of
699 the group being active. If the group is
700 active (for solo), then this modifier means
701 "do not apply to solo". If the group is
702 inactive (for mute), then this modifier
703 means "apply to route". This is all
704 accomplished by passing just the actual
705 route, along with the InverseGroup group
708 NOTE: Primary-button2 is MIDI learn.
711 rl.reset (new RouteList);
712 rl->push_back (_route);
715 _solo_release->routes = rl;
718 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
721 delete _solo_release;
726 /* click: solo this route */
728 boost::shared_ptr<RouteList> rl (new RouteList);
729 rl->push_back (route());
732 _solo_release->routes = rl;
735 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
744 RouteUI::solo_release (GdkEventButton* /*ev*/)
747 if (_solo_release->exclusive) {
748 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
749 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
751 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
754 delete _solo_release;
762 RouteUI::rec_enable_press(GdkEventButton* ev)
764 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
768 //if this is a binding action, let the ArdourButton handle it
769 if ( BindingProxy::is_bind_action(ev) )
772 if (!_session->engine().connected()) {
773 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
778 if (is_midi_track()) {
780 /* rec-enable button exits from step editing */
782 if (midi_track()->step_editing()) {
783 midi_track()->set_step_editing (false);
788 if (is_track() && rec_enable_button) {
790 if (Keyboard::is_button2_event (ev)) {
792 //rec arm does not have a momentary mode
795 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
797 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
799 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
801 /* Primary-button1 applies change to the route group (even if it is not active)
802 NOTE: Primary-button2 is MIDI learn.
805 if (ev->button == 1) {
807 boost::shared_ptr<RouteList> rl;
809 rl.reset (new RouteList);
810 rl->push_back (_route);
812 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
815 } else if (Keyboard::is_context_menu_event (ev)) {
817 /* do this on release */
821 boost::shared_ptr<Track> trk = track();
822 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
830 RouteUI::update_monitoring_display ()
836 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
842 MonitorState ms = t->monitoring_state();
844 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
845 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
847 if (ms & MonitoringInput) {
848 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
850 monitor_input_button->unset_active_state ();
854 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
855 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
857 if (ms & MonitoringDisk) {
858 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
860 monitor_disk_button->unset_active_state ();
866 RouteUI::monitor_input_press(GdkEventButton*)
872 RouteUI::monitor_input_release(GdkEventButton* ev)
874 return monitor_release (ev, MonitorInput);
878 RouteUI::monitor_disk_press (GdkEventButton*)
884 RouteUI::monitor_disk_release (GdkEventButton* ev)
886 return monitor_release (ev, MonitorDisk);
890 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
892 if (ev->button != 1) {
896 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
903 boost::shared_ptr<RouteList> rl;
905 /* XXX for now, monitoring choices are orthogonal. cue monitoring
906 will follow in 3.X but requires mixing the input and playback (disk)
907 signal together, which requires yet more buffers.
910 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
911 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
913 /* this line will change when the options are non-orthogonal */
914 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
918 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
919 rl = _session->get_routes ();
921 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
922 if (_route->route_group() && _route->route_group()->is_monitoring()) {
923 rl = _route->route_group()->route_list();
925 rl.reset (new RouteList);
926 rl->push_back (route());
929 rl.reset (new RouteList);
930 rl->push_back (route());
933 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
939 RouteUI::build_record_menu ()
942 record_menu = new Menu;
943 record_menu->set_name ("ArdourContextMenu");
944 using namespace Menu_Helpers;
945 MenuList& items = record_menu->items();
947 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
948 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
950 if (is_midi_track()) {
951 items.push_back (SeparatorElem());
952 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
953 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
957 if (step_edit_item) {
958 if (track()->rec_enable_control()->get_value()) {
959 step_edit_item->set_sensitive (false);
961 step_edit_item->set_active (midi_track()->step_editing());
964 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
965 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
970 RouteUI::toggle_step_edit ()
972 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
976 midi_track()->set_step_editing (step_edit_item->get_active());
980 RouteUI::toggle_rec_safe ()
982 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
988 /* This check is made inside the control too, but dong it here can't
992 if (_route->rec_enable_control()->get_value()) {
996 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
1000 RouteUI::step_edit_changed (bool yn)
1003 if (rec_enable_button) {
1004 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1007 start_step_editing ();
1009 if (step_edit_item) {
1010 step_edit_item->set_active (true);
1015 if (rec_enable_button) {
1016 rec_enable_button->unset_active_state ();
1019 stop_step_editing ();
1021 if (step_edit_item) {
1022 step_edit_item->set_active (false);
1028 RouteUI::rec_enable_release (GdkEventButton* ev)
1030 if (Keyboard::is_context_menu_event (ev)) {
1031 build_record_menu ();
1033 record_menu->popup (1, ev->time);
1042 RouteUI::build_sends_menu ()
1044 using namespace Menu_Helpers;
1046 sends_menu = new Menu;
1047 sends_menu->set_name ("ArdourContextMenu");
1048 MenuList& items = sends_menu->items();
1051 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1055 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1059 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1063 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1067 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1071 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1074 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1078 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1081 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1082 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1083 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1088 RouteUI::create_sends (Placement p, bool include_buses)
1090 _session->globally_add_internal_sends (_route, p, include_buses);
1094 RouteUI::create_selected_sends (Placement p, bool include_buses)
1096 boost::shared_ptr<RouteList> rlist (new RouteList);
1097 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1099 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1100 RouteTimeAxisView* rtv;
1102 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1103 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1104 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1105 rlist->push_back (rui->route());
1111 _session->add_internal_sends (_route, p, rlist);
1115 RouteUI::set_sends_gain_from_track ()
1117 _session->globally_set_send_gains_from_track (_route);
1121 RouteUI::set_sends_gain_to_zero ()
1123 _session->globally_set_send_gains_to_zero (_route);
1127 RouteUI::set_sends_gain_to_unity ()
1129 _session->globally_set_send_gains_to_unity (_route);
1133 RouteUI::show_sends_press(GdkEventButton* ev)
1135 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1139 if (!is_track() && show_sends_button) {
1141 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1143 // do nothing on midi sigc::bind event
1146 } else if (Keyboard::is_context_menu_event (ev)) {
1148 if (sends_menu == 0) {
1149 build_sends_menu ();
1152 sends_menu->popup (0, ev->time);
1156 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1159 set_showing_sends_to (boost::shared_ptr<Route> ());
1161 set_showing_sends_to (_route);
1170 RouteUI::show_sends_release (GdkEventButton*)
1176 RouteUI::send_blink (bool onoff)
1178 if (!show_sends_button) {
1183 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1185 show_sends_button->unset_active_state ();
1189 Gtkmm2ext::ActiveState
1190 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1192 boost::shared_ptr<SoloControl> sc = s->solo_control();
1195 return Gtkmm2ext::Off;
1198 if (!sc->can_solo()) {
1199 return Gtkmm2ext::Off;
1203 if (sc->self_soloed()) {
1204 return Gtkmm2ext::ExplicitActive;
1205 } else if (sc->soloed_by_others()) {
1206 return Gtkmm2ext::ImplicitActive;
1208 return Gtkmm2ext::Off;
1212 Gtkmm2ext::ActiveState
1213 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1215 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1218 return Gtkmm2ext::Off;
1221 if (s->is_master() || s->is_monitor()) {
1222 return Gtkmm2ext::Off;
1225 if (sc->solo_isolated()) {
1226 return Gtkmm2ext::ExplicitActive;
1228 return Gtkmm2ext::Off;
1232 Gtkmm2ext::ActiveState
1233 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1235 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1238 return Gtkmm2ext::Off;
1241 if (s->is_master() || s->is_monitor()) {
1242 return Gtkmm2ext::Off;
1245 if (sc->solo_safe()) {
1246 return Gtkmm2ext::ExplicitActive;
1248 return Gtkmm2ext::Off;
1253 RouteUI::update_solo_display ()
1255 bool yn = _route->solo_safe_control()->solo_safe ();
1257 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1258 solo_safe_check->set_active (yn);
1261 yn = _route->solo_isolate_control()->solo_isolated ();
1263 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1264 solo_isolated_check->set_active (yn);
1267 set_button_names ();
1269 if (solo_isolated_led) {
1270 if (_route->solo_isolate_control()->solo_isolated()) {
1271 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1273 solo_isolated_led->unset_active_state ();
1277 if (solo_safe_led) {
1278 if (_route->solo_safe_control()->solo_safe()) {
1279 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1281 solo_safe_led->unset_active_state ();
1285 solo_button->set_active_state (solo_active_state (_route));
1287 /* some changes to solo status can affect mute display, so catch up
1290 update_mute_display ();
1294 RouteUI::solo_changed_so_update_mute ()
1296 update_mute_display ();
1300 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1302 boost::shared_ptr<MuteControl> mc = s->mute_control();
1304 if (s->is_monitor()) {
1305 return Gtkmm2ext::Off;
1309 return Gtkmm2ext::Off;
1312 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1314 if (mc->muted_by_self ()) {
1316 return Gtkmm2ext::ExplicitActive;
1317 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1318 /* this will reflect both solo mutes AND master mutes */
1319 return Gtkmm2ext::ImplicitActive;
1321 /* no mute at all */
1322 return Gtkmm2ext::Off;
1327 if (mc->muted_by_self()) {
1329 return Gtkmm2ext::ExplicitActive;
1330 } else if (mc->muted_by_masters ()) {
1331 /* this shows only master mutes, not mute-by-others-soloing */
1332 return Gtkmm2ext::ImplicitActive;
1334 /* no mute at all */
1335 return Gtkmm2ext::Off;
1339 return ActiveState(0);
1343 RouteUI::update_mute_display ()
1349 mute_button->set_active_state (mute_active_state (_session, _route));
1354 RouteUI::route_rec_enable_changed ()
1356 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1360 RouteUI::session_rec_enable_changed ()
1362 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1366 RouteUI::blink_rec_display (bool blinkOn)
1368 if (!rec_enable_button || !_route) {
1372 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1380 if (track()->rec_enable_control()->get_value()) {
1381 switch (_session->record_status ()) {
1382 case Session::Recording:
1383 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1386 case Session::Disabled:
1387 case Session::Enabled:
1388 if (UIConfiguration::instance().get_blink_rec_arm()) {
1389 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1391 rec_enable_button->set_active_state ( ImplicitActive );
1396 if (step_edit_item) {
1397 step_edit_item->set_sensitive (false);
1401 rec_enable_button->unset_active_state ();
1403 if (step_edit_item) {
1404 step_edit_item->set_sensitive (true);
1408 check_rec_enable_sensitivity ();
1412 RouteUI::build_solo_menu (void)
1414 using namespace Menu_Helpers;
1416 solo_menu = new Menu;
1417 solo_menu->set_name ("ArdourContextMenu");
1418 MenuList& items = solo_menu->items();
1419 Gtk::CheckMenuItem* check;
1421 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1422 check->set_active (_route->solo_isolate_control()->solo_isolated());
1423 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1424 items.push_back (CheckMenuElem(*check));
1425 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1428 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1429 check->set_active (_route->solo_safe_control()->solo_safe());
1430 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1431 items.push_back (CheckMenuElem(*check));
1432 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1435 //items.push_back (SeparatorElem());
1436 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1441 RouteUI::build_mute_menu(void)
1443 using namespace Menu_Helpers;
1445 mute_menu = new Menu;
1446 mute_menu->set_name ("ArdourContextMenu");
1448 MenuList& items = mute_menu->items();
1450 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1451 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1452 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1453 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1454 pre_fader_mute_check->show_all();
1456 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1457 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1458 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1459 items.push_back (CheckMenuElem(*post_fader_mute_check));
1460 post_fader_mute_check->show_all();
1462 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1463 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1464 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1465 items.push_back (CheckMenuElem(*listen_mute_check));
1466 listen_mute_check->show_all();
1468 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1469 init_mute_menu(MuteMaster::Main, main_mute_check);
1470 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1471 items.push_back (CheckMenuElem(*main_mute_check));
1472 main_mute_check->show_all();
1474 //items.push_back (SeparatorElem());
1475 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1477 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1481 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1483 check->set_active (_route->mute_control()->mute_points() & mp);
1487 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1489 if (check->get_active()) {
1490 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1492 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1497 RouteUI::muting_change ()
1499 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1502 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1504 yn = (current & MuteMaster::PreFader);
1506 if (pre_fader_mute_check->get_active() != yn) {
1507 pre_fader_mute_check->set_active (yn);
1510 yn = (current & MuteMaster::PostFader);
1512 if (post_fader_mute_check->get_active() != yn) {
1513 post_fader_mute_check->set_active (yn);
1516 yn = (current & MuteMaster::Listen);
1518 if (listen_mute_check->get_active() != yn) {
1519 listen_mute_check->set_active (yn);
1522 yn = (current & MuteMaster::Main);
1524 if (main_mute_check->get_active() != yn) {
1525 main_mute_check->set_active (yn);
1530 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1532 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1536 bool view = solo_isolated_led->active_state();
1537 bool model = _route->solo_isolate_control()->solo_isolated();
1539 /* called BEFORE the view has changed */
1541 if (ev->button == 1) {
1542 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1545 /* disable isolate for all routes */
1546 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1548 /* enable isolate for all routes */
1549 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1554 if (model == view) {
1556 /* flip just this route */
1558 boost::shared_ptr<RouteList> rl (new RouteList);
1559 rl->push_back (_route);
1560 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1569 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1571 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1575 bool view = solo_safe_led->active_state();
1576 bool model = _route->solo_safe_control()->solo_safe();
1578 if (ev->button == 1) {
1579 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1580 boost::shared_ptr<RouteList> rl (_session->get_routes());
1582 /* disable solo safe for all routes */
1583 DisplaySuspender ds;
1584 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1585 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1588 /* enable solo safe for all routes */
1589 DisplaySuspender ds;
1590 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1591 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1596 if (model == view) {
1597 /* flip just this route */
1598 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1607 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1609 bool view = check->get_active();
1610 bool model = _route->solo_isolate_control()->solo_isolated();
1612 /* called AFTER the view has changed */
1614 if (model != view) {
1615 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1620 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1622 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1625 /** Ask the user to choose a colour, and then apply that color to my route
1628 RouteUI::choose_color ()
1630 _color_picker.popup (_route);
1633 /** Set the route's own color. This may not be used for display if
1634 * the route is in a group which shares its color with its routes.
1637 RouteUI::set_color (uint32_t c)
1639 _route->presentation_info().set_color (c);
1642 /** @return GUI state ID for things that are common to the route in all its representations */
1644 RouteUI::route_state_id () const
1646 return string_compose (X_("route %1"), _route->id().to_s());
1650 RouteUI::set_color_from_route ()
1652 if (_route->presentation_info().color_set()) {
1653 return 0; /* nothing to do */
1656 return 1; /* pick a color */
1659 /** @return true if this name should be used for the route, otherwise false */
1661 RouteUI::verify_new_route_name (const std::string& name)
1663 if (name.find (':') == string::npos) {
1667 MessageDialog colon_msg (
1668 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1669 false, MESSAGE_QUESTION, BUTTONS_NONE
1672 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1673 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1675 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1679 RouteUI::route_rename ()
1681 ArdourPrompter name_prompter (true);
1686 name_prompter.set_title (_("Rename Track"));
1688 name_prompter.set_title (_("Rename Bus"));
1690 name_prompter.set_prompt (_("New name:"));
1691 name_prompter.set_initial_text (_route->name());
1692 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1693 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1694 name_prompter.show_all ();
1697 switch (name_prompter.run ()) {
1698 case Gtk::RESPONSE_ACCEPT:
1699 name_prompter.get_result (result);
1700 name_prompter.hide ();
1701 if (result.length()) {
1702 if (verify_new_route_name (result)) {
1703 _route->set_name (result);
1706 /* back to name prompter */
1710 /* nothing entered, just get out of here */
1725 RouteUI::toggle_comment_editor ()
1727 // if (ignore_toggle) {
1731 if (comment_window && comment_window->is_visible ()) {
1732 comment_window->hide ();
1734 open_comment_editor ();
1740 RouteUI::open_comment_editor ()
1742 if (comment_window == 0) {
1743 setup_comment_editor ();
1747 title = _route->name();
1748 title += _(": comment editor");
1750 comment_window->set_title (title);
1751 comment_window->present();
1755 RouteUI::setup_comment_editor ()
1757 comment_window = new ArdourWindow (""); // title will be reset to show route
1758 comment_window->set_skip_taskbar_hint (true);
1759 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1760 comment_window->set_default_size (400, 200);
1762 comment_area = manage (new TextView());
1763 comment_area->set_name ("MixerTrackCommentArea");
1764 comment_area->set_wrap_mode (WRAP_WORD);
1765 comment_area->set_editable (true);
1766 comment_area->get_buffer()->set_text (_route->comment());
1767 comment_area->show ();
1769 comment_window->add (*comment_area);
1773 RouteUI::comment_changed ()
1775 ignore_comment_edit = true;
1777 comment_area->get_buffer()->set_text (_route->comment());
1779 ignore_comment_edit = false;
1783 RouteUI::comment_editor_done_editing ()
1785 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1787 string const str = comment_area->get_buffer()->get_text();
1788 if (str == _route->comment ()) {
1792 _route->set_comment (str, this);
1796 RouteUI::set_route_active (bool a, bool apply_to_selection)
1798 if (apply_to_selection) {
1799 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1801 _route->set_active (a, this);
1806 RouteUI::duplicate_selected_routes ()
1808 ARDOUR_UI::instance()->start_duplicate_routes();
1812 RouteUI::toggle_denormal_protection ()
1814 if (denormal_menu_item) {
1818 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1820 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1821 _route->set_denormal_protection (x);
1827 RouteUI::denormal_protection_changed ()
1829 if (denormal_menu_item) {
1830 denormal_menu_item->set_active (_route->denormal_protection());
1835 RouteUI::disconnect_input ()
1837 _route->input()->disconnect (this);
1841 RouteUI::disconnect_output ()
1843 _route->output()->disconnect (this);
1847 RouteUI::is_track () const
1849 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1852 boost::shared_ptr<Track>
1853 RouteUI::track() const
1855 return boost::dynamic_pointer_cast<Track>(_route);
1859 RouteUI::is_audio_track () const
1861 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1864 boost::shared_ptr<AudioTrack>
1865 RouteUI::audio_track() const
1867 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1871 RouteUI::is_midi_track () const
1873 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1876 boost::shared_ptr<MidiTrack>
1877 RouteUI::midi_track() const
1879 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1883 RouteUI::has_audio_outputs () const
1885 return (_route->n_outputs().n_audio() > 0);
1889 RouteUI::map_frozen ()
1891 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1893 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1896 check_rec_enable_sensitivity ();
1901 RouteUI::adjust_latency ()
1903 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1907 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1910 std::string safe_name;
1913 prompter.get_result (name, true);
1915 safe_name = legalize_for_path (name);
1916 safe_name += template_suffix;
1918 path = Glib::build_filename (dir, safe_name);
1920 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1921 bool overwrite = overwrite_file_dialog (prompter,
1922 _("Confirm Template Overwrite"),
1923 _("A template already exists with that name. Do you want to overwrite it?"));
1930 _route->save_as_template (path, name);
1936 RouteUI::save_as_template ()
1940 dir = ARDOUR::user_route_template_directory ();
1942 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1943 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1947 ArdourPrompter prompter (true); // modal
1949 prompter.set_title (_("Save As Template"));
1950 prompter.set_prompt (_("Template name:"));
1951 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1953 bool finished = false;
1955 switch (prompter.run()) {
1956 case RESPONSE_ACCEPT:
1957 finished = process_save_template_prompter (prompter, dir);
1967 RouteUI::check_rec_enable_sensitivity ()
1969 if (!rec_enable_button) {
1970 assert (0); // This should not happen
1973 if (!_session->writable()) {
1974 rec_enable_button->set_sensitive (false);
1978 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1979 rec_enable_button->set_sensitive (false);
1980 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1981 rec_enable_button->set_sensitive (false);
1983 rec_enable_button->set_sensitive (true);
1985 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1986 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1988 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1990 update_monitoring_display ();
1994 RouteUI::parameter_changed (string const & p)
1996 /* this handles RC and per-session parameter changes */
1998 if (p == "disable-disarm-during-roll") {
1999 check_rec_enable_sensitivity ();
2000 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2001 set_button_names ();
2002 } else if (p == "session-monitoring") {
2003 update_monitoring_display ();
2004 } else if (p == "auto-input") {
2005 update_monitoring_display ();
2006 } else if (p == "blink-rec-arm") {
2007 if (UIConfiguration::instance().get_blink_rec_arm()) {
2008 rec_blink_connection.disconnect ();
2009 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2011 rec_blink_connection.disconnect ();
2012 RouteUI::blink_rec_display(false);
2018 RouteUI::step_gain_up ()
2020 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2024 RouteUI::page_gain_up ()
2026 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2030 RouteUI::step_gain_down ()
2032 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2036 RouteUI::page_gain_down ()
2038 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2042 RouteUI::setup_invert_buttons ()
2044 /* remove old invert buttons */
2045 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2046 _invert_button_box.remove (**i);
2049 _invert_buttons.clear ();
2051 if (!_route || !_route->input()) {
2055 uint32_t const N = _route->input()->n_ports().n_audio ();
2057 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2059 for (uint32_t i = 0; i < to_add; ++i) {
2060 ArdourButton* b = manage (new ArdourButton);
2061 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2062 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2064 b->set_name (X_("invert button"));
2067 b->set_text (string_compose (X_("Ø (%1)"), N));
2069 b->set_text (X_("Ø"));
2072 b->set_text (string_compose (X_("Ø%1"), i + 1));
2075 if (N <= _max_invert_buttons) {
2076 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));
2078 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2081 _invert_buttons.push_back (b);
2082 _invert_button_box.pack_start (*b);
2085 _invert_button_box.set_spacing (1);
2086 _invert_button_box.show_all ();
2090 RouteUI::set_invert_button_state ()
2092 uint32_t const N = _route->input()->n_ports().n_audio();
2093 if (N > _max_invert_buttons) {
2095 /* One button for many channels; explicit active if all channels are inverted,
2096 implicit active if some are, off if none are.
2099 ArdourButton* b = _invert_buttons.front ();
2101 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2102 b->set_active_state (Gtkmm2ext::ExplicitActive);
2103 } else if (_route->phase_control()->any()) {
2104 b->set_active_state (Gtkmm2ext::ImplicitActive);
2106 b->set_active_state (Gtkmm2ext::Off);
2111 /* One button per channel; just set active */
2114 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2115 (*i)->set_active (_route->phase_control()->inverted (j));
2122 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2124 if (ev->button == 1 && i < _invert_buttons.size()) {
2125 uint32_t const N = _route->input()->n_ports().n_audio ();
2126 if (N <= _max_invert_buttons) {
2127 /* left-click inverts phase so long as we have a button per channel */
2128 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2137 RouteUI::invert_press (GdkEventButton* ev)
2139 using namespace Menu_Helpers;
2141 uint32_t const N = _route->input()->n_ports().n_audio();
2142 if (N <= _max_invert_buttons && ev->button != 3) {
2143 /* If we have an invert button per channel, we only pop
2144 up a menu on right-click; left click is handled
2150 delete _invert_menu;
2151 _invert_menu = new Menu;
2152 _invert_menu->set_name ("ArdourContextMenu");
2153 MenuList& items = _invert_menu->items ();
2155 for (uint32_t i = 0; i < N; ++i) {
2156 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2157 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2158 ++_i_am_the_modifier;
2159 e->set_active (_route->phase_control()->inverted (i));
2160 --_i_am_the_modifier;
2163 _invert_menu->popup (0, ev->time);
2169 RouteUI::invert_menu_toggled (uint32_t c)
2171 if (_i_am_the_modifier) {
2176 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2180 RouteUI::set_invert_sensitive (bool yn)
2182 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2183 (*b)->set_sensitive (yn);
2188 RouteUI::request_redraw ()
2191 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2195 /** The Route's gui_changed signal has been emitted */
2197 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2199 if (what_changed.contains (Properties::color)) {
2200 if (set_color_from_route () == 0) {
2201 route_color_changed ();
2207 RouteUI::track_mode_changed (void)
2210 switch (track()->mode()) {
2211 case ARDOUR::NonLayered:
2212 case ARDOUR::Normal:
2213 rec_enable_button->set_icon (ArdourIcon::RecButton);
2215 case ARDOUR::Destructive:
2216 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2219 rec_enable_button->queue_draw();
2222 /** @return the color that this route should use; it maybe its own,
2223 or it maybe that of its route group.
2227 RouteUI::route_color () const
2230 RouteGroup* g = _route->route_group ();
2233 if (g && g->is_color()) {
2234 set_color_from_rgba (c, GroupTabs::group_color (g));
2236 set_color_from_rgba (c, _route->presentation_info().color());
2243 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2245 _showing_sends_to = send_to;
2246 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2250 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2252 if (_route == send_to) {
2253 show_sends_button->set_active (true);
2254 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2256 show_sends_button->set_active (false);
2257 send_blink_connection.disconnect ();
2262 RouteUI::route_group() const
2264 return _route->route_group();
2268 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2269 : WM::ProxyBase (name, string())
2270 , _route (boost::weak_ptr<Route> (route))
2272 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2275 RoutePinWindowProxy::~RoutePinWindowProxy()
2280 ARDOUR::SessionHandlePtr*
2281 RoutePinWindowProxy::session_handle ()
2283 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2284 if (aw) { return aw; }
2289 RoutePinWindowProxy::get (bool create)
2291 boost::shared_ptr<Route> r = _route.lock ();
2300 _window = new PluginPinDialog (r);
2301 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2303 aw->set_session (_session);
2305 _window->show_all ();
2311 RoutePinWindowProxy::route_going_away ()
2315 WM::Manager::instance().remove (this);
2316 going_away_connection.disconnect();
2321 RouteUI::maybe_add_route_print_mgr ()
2323 if (_route->pinmgr_proxy ()) {
2326 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2327 string_compose ("RPM-%1", _route->id()), _route);
2328 wp->set_session (_session);
2330 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2332 wp->set_state (*ui_xml, 0);
2336 void* existing_ui = _route->pinmgr_proxy ();
2338 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2341 _route->set_pingmgr_proxy (wp);
2343 WM::Manager::instance().register_window (wp);
2347 RouteUI::manage_pins ()
2349 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2357 RouteUI::fan_out (bool to_busses, bool group)
2359 DisplaySuspender ds;
2360 boost::shared_ptr<ARDOUR::Route> route = _route;
2361 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2364 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2365 if (route->n_outputs ().n_audio () != n_outputs) {
2366 MessageDialog msg (string_compose (
2367 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2368 n_outputs, route->n_outputs ().n_audio ()));
2373 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2375 /* count busses and channels/bus */
2376 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2377 std::map<std::string, uint32_t> busnames;
2378 for (uint32_t p = 0; p < n_outputs; ++p) {
2379 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2380 std::string bn = BUSNAME;
2384 if (busnames.size () < 2) {
2385 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2390 uint32_t outputs = 2;
2391 if (_session->master_out ()) {
2392 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2395 route->output ()->disconnect (this);
2396 route->panner_shell ()->set_bypassed (true);
2399 for (uint32_t p = 0; p < n_outputs; ++p) {
2400 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2401 std::string bn = BUSNAME;
2402 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2405 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2409 list<boost::shared_ptr<AudioTrack> > tl =
2410 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2414 boost::shared_ptr<ControlList> cl (new ControlList);
2415 cl->push_back (r->monitoring_control ());
2416 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2418 r->input ()->disconnect (this);
2420 to_group.push_back (r);
2421 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2426 RouteGroup* rg = NULL;
2427 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2428 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2429 if ((*i)->name () == pi->name ()) {
2435 rg = new RouteGroup (*_session, pi->name ());
2436 _session->add_route_group (rg);
2437 rg->set_gain (false);
2440 GroupTabs::set_group_color (rg, route->presentation_info().color());
2441 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2448 RouteUI::mark_hidden (bool yn)
2450 if (yn != _route->presentation_info().hidden()) {
2451 _route->presentation_info().set_hidden (yn);
2452 return true; // things changed
2457 boost::shared_ptr<Stripable>
2458 RouteUI::stripable () const