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 /* Primary-Tertiary-click applies change to all routes */
920 rl = _session->get_routes ();
921 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
922 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
923 /* Primary-click overrides group */
924 rl.reset (new RouteList);
925 rl->push_back (route());
926 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
928 rl.reset (new RouteList);
929 rl->push_back (route());
930 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
937 RouteUI::build_record_menu ()
940 record_menu = new Menu;
941 record_menu->set_name ("ArdourContextMenu");
942 using namespace Menu_Helpers;
943 MenuList& items = record_menu->items();
945 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
946 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
948 if (is_midi_track()) {
949 items.push_back (SeparatorElem());
950 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
951 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
955 if (step_edit_item) {
956 if (track()->rec_enable_control()->get_value()) {
957 step_edit_item->set_sensitive (false);
959 step_edit_item->set_active (midi_track()->step_editing());
962 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
963 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
968 RouteUI::toggle_step_edit ()
970 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
974 midi_track()->set_step_editing (step_edit_item->get_active());
978 RouteUI::toggle_rec_safe ()
980 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
986 /* This check is made inside the control too, but dong it here can't
990 if (_route->rec_enable_control()->get_value()) {
994 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
998 RouteUI::step_edit_changed (bool yn)
1001 if (rec_enable_button) {
1002 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1005 start_step_editing ();
1007 if (step_edit_item) {
1008 step_edit_item->set_active (true);
1013 if (rec_enable_button) {
1014 rec_enable_button->unset_active_state ();
1017 stop_step_editing ();
1019 if (step_edit_item) {
1020 step_edit_item->set_active (false);
1026 RouteUI::rec_enable_release (GdkEventButton* ev)
1028 if (Keyboard::is_context_menu_event (ev)) {
1029 build_record_menu ();
1031 record_menu->popup (1, ev->time);
1040 RouteUI::build_sends_menu ()
1042 using namespace Menu_Helpers;
1044 sends_menu = new Menu;
1045 sends_menu->set_name ("ArdourContextMenu");
1046 MenuList& items = sends_menu->items();
1049 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1053 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1057 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1061 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1065 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1069 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1072 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1076 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1079 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1080 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1081 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1086 RouteUI::create_sends (Placement p, bool include_buses)
1088 _session->globally_add_internal_sends (_route, p, include_buses);
1092 RouteUI::create_selected_sends (Placement p, bool include_buses)
1094 boost::shared_ptr<RouteList> rlist (new RouteList);
1095 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1097 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1098 RouteTimeAxisView* rtv;
1100 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1101 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1102 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1103 rlist->push_back (rui->route());
1109 _session->add_internal_sends (_route, p, rlist);
1113 RouteUI::set_sends_gain_from_track ()
1115 _session->globally_set_send_gains_from_track (_route);
1119 RouteUI::set_sends_gain_to_zero ()
1121 _session->globally_set_send_gains_to_zero (_route);
1125 RouteUI::set_sends_gain_to_unity ()
1127 _session->globally_set_send_gains_to_unity (_route);
1131 RouteUI::show_sends_press(GdkEventButton* ev)
1133 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1137 if (!is_track() && show_sends_button) {
1139 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1141 // do nothing on midi sigc::bind event
1144 } else if (Keyboard::is_context_menu_event (ev)) {
1146 if (sends_menu == 0) {
1147 build_sends_menu ();
1150 sends_menu->popup (0, ev->time);
1154 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1157 set_showing_sends_to (boost::shared_ptr<Route> ());
1159 set_showing_sends_to (_route);
1168 RouteUI::show_sends_release (GdkEventButton*)
1174 RouteUI::send_blink (bool onoff)
1176 if (!show_sends_button) {
1181 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1183 show_sends_button->unset_active_state ();
1187 Gtkmm2ext::ActiveState
1188 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1190 boost::shared_ptr<SoloControl> sc = s->solo_control();
1193 return Gtkmm2ext::Off;
1196 if (!sc->can_solo()) {
1197 return Gtkmm2ext::Off;
1201 if (sc->self_soloed()) {
1202 return Gtkmm2ext::ExplicitActive;
1203 } else if (sc->soloed_by_others()) {
1204 return Gtkmm2ext::ImplicitActive;
1206 return Gtkmm2ext::Off;
1210 Gtkmm2ext::ActiveState
1211 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1213 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1216 return Gtkmm2ext::Off;
1219 if (s->is_master() || s->is_monitor()) {
1220 return Gtkmm2ext::Off;
1223 if (sc->solo_isolated()) {
1224 return Gtkmm2ext::ExplicitActive;
1226 return Gtkmm2ext::Off;
1230 Gtkmm2ext::ActiveState
1231 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1233 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1236 return Gtkmm2ext::Off;
1239 if (s->is_master() || s->is_monitor()) {
1240 return Gtkmm2ext::Off;
1243 if (sc->solo_safe()) {
1244 return Gtkmm2ext::ExplicitActive;
1246 return Gtkmm2ext::Off;
1251 RouteUI::update_solo_display ()
1253 bool yn = _route->solo_safe_control()->solo_safe ();
1255 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1256 solo_safe_check->set_active (yn);
1259 yn = _route->solo_isolate_control()->solo_isolated ();
1261 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1262 solo_isolated_check->set_active (yn);
1265 set_button_names ();
1267 if (solo_isolated_led) {
1268 if (_route->solo_isolate_control()->solo_isolated()) {
1269 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1271 solo_isolated_led->unset_active_state ();
1275 if (solo_safe_led) {
1276 if (_route->solo_safe_control()->solo_safe()) {
1277 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1279 solo_safe_led->unset_active_state ();
1283 solo_button->set_active_state (solo_active_state (_route));
1285 /* some changes to solo status can affect mute display, so catch up
1288 update_mute_display ();
1292 RouteUI::solo_changed_so_update_mute ()
1294 update_mute_display ();
1298 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1300 boost::shared_ptr<MuteControl> mc = s->mute_control();
1302 if (s->is_monitor()) {
1303 return Gtkmm2ext::Off;
1307 return Gtkmm2ext::Off;
1310 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1312 if (mc->muted_by_self ()) {
1314 return Gtkmm2ext::ExplicitActive;
1315 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1316 /* this will reflect both solo mutes AND master mutes */
1317 return Gtkmm2ext::ImplicitActive;
1319 /* no mute at all */
1320 return Gtkmm2ext::Off;
1325 if (mc->muted_by_self()) {
1327 return Gtkmm2ext::ExplicitActive;
1328 } else if (mc->muted_by_masters ()) {
1329 /* this shows only master mutes, not mute-by-others-soloing */
1330 return Gtkmm2ext::ImplicitActive;
1332 /* no mute at all */
1333 return Gtkmm2ext::Off;
1337 return ActiveState(0);
1341 RouteUI::update_mute_display ()
1347 mute_button->set_active_state (mute_active_state (_session, _route));
1352 RouteUI::route_rec_enable_changed ()
1354 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1358 RouteUI::session_rec_enable_changed ()
1360 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1364 RouteUI::blink_rec_display (bool blinkOn)
1366 if (!rec_enable_button || !_route) {
1370 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1378 if (track()->rec_enable_control()->get_value()) {
1379 switch (_session->record_status ()) {
1380 case Session::Recording:
1381 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1384 case Session::Disabled:
1385 case Session::Enabled:
1386 if (UIConfiguration::instance().get_blink_rec_arm()) {
1387 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1389 rec_enable_button->set_active_state ( ImplicitActive );
1394 if (step_edit_item) {
1395 step_edit_item->set_sensitive (false);
1399 rec_enable_button->unset_active_state ();
1401 if (step_edit_item) {
1402 step_edit_item->set_sensitive (true);
1406 check_rec_enable_sensitivity ();
1410 RouteUI::build_solo_menu (void)
1412 using namespace Menu_Helpers;
1414 solo_menu = new Menu;
1415 solo_menu->set_name ("ArdourContextMenu");
1416 MenuList& items = solo_menu->items();
1417 Gtk::CheckMenuItem* check;
1419 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1420 check->set_active (_route->solo_isolate_control()->solo_isolated());
1421 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1422 items.push_back (CheckMenuElem(*check));
1423 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1426 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1427 check->set_active (_route->solo_safe_control()->solo_safe());
1428 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1429 items.push_back (CheckMenuElem(*check));
1430 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1433 //items.push_back (SeparatorElem());
1434 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1439 RouteUI::build_mute_menu(void)
1441 using namespace Menu_Helpers;
1443 mute_menu = new Menu;
1444 mute_menu->set_name ("ArdourContextMenu");
1446 MenuList& items = mute_menu->items();
1448 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1449 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1450 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1451 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1452 pre_fader_mute_check->show_all();
1454 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1455 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1456 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1457 items.push_back (CheckMenuElem(*post_fader_mute_check));
1458 post_fader_mute_check->show_all();
1460 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1461 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1462 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1463 items.push_back (CheckMenuElem(*listen_mute_check));
1464 listen_mute_check->show_all();
1466 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1467 init_mute_menu(MuteMaster::Main, main_mute_check);
1468 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1469 items.push_back (CheckMenuElem(*main_mute_check));
1470 main_mute_check->show_all();
1472 //items.push_back (SeparatorElem());
1473 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1475 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1479 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1481 check->set_active (_route->mute_control()->mute_points() & mp);
1485 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1487 if (check->get_active()) {
1488 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1490 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1495 RouteUI::muting_change ()
1497 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1500 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1502 yn = (current & MuteMaster::PreFader);
1504 if (pre_fader_mute_check->get_active() != yn) {
1505 pre_fader_mute_check->set_active (yn);
1508 yn = (current & MuteMaster::PostFader);
1510 if (post_fader_mute_check->get_active() != yn) {
1511 post_fader_mute_check->set_active (yn);
1514 yn = (current & MuteMaster::Listen);
1516 if (listen_mute_check->get_active() != yn) {
1517 listen_mute_check->set_active (yn);
1520 yn = (current & MuteMaster::Main);
1522 if (main_mute_check->get_active() != yn) {
1523 main_mute_check->set_active (yn);
1528 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1530 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1534 bool view = solo_isolated_led->active_state();
1535 bool model = _route->solo_isolate_control()->solo_isolated();
1537 /* called BEFORE the view has changed */
1539 if (ev->button == 1) {
1540 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1543 /* disable isolate for all routes */
1544 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1546 /* enable isolate for all routes */
1547 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1552 if (model == view) {
1554 /* flip just this route */
1556 boost::shared_ptr<RouteList> rl (new RouteList);
1557 rl->push_back (_route);
1558 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1567 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1569 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1573 bool view = solo_safe_led->active_state();
1574 bool model = _route->solo_safe_control()->solo_safe();
1576 if (ev->button == 1) {
1577 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1578 boost::shared_ptr<RouteList> rl (_session->get_routes());
1580 /* disable solo safe for all routes */
1581 DisplaySuspender ds;
1582 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1583 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1586 /* enable solo safe for all routes */
1587 DisplaySuspender ds;
1588 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1589 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1594 if (model == view) {
1595 /* flip just this route */
1596 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1605 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1607 bool view = check->get_active();
1608 bool model = _route->solo_isolate_control()->solo_isolated();
1610 /* called AFTER the view has changed */
1612 if (model != view) {
1613 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1618 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1620 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1623 /** Ask the user to choose a colour, and then apply that color to my route */
1625 RouteUI::choose_color ()
1627 _color_picker.popup (_route);
1630 /** Set the route's own color. This may not be used for display if
1631 * the route is in a group which shares its color with its routes.
1634 RouteUI::set_color (uint32_t c)
1636 _route->presentation_info().set_color (c);
1639 /** @return GUI state ID for things that are common to the route in all its representations */
1641 RouteUI::route_state_id () const
1643 return string_compose (X_("route %1"), _route->id().to_s());
1647 RouteUI::set_color_from_route ()
1649 if (_route->presentation_info().color_set()) {
1650 return 0; /* nothing to do */
1653 return 1; /* pick a color */
1656 /** @return true if this name should be used for the route, otherwise false */
1658 RouteUI::verify_new_route_name (const std::string& name)
1660 if (name.find (':') == string::npos) {
1664 MessageDialog colon_msg (
1665 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1666 false, MESSAGE_QUESTION, BUTTONS_NONE
1669 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1670 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1672 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1676 RouteUI::route_rename ()
1678 ArdourPrompter name_prompter (true);
1683 name_prompter.set_title (_("Rename Track"));
1685 name_prompter.set_title (_("Rename Bus"));
1687 name_prompter.set_prompt (_("New name:"));
1688 name_prompter.set_initial_text (_route->name());
1689 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1690 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1691 name_prompter.show_all ();
1694 switch (name_prompter.run ()) {
1695 case Gtk::RESPONSE_ACCEPT:
1696 name_prompter.get_result (result);
1697 name_prompter.hide ();
1698 if (result.length()) {
1699 if (verify_new_route_name (result)) {
1700 _route->set_name (result);
1703 /* back to name prompter */
1707 /* nothing entered, just get out of here */
1722 RouteUI::toggle_comment_editor ()
1724 // if (ignore_toggle) {
1728 if (comment_window && comment_window->is_visible ()) {
1729 comment_window->hide ();
1731 open_comment_editor ();
1737 RouteUI::open_comment_editor ()
1739 if (comment_window == 0) {
1740 setup_comment_editor ();
1744 title = _route->name();
1745 title += _(": comment editor");
1747 comment_window->set_title (title);
1748 comment_window->present();
1752 RouteUI::setup_comment_editor ()
1754 comment_window = new ArdourWindow (""); // title will be reset to show route
1755 comment_window->set_skip_taskbar_hint (true);
1756 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1757 comment_window->set_default_size (400, 200);
1759 comment_area = manage (new TextView());
1760 comment_area->set_name ("MixerTrackCommentArea");
1761 comment_area->set_wrap_mode (WRAP_WORD);
1762 comment_area->set_editable (true);
1763 comment_area->get_buffer()->set_text (_route->comment());
1764 comment_area->show ();
1766 comment_window->add (*comment_area);
1770 RouteUI::comment_changed ()
1772 ignore_comment_edit = true;
1774 comment_area->get_buffer()->set_text (_route->comment());
1776 ignore_comment_edit = false;
1780 RouteUI::comment_editor_done_editing ()
1782 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1784 string const str = comment_area->get_buffer()->get_text();
1785 if (str == _route->comment ()) {
1789 _route->set_comment (str, this);
1793 RouteUI::set_route_active (bool a, bool apply_to_selection)
1795 if (apply_to_selection) {
1796 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1798 _route->set_active (a, this);
1803 RouteUI::duplicate_selected_routes ()
1805 ARDOUR_UI::instance()->start_duplicate_routes();
1809 RouteUI::toggle_denormal_protection ()
1811 if (denormal_menu_item) {
1815 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1817 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1818 _route->set_denormal_protection (x);
1824 RouteUI::denormal_protection_changed ()
1826 if (denormal_menu_item) {
1827 denormal_menu_item->set_active (_route->denormal_protection());
1832 RouteUI::disconnect_input ()
1834 _route->input()->disconnect (this);
1838 RouteUI::disconnect_output ()
1840 _route->output()->disconnect (this);
1844 RouteUI::is_track () const
1846 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1849 boost::shared_ptr<Track>
1850 RouteUI::track() const
1852 return boost::dynamic_pointer_cast<Track>(_route);
1856 RouteUI::is_audio_track () const
1858 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1861 boost::shared_ptr<AudioTrack>
1862 RouteUI::audio_track() const
1864 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1868 RouteUI::is_midi_track () const
1870 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1873 boost::shared_ptr<MidiTrack>
1874 RouteUI::midi_track() const
1876 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1880 RouteUI::has_audio_outputs () const
1882 return (_route->n_outputs().n_audio() > 0);
1886 RouteUI::map_frozen ()
1888 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1890 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1893 check_rec_enable_sensitivity ();
1898 RouteUI::adjust_latency ()
1900 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1904 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1907 std::string safe_name;
1910 prompter.get_result (name, true);
1912 safe_name = legalize_for_path (name);
1913 safe_name += template_suffix;
1915 path = Glib::build_filename (dir, safe_name);
1917 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1918 bool overwrite = overwrite_file_dialog (prompter,
1919 _("Confirm Template Overwrite"),
1920 _("A template already exists with that name. Do you want to overwrite it?"));
1927 _route->save_as_template (path, name);
1933 RouteUI::save_as_template ()
1937 dir = ARDOUR::user_route_template_directory ();
1939 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1940 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1944 ArdourPrompter prompter (true); // modal
1946 prompter.set_title (_("Save As Template"));
1947 prompter.set_prompt (_("Template name:"));
1948 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1950 bool finished = false;
1952 switch (prompter.run()) {
1953 case RESPONSE_ACCEPT:
1954 finished = process_save_template_prompter (prompter, dir);
1964 RouteUI::check_rec_enable_sensitivity ()
1966 if (!rec_enable_button) {
1967 assert (0); // This should not happen
1970 if (!_session->writable()) {
1971 rec_enable_button->set_sensitive (false);
1975 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1976 rec_enable_button->set_sensitive (false);
1977 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1978 rec_enable_button->set_sensitive (false);
1980 rec_enable_button->set_sensitive (true);
1982 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1983 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1985 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1987 update_monitoring_display ();
1991 RouteUI::parameter_changed (string const & p)
1993 /* this handles RC and per-session parameter changes */
1995 if (p == "disable-disarm-during-roll") {
1996 check_rec_enable_sensitivity ();
1997 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1998 set_button_names ();
1999 } else if (p == "session-monitoring") {
2000 update_monitoring_display ();
2001 } else if (p == "auto-input") {
2002 update_monitoring_display ();
2003 } else if (p == "blink-rec-arm") {
2004 if (UIConfiguration::instance().get_blink_rec_arm()) {
2005 rec_blink_connection.disconnect ();
2006 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2008 rec_blink_connection.disconnect ();
2009 RouteUI::blink_rec_display(false);
2015 RouteUI::step_gain_up ()
2017 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2021 RouteUI::page_gain_up ()
2023 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2027 RouteUI::step_gain_down ()
2029 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2033 RouteUI::page_gain_down ()
2035 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2039 RouteUI::setup_invert_buttons ()
2041 /* remove old invert buttons */
2042 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2043 _invert_button_box.remove (**i);
2046 _invert_buttons.clear ();
2048 if (!_route || !_route->input()) {
2052 uint32_t const N = _route->input()->n_ports().n_audio ();
2054 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2056 for (uint32_t i = 0; i < to_add; ++i) {
2057 ArdourButton* b = manage (new ArdourButton);
2058 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2059 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2061 b->set_name (X_("invert button"));
2064 b->set_text (string_compose (X_("Ø (%1)"), N));
2066 b->set_text (X_("Ø"));
2069 b->set_text (string_compose (X_("Ø%1"), i + 1));
2072 if (N <= _max_invert_buttons) {
2073 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));
2075 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2078 _invert_buttons.push_back (b);
2079 _invert_button_box.pack_start (*b);
2082 _invert_button_box.set_spacing (1);
2083 _invert_button_box.show_all ();
2087 RouteUI::set_invert_button_state ()
2089 uint32_t const N = _route->input()->n_ports().n_audio();
2090 if (N > _max_invert_buttons) {
2092 /* One button for many channels; explicit active if all channels are inverted,
2093 implicit active if some are, off if none are.
2096 ArdourButton* b = _invert_buttons.front ();
2098 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2099 b->set_active_state (Gtkmm2ext::ExplicitActive);
2100 } else if (_route->phase_control()->any()) {
2101 b->set_active_state (Gtkmm2ext::ImplicitActive);
2103 b->set_active_state (Gtkmm2ext::Off);
2108 /* One button per channel; just set active */
2111 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2112 (*i)->set_active (_route->phase_control()->inverted (j));
2119 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2121 if (ev->button == 1 && i < _invert_buttons.size()) {
2122 uint32_t const N = _route->input()->n_ports().n_audio ();
2123 if (N <= _max_invert_buttons) {
2124 /* left-click inverts phase so long as we have a button per channel */
2125 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2134 RouteUI::invert_press (GdkEventButton* ev)
2136 using namespace Menu_Helpers;
2138 uint32_t const N = _route->input()->n_ports().n_audio();
2139 if (N <= _max_invert_buttons && ev->button != 3) {
2140 /* If we have an invert button per channel, we only pop
2141 up a menu on right-click; left click is handled
2147 delete _invert_menu;
2148 _invert_menu = new Menu;
2149 _invert_menu->set_name ("ArdourContextMenu");
2150 MenuList& items = _invert_menu->items ();
2152 for (uint32_t i = 0; i < N; ++i) {
2153 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2154 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2155 ++_i_am_the_modifier;
2156 e->set_active (_route->phase_control()->inverted (i));
2157 --_i_am_the_modifier;
2160 _invert_menu->popup (0, ev->time);
2166 RouteUI::invert_menu_toggled (uint32_t c)
2168 if (_i_am_the_modifier) {
2173 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2177 RouteUI::set_invert_sensitive (bool yn)
2179 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2180 (*b)->set_sensitive (yn);
2185 RouteUI::request_redraw ()
2188 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2192 /** The Route's gui_changed signal has been emitted */
2194 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2196 if (what_changed.contains (Properties::color)) {
2197 if (set_color_from_route () == 0) {
2198 route_color_changed ();
2204 RouteUI::track_mode_changed (void)
2207 switch (track()->mode()) {
2208 case ARDOUR::NonLayered:
2209 case ARDOUR::Normal:
2210 rec_enable_button->set_icon (ArdourIcon::RecButton);
2212 case ARDOUR::Destructive:
2213 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2216 rec_enable_button->queue_draw();
2219 /** @return the color that this route should use; it maybe its own,
2220 * or it maybe that of its route group.
2223 RouteUI::route_color () const
2226 RouteGroup* g = _route->route_group ();
2229 if (g && g->is_color()) {
2230 set_color_from_rgba (c, GroupTabs::group_color (g));
2232 set_color_from_rgba (c, _route->presentation_info().color());
2239 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2241 _showing_sends_to = send_to;
2242 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2246 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2248 if (_route == send_to) {
2249 show_sends_button->set_active (true);
2250 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2252 show_sends_button->set_active (false);
2253 send_blink_connection.disconnect ();
2258 RouteUI::route_group() const
2260 return _route->route_group();
2264 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2265 : WM::ProxyBase (name, string())
2266 , _route (boost::weak_ptr<Route> (route))
2268 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2271 RoutePinWindowProxy::~RoutePinWindowProxy()
2276 ARDOUR::SessionHandlePtr*
2277 RoutePinWindowProxy::session_handle ()
2279 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2280 if (aw) { return aw; }
2285 RoutePinWindowProxy::get (bool create)
2287 boost::shared_ptr<Route> r = _route.lock ();
2296 _window = new PluginPinDialog (r);
2297 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2299 aw->set_session (_session);
2301 _window->show_all ();
2307 RoutePinWindowProxy::route_going_away ()
2311 WM::Manager::instance().remove (this);
2312 going_away_connection.disconnect();
2317 RouteUI::maybe_add_route_print_mgr ()
2319 if (_route->pinmgr_proxy ()) {
2322 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2323 string_compose ("RPM-%1", _route->id()), _route);
2324 wp->set_session (_session);
2326 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2328 wp->set_state (*ui_xml, 0);
2332 void* existing_ui = _route->pinmgr_proxy ();
2334 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2337 _route->set_pingmgr_proxy (wp);
2339 WM::Manager::instance().register_window (wp);
2343 RouteUI::manage_pins ()
2345 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2353 RouteUI::fan_out (bool to_busses, bool group)
2355 DisplaySuspender ds;
2356 boost::shared_ptr<ARDOUR::Route> route = _route;
2357 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2360 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2361 if (route->n_outputs ().n_audio () != n_outputs) {
2362 MessageDialog msg (string_compose (
2363 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2364 n_outputs, route->n_outputs ().n_audio ()));
2369 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2371 /* count busses and channels/bus */
2372 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2373 std::map<std::string, uint32_t> busnames;
2374 for (uint32_t p = 0; p < n_outputs; ++p) {
2375 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2376 std::string bn = BUSNAME;
2380 if (busnames.size () < 2) {
2381 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2386 uint32_t outputs = 2;
2387 if (_session->master_out ()) {
2388 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2391 route->output ()->disconnect (this);
2392 route->panner_shell ()->set_bypassed (true);
2395 for (uint32_t p = 0; p < n_outputs; ++p) {
2396 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2397 std::string bn = BUSNAME;
2398 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2401 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2405 list<boost::shared_ptr<AudioTrack> > tl =
2406 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2410 boost::shared_ptr<ControlList> cl (new ControlList);
2411 cl->push_back (r->monitoring_control ());
2412 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2414 r->input ()->disconnect (this);
2416 to_group.push_back (r);
2417 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2422 RouteGroup* rg = NULL;
2423 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2424 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2425 if ((*i)->name () == pi->name ()) {
2431 rg = new RouteGroup (*_session, pi->name ());
2432 _session->add_route_group (rg);
2433 rg->set_gain (false);
2436 GroupTabs::set_group_color (rg, route->presentation_info().color());
2437 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2444 RouteUI::mark_hidden (bool yn)
2446 if (yn != _route->presentation_info().hidden()) {
2447 _route->presentation_info().set_hidden (yn);
2448 return true; // things changed
2453 boost::shared_ptr<Stripable>
2454 RouteUI::stripable () const