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/gtk_ui.h"
28 #include "gtkmm2ext/utils.h"
30 #include "widgets/ardour_button.h"
32 #include "pbd/memento_command.h"
33 #include "pbd/stacktrace.h"
34 #include "pbd/controllable.h"
35 #include "pbd/enumwriter.h"
37 #include "ardour/dB.h"
38 #include "ardour/route_group.h"
39 #include "ardour/solo_isolate_control.h"
40 #include "ardour/vca.h"
41 #include "ardour/vca_manager.h"
42 #include "ardour/audio_track.h"
43 #include "ardour/audio_port.h"
44 #include "ardour/audioengine.h"
45 #include "ardour/filename_extensions.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/monitor_control.h"
48 #include "ardour/internal_send.h"
49 #include "ardour/panner_shell.h"
50 #include "ardour/profile.h"
51 #include "ardour/phase_control.h"
52 #include "ardour/send.h"
53 #include "ardour/route.h"
54 #include "ardour/session.h"
55 #include "ardour/template_utils.h"
58 #include "ardour_dialog.h"
59 #include "ardour_ui.h"
60 #include "automation_time_axis.h"
62 #include "group_tabs.h"
63 #include "gui_object.h"
64 #include "gui_thread.h"
66 #include "latency_gui.h"
67 #include "mixer_strip.h"
68 #include "plugin_pin_dialog.h"
70 #include "rgb_macros.h"
71 #include "route_time_axis.h"
74 #include "ui_config.h"
80 using namespace Gtkmm2ext;
81 using namespace ARDOUR;
82 using namespace ARDOUR_UI_UTILS;
83 using namespace ArdourWidgets;
87 uint32_t RouteUI::_max_invert_buttons = 3;
88 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
89 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
90 std::string RouteUI::program_port_prefix;
92 RouteUI::RouteUI (ARDOUR::Session* sess)
93 : monitor_input_button (0)
94 , monitor_disk_button (0)
102 , output_selector (0)
105 if (program_port_prefix.empty()) {
106 // compare to gtk2_ardour/port_group.cc
107 string lpn (PROGRAM_NAME);
108 boost::to_lower (lpn);
109 program_port_prefix = lpn + ":"; // e.g. "ardour:"
120 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
123 _route.reset (); /* drop reference to route, so that it can be cleaned up */
124 route_connections.drop_connections ();
130 delete comment_window;
131 delete input_selector;
132 delete output_selector;
133 delete monitor_input_button;
134 delete monitor_disk_button;
137 send_blink_connection.disconnect ();
138 rec_blink_connection.disconnect ();
144 self_destruct = true;
150 pre_fader_mute_check = 0;
151 post_fader_mute_check = 0;
152 listen_mute_check = 0;
155 solo_isolated_check = 0;
156 solo_isolated_led = 0;
160 denormal_menu_item = 0;
163 multiple_mute_change = false;
164 multiple_solo_change = false;
165 _i_am_the_modifier = 0;
170 setup_invert_buttons ();
172 mute_button = manage (new ArdourButton);
173 mute_button->set_name ("mute button");
174 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
176 solo_button = manage (new ArdourButton);
177 solo_button->set_name ("solo button");
178 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
179 solo_button->set_no_show_all (true);
181 rec_enable_button = manage (new ArdourButton);
182 rec_enable_button->set_name ("record enable button");
183 rec_enable_button->set_icon (ArdourIcon::RecButton);
184 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
186 if (UIConfiguration::instance().get_blink_rec_arm()) {
187 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
190 show_sends_button = manage (new ArdourButton);
191 show_sends_button->set_name ("send alert button");
192 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
194 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
195 monitor_input_button->set_name ("monitor button");
196 monitor_input_button->set_text (_("In"));
197 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
198 monitor_input_button->set_no_show_all (true);
200 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
201 monitor_disk_button->set_name ("monitor button");
202 monitor_disk_button->set_text (_("Disk"));
203 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
204 monitor_disk_button->set_no_show_all (true);
206 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
207 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
208 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
210 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
211 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
212 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
214 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
215 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
217 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
218 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
220 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
221 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
222 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
223 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
225 monitor_input_button->set_distinct_led_click (false);
226 monitor_disk_button->set_distinct_led_click (false);
228 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
229 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
231 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
232 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
234 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
240 route_connections.drop_connections ();
248 _color_picker.reset ();
250 denormal_menu_item = 0;
254 RouteUI::self_delete ()
260 RouteUI::set_route (boost::shared_ptr<Route> rp)
266 if ( !_route->presentation_info().color_set() ) {
267 /* deal with older 4.x color, which was stored in the GUI object state */
269 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
273 /* old v4.x or earlier session. Use this information */
275 int red, green, blue;
280 /* old color format version was:
282 16bit value for red:16 bit value for green:16 bit value for blue
297 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
301 if (set_color_from_route()) {
302 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
306 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
309 delete input_selector;
312 delete output_selector;
315 mute_button->set_controllable (_route->mute_control());
316 solo_button->set_controllable (_route->solo_control());
318 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
320 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
322 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
323 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
324 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
325 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
326 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
327 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
330 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
331 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
332 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
334 track_mode_changed();
338 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
339 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
341 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
343 if (_session->writable() && is_track()) {
344 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
346 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
347 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
349 rec_enable_button->show();
350 rec_enable_button->set_controllable (t->rec_enable_control());
352 if (is_midi_track()) {
353 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
354 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
359 /* this will work for busses and tracks, and needs to be called to
360 set up the name entry/name label display.
364 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
365 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
367 update_monitoring_display ();
370 mute_button->unset_flags (Gtk::CAN_FOCUS);
371 solo_button->unset_flags (Gtk::CAN_FOCUS);
375 if (_route->is_monitor() || _route->is_master()) {
376 solo_button->hide ();
383 setup_invert_buttons ();
384 set_invert_button_state ();
386 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
387 bus_send_display_changed (s);
389 update_mute_display ();
390 update_solo_display ();
392 if (!UIConfiguration::instance().get_blink_rec_arm()) {
393 blink_rec_display(true); // set initial rec-en button state
396 check_rec_enable_sensitivity ();
397 maybe_add_route_print_mgr ();
398 route_color_changed();
399 route_gui_changed (PropertyChange (Properties::selected));
403 RouteUI::polarity_changed ()
409 set_invert_button_state ();
413 RouteUI::mute_press (GdkEventButton* ev)
415 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
419 //if this is a binding action, let the ArdourButton handle it
420 if ( BindingProxy::is_bind_action(ev) )
423 multiple_mute_change = false;
425 if (Keyboard::is_context_menu_event (ev)) {
431 mute_menu->popup(0,ev->time);
437 if (Keyboard::is_button2_event (ev)) {
438 // button2-click is "momentary"
440 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
443 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
445 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
447 /* toggle mute on everything (but
448 * exclude the master and monitor)
450 * because we are going to erase
451 * elements of the list we need to work
455 boost::shared_ptr<RouteList> copy (new RouteList);
457 *copy = *_session->get_routes ();
459 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
460 if ((*i)->is_master() || (*i)->is_monitor()) {
468 _mute_release->routes = copy;
471 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
473 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
475 /* Primary-button1 inverts the implication of
476 the group being active. If the group is
477 active (for mute), then this modifier means
478 "do not apply to mute". If the group is
479 inactive (for mute), then this modifier
480 means "apply to route". This is all
481 accomplished by passing just the actual
482 route, along with the InverseGroup group
485 NOTE: Primary-button2 is MIDI learn.
488 boost::shared_ptr<RouteList> rl;
490 if (ev->button == 1) {
492 rl.reset (new RouteList);
493 rl->push_back (_route);
496 _mute_release->routes = rl;
499 boost::shared_ptr<MuteControl> mc = _route->mute_control();
500 mc->start_touch (_session->audible_frame ());
501 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
506 /* plain click applies change to this route */
508 boost::shared_ptr<RouteList> rl (new RouteList);
509 rl->push_back (_route);
512 _mute_release->routes = rl;
515 boost::shared_ptr<MuteControl> mc = _route->mute_control();
516 mc->start_touch (_session->audible_frame ());
517 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
526 RouteUI::mute_release (GdkEventButton* /*ev*/)
529 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
530 delete _mute_release;
534 _route->mute_control()->stop_touch (false, _session->audible_frame ());
540 RouteUI::edit_output_configuration ()
542 if (output_selector == 0) {
544 boost::shared_ptr<Send> send;
545 boost::shared_ptr<IO> output;
547 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
548 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
549 output = send->output();
551 output = _route->output ();
554 output = _route->output ();
557 output_selector = new IOSelectorWindow (_session, output);
560 if (output_selector->is_visible()) {
561 output_selector->get_toplevel()->get_window()->raise();
563 output_selector->present ();
566 //output_selector->set_keep_above (true);
570 RouteUI::edit_input_configuration ()
572 if (input_selector == 0) {
573 input_selector = new IOSelectorWindow (_session, _route->input());
576 if (input_selector->is_visible()) {
577 input_selector->get_toplevel()->get_window()->raise();
579 input_selector->present ();
582 //input_selector->set_keep_above (true);
586 RouteUI::solo_press(GdkEventButton* ev)
588 /* ignore double/triple clicks */
590 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
594 //if this is a binding action, let the ArdourButton handle it
595 if ( BindingProxy::is_bind_action(ev) )
598 multiple_solo_change = false;
600 if (Keyboard::is_context_menu_event (ev)) {
602 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
603 ! (solo_safe_led && solo_safe_led->is_visible())) {
605 if (solo_menu == 0) {
609 solo_menu->popup (1, ev->time);
614 if (Keyboard::is_button2_event (ev)) {
616 // button2-click is "momentary"
617 _solo_release = new SoloMuteRelease (_route->self_soloed());
620 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
622 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
624 /* Primary-Tertiary-click applies change to all routes */
627 _solo_release->routes = _session->get_routes ();
630 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
632 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
634 /* Primary-Secondary-click: exclusively solo this track */
637 _solo_release->exclusive = true;
639 _solo_release->routes_on.reset (new RouteList);
640 _solo_release->routes_off.reset (new RouteList);
642 boost::shared_ptr<RouteList> routes = _session->get_routes();
643 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
645 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
649 if ((*i)->soloed ()) {
650 _solo_release->routes_on->push_back (*i);
652 _solo_release->routes_off->push_back (*i);
657 boost::shared_ptr<RouteList> rl (new RouteList);
658 boost::shared_ptr<RouteList> routes = _session->get_routes();
659 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
661 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
665 if ((*i)->soloed ()) {
669 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
671 if (Config->get_solo_control_is_listen_control()) {
672 /* ??? we need a just_one_listen() method */
675 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
678 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
680 // shift-click: toggle solo isolated status
682 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
683 delete _solo_release;
686 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
688 /* Primary-button1: solo mix group.
689 NOTE: Primary-button2 is MIDI learn.
692 /* Primary-button1 applies change to the mix group even if it is not active
693 NOTE: Primary-button2 is MIDI learn.
696 boost::shared_ptr<RouteList> rl;
698 if (ev->button == 1) {
700 /* Primary-button1 inverts the implication of
701 the group being active. If the group is
702 active (for solo), then this modifier means
703 "do not apply to solo". If the group is
704 inactive (for mute), then this modifier
705 means "apply to route". This is all
706 accomplished by passing just the actual
707 route, along with the InverseGroup group
710 NOTE: Primary-button2 is MIDI learn.
713 rl.reset (new RouteList);
714 rl->push_back (_route);
717 _solo_release->routes = rl;
720 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
723 delete _solo_release;
728 /* click: solo this route */
730 boost::shared_ptr<RouteList> rl (new RouteList);
731 rl->push_back (route());
734 _solo_release->routes = rl;
737 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
746 RouteUI::solo_release (GdkEventButton* /*ev*/)
749 if (_solo_release->exclusive) {
750 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
751 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
753 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
756 delete _solo_release;
764 RouteUI::rec_enable_press(GdkEventButton* ev)
766 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
770 //if this is a binding action, let the ArdourButton handle it
771 if ( BindingProxy::is_bind_action(ev) )
774 if (!_session->engine().connected()) {
775 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
780 if (is_midi_track()) {
782 /* rec-enable button exits from step editing */
784 if (midi_track()->step_editing()) {
785 midi_track()->set_step_editing (false);
790 if (is_track() && rec_enable_button) {
792 if (Keyboard::is_button2_event (ev)) {
794 //rec arm does not have a momentary mode
797 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
799 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
801 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
803 /* Primary-button1 applies change to the route group (even if it is not active)
804 NOTE: Primary-button2 is MIDI learn.
807 if (ev->button == 1) {
809 boost::shared_ptr<RouteList> rl;
811 rl.reset (new RouteList);
812 rl->push_back (_route);
814 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
817 } else if (Keyboard::is_context_menu_event (ev)) {
819 /* do this on release */
823 boost::shared_ptr<Track> trk = track();
824 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
832 RouteUI::update_monitoring_display ()
838 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
844 MonitorState ms = t->monitoring_state();
846 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
847 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
849 if (ms & MonitoringInput) {
850 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
852 monitor_input_button->unset_active_state ();
856 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
857 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
859 if (ms & MonitoringDisk) {
860 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
862 monitor_disk_button->unset_active_state ();
868 RouteUI::monitor_input_press(GdkEventButton*)
874 RouteUI::monitor_input_release(GdkEventButton* ev)
876 return monitor_release (ev, MonitorInput);
880 RouteUI::monitor_disk_press (GdkEventButton*)
886 RouteUI::monitor_disk_release (GdkEventButton* ev)
888 return monitor_release (ev, MonitorDisk);
892 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
894 if (ev->button != 1) {
898 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
905 boost::shared_ptr<RouteList> rl;
907 /* XXX for now, monitoring choices are orthogonal. cue monitoring
908 will follow in 3.X but requires mixing the input and playback (disk)
909 signal together, which requires yet more buffers.
912 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
913 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
915 /* this line will change when the options are non-orthogonal */
916 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
920 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
921 /* Primary-Tertiary-click applies change to all routes */
922 rl = _session->get_routes ();
923 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
924 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
925 /* Primary-click overrides group */
926 rl.reset (new RouteList);
927 rl->push_back (route());
928 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
930 rl.reset (new RouteList);
931 rl->push_back (route());
932 _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 */
1627 RouteUI::choose_color ()
1629 _color_picker.popup (_route);
1632 /** Set the route's own color. This may not be used for display if
1633 * the route is in a group which shares its color with its routes.
1636 RouteUI::set_color (uint32_t c)
1638 _route->presentation_info().set_color (c);
1641 /** @return GUI state ID for things that are common to the route in all its representations */
1643 RouteUI::route_state_id () const
1645 return string_compose (X_("route %1"), _route->id().to_s());
1649 RouteUI::set_color_from_route ()
1651 if (_route->presentation_info().color_set()) {
1652 return 0; /* nothing to do */
1655 return 1; /* pick a color */
1658 /** @return true if this name should be used for the route, otherwise false */
1660 RouteUI::verify_new_route_name (const std::string& name)
1662 if (name.find (':') == string::npos) {
1666 MessageDialog colon_msg (
1667 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1668 false, MESSAGE_QUESTION, BUTTONS_NONE
1671 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1672 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1674 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1678 RouteUI::route_rename ()
1680 ArdourPrompter name_prompter (true);
1685 name_prompter.set_title (_("Rename Track"));
1687 name_prompter.set_title (_("Rename Bus"));
1689 name_prompter.set_prompt (_("New name:"));
1690 name_prompter.set_initial_text (_route->name());
1691 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1692 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1693 name_prompter.show_all ();
1696 switch (name_prompter.run ()) {
1697 case Gtk::RESPONSE_ACCEPT:
1698 name_prompter.get_result (result);
1699 name_prompter.hide ();
1700 if (result.length()) {
1701 if (verify_new_route_name (result)) {
1702 _route->set_name (result);
1705 /* back to name prompter */
1709 /* nothing entered, just get out of here */
1724 RouteUI::toggle_comment_editor ()
1726 // if (ignore_toggle) {
1730 if (comment_window && comment_window->is_visible ()) {
1731 comment_window->hide ();
1733 open_comment_editor ();
1739 RouteUI::open_comment_editor ()
1741 if (comment_window == 0) {
1742 setup_comment_editor ();
1746 title = _route->name();
1747 title += _(": comment editor");
1749 comment_window->set_title (title);
1750 comment_window->present();
1754 RouteUI::setup_comment_editor ()
1756 comment_window = new ArdourWindow (""); // title will be reset to show route
1757 comment_window->set_skip_taskbar_hint (true);
1758 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1759 comment_window->set_default_size (400, 200);
1761 comment_area = manage (new TextView());
1762 comment_area->set_name ("MixerTrackCommentArea");
1763 comment_area->set_wrap_mode (WRAP_WORD);
1764 comment_area->set_editable (true);
1765 comment_area->get_buffer()->set_text (_route->comment());
1766 comment_area->show ();
1768 comment_window->add (*comment_area);
1772 RouteUI::comment_changed ()
1774 ignore_comment_edit = true;
1776 comment_area->get_buffer()->set_text (_route->comment());
1778 ignore_comment_edit = false;
1782 RouteUI::comment_editor_done_editing ()
1784 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1786 string const str = comment_area->get_buffer()->get_text();
1787 if (str == _route->comment ()) {
1791 _route->set_comment (str, this);
1795 RouteUI::set_route_active (bool a, bool apply_to_selection)
1797 if (apply_to_selection) {
1798 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1800 _route->set_active (a, this);
1805 RouteUI::duplicate_selected_routes ()
1807 ARDOUR_UI::instance()->start_duplicate_routes();
1811 RouteUI::toggle_denormal_protection ()
1813 if (denormal_menu_item) {
1817 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1819 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1820 _route->set_denormal_protection (x);
1826 RouteUI::denormal_protection_changed ()
1828 if (denormal_menu_item) {
1829 denormal_menu_item->set_active (_route->denormal_protection());
1834 RouteUI::disconnect_input ()
1836 _route->input()->disconnect (this);
1840 RouteUI::disconnect_output ()
1842 _route->output()->disconnect (this);
1846 RouteUI::is_track () const
1848 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1851 boost::shared_ptr<Track>
1852 RouteUI::track() const
1854 return boost::dynamic_pointer_cast<Track>(_route);
1858 RouteUI::is_audio_track () const
1860 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1863 boost::shared_ptr<AudioTrack>
1864 RouteUI::audio_track() const
1866 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1870 RouteUI::is_midi_track () const
1872 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1875 boost::shared_ptr<MidiTrack>
1876 RouteUI::midi_track() const
1878 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1882 RouteUI::has_audio_outputs () const
1884 return (_route->n_outputs().n_audio() > 0);
1888 RouteUI::map_frozen ()
1890 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1892 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1895 check_rec_enable_sensitivity ();
1900 RouteUI::adjust_latency ()
1902 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1906 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1909 std::string safe_name;
1912 prompter.get_result (name, true);
1914 safe_name = legalize_for_path (name);
1915 safe_name += template_suffix;
1917 path = Glib::build_filename (dir, safe_name);
1919 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1920 bool overwrite = overwrite_file_dialog (prompter,
1921 _("Confirm Template Overwrite"),
1922 _("A template already exists with that name. Do you want to overwrite it?"));
1929 _route->save_as_template (path, name);
1935 RouteUI::save_as_template ()
1939 dir = ARDOUR::user_route_template_directory ();
1941 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1942 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1946 ArdourPrompter prompter (true); // modal
1948 prompter.set_title (_("Save As Template"));
1949 prompter.set_prompt (_("Template name:"));
1950 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1952 bool finished = false;
1954 switch (prompter.run()) {
1955 case RESPONSE_ACCEPT:
1956 finished = process_save_template_prompter (prompter, dir);
1966 RouteUI::check_rec_enable_sensitivity ()
1968 if (!rec_enable_button) {
1969 assert (0); // This should not happen
1972 if (!_session->writable()) {
1973 rec_enable_button->set_sensitive (false);
1977 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1978 rec_enable_button->set_sensitive (false);
1979 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1980 rec_enable_button->set_sensitive (false);
1982 rec_enable_button->set_sensitive (true);
1984 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1985 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1987 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1989 update_monitoring_display ();
1993 RouteUI::parameter_changed (string const & p)
1995 /* this handles RC and per-session parameter changes */
1997 if (p == "disable-disarm-during-roll") {
1998 check_rec_enable_sensitivity ();
1999 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2000 set_button_names ();
2001 } else if (p == "session-monitoring") {
2002 update_monitoring_display ();
2003 } else if (p == "auto-input") {
2004 update_monitoring_display ();
2005 } else if (p == "blink-rec-arm") {
2006 if (UIConfiguration::instance().get_blink_rec_arm()) {
2007 rec_blink_connection.disconnect ();
2008 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2010 rec_blink_connection.disconnect ();
2011 RouteUI::blink_rec_display(false);
2017 RouteUI::setup_invert_buttons ()
2019 /* remove old invert buttons */
2020 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2021 _invert_button_box.remove (**i);
2024 _invert_buttons.clear ();
2026 if (!_route || !_route->input()) {
2030 uint32_t const N = _route->input()->n_ports().n_audio ();
2032 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2034 for (uint32_t i = 0; i < to_add; ++i) {
2035 ArdourButton* b = manage (new ArdourButton);
2036 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2037 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2039 b->set_name (X_("invert button"));
2042 b->set_text (string_compose (X_("Ø (%1)"), N));
2044 b->set_text (X_("Ø"));
2047 b->set_text (string_compose (X_("Ø%1"), i + 1));
2050 if (N <= _max_invert_buttons) {
2051 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));
2053 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2056 _invert_buttons.push_back (b);
2057 _invert_button_box.pack_start (*b);
2060 _invert_button_box.set_spacing (1);
2061 _invert_button_box.show_all ();
2065 RouteUI::set_invert_button_state ()
2067 uint32_t const N = _route->input()->n_ports().n_audio();
2068 if (N > _max_invert_buttons) {
2070 /* One button for many channels; explicit active if all channels are inverted,
2071 implicit active if some are, off if none are.
2074 ArdourButton* b = _invert_buttons.front ();
2076 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2077 b->set_active_state (Gtkmm2ext::ExplicitActive);
2078 } else if (_route->phase_control()->any()) {
2079 b->set_active_state (Gtkmm2ext::ImplicitActive);
2081 b->set_active_state (Gtkmm2ext::Off);
2086 /* One button per channel; just set active */
2089 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2090 (*i)->set_active (_route->phase_control()->inverted (j));
2097 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2099 if (ev->button == 1 && i < _invert_buttons.size()) {
2100 uint32_t const N = _route->input()->n_ports().n_audio ();
2101 if (N <= _max_invert_buttons) {
2102 /* left-click inverts phase so long as we have a button per channel */
2103 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2112 RouteUI::invert_press (GdkEventButton* ev)
2114 using namespace Menu_Helpers;
2116 uint32_t const N = _route->input()->n_ports().n_audio();
2117 if (N <= _max_invert_buttons && ev->button != 3) {
2118 /* If we have an invert button per channel, we only pop
2119 up a menu on right-click; left click is handled
2125 delete _invert_menu;
2126 _invert_menu = new Menu;
2127 _invert_menu->set_name ("ArdourContextMenu");
2128 MenuList& items = _invert_menu->items ();
2130 for (uint32_t i = 0; i < N; ++i) {
2131 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2132 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2133 ++_i_am_the_modifier;
2134 e->set_active (_route->phase_control()->inverted (i));
2135 --_i_am_the_modifier;
2138 _invert_menu->popup (0, ev->time);
2144 RouteUI::invert_menu_toggled (uint32_t c)
2146 if (_i_am_the_modifier) {
2151 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2155 RouteUI::set_invert_sensitive (bool yn)
2157 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2158 (*b)->set_sensitive (yn);
2162 /** The Route's gui_changed signal has been emitted */
2164 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2166 if (what_changed.contains (Properties::color)) {
2167 if (set_color_from_route () == 0) {
2168 route_color_changed ();
2174 RouteUI::track_mode_changed (void)
2177 switch (track()->mode()) {
2178 case ARDOUR::NonLayered:
2179 case ARDOUR::Normal:
2180 rec_enable_button->set_icon (ArdourIcon::RecButton);
2182 case ARDOUR::Destructive:
2183 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2186 rec_enable_button->queue_draw();
2189 /** @return the color that this route should use; it maybe its own,
2190 * or it maybe that of its route group.
2193 RouteUI::route_color () const
2196 RouteGroup* g = _route->route_group ();
2199 if (g && g->is_color()) {
2200 set_color_from_rgba (c, GroupTabs::group_color (g));
2202 set_color_from_rgba (c, _route->presentation_info().color());
2209 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2211 _showing_sends_to = send_to;
2212 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2216 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2218 if (_route == send_to) {
2219 show_sends_button->set_active (true);
2220 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2222 show_sends_button->set_active (false);
2223 send_blink_connection.disconnect ();
2228 RouteUI::route_group() const
2230 return _route->route_group();
2234 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2235 : WM::ProxyBase (name, string())
2236 , _route (boost::weak_ptr<Route> (route))
2238 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2241 RoutePinWindowProxy::~RoutePinWindowProxy()
2246 ARDOUR::SessionHandlePtr*
2247 RoutePinWindowProxy::session_handle ()
2249 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2250 if (aw) { return aw; }
2255 RoutePinWindowProxy::get (bool create)
2257 boost::shared_ptr<Route> r = _route.lock ();
2266 _window = new PluginPinDialog (r);
2267 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2269 aw->set_session (_session);
2271 _window->show_all ();
2277 RoutePinWindowProxy::route_going_away ()
2281 WM::Manager::instance().remove (this);
2282 going_away_connection.disconnect();
2287 RouteUI::maybe_add_route_print_mgr ()
2289 if (_route->pinmgr_proxy ()) {
2292 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2293 string_compose ("RPM-%1", _route->id()), _route);
2294 wp->set_session (_session);
2296 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2298 wp->set_state (*ui_xml, 0);
2302 void* existing_ui = _route->pinmgr_proxy ();
2304 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2307 _route->set_pingmgr_proxy (wp);
2309 WM::Manager::instance().register_window (wp);
2313 RouteUI::manage_pins ()
2315 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2323 RouteUI::fan_out (bool to_busses, bool group)
2325 DisplaySuspender ds;
2326 boost::shared_ptr<ARDOUR::Route> route = _route;
2327 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2330 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2331 if (route->n_outputs ().n_audio () != n_outputs) {
2332 MessageDialog msg (string_compose (
2333 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2334 n_outputs, route->n_outputs ().n_audio ()));
2339 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2341 /* count busses and channels/bus */
2342 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2343 std::map<std::string, uint32_t> busnames;
2344 for (uint32_t p = 0; p < n_outputs; ++p) {
2345 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2346 std::string bn = BUSNAME;
2350 if (busnames.size () < 2) {
2351 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2356 uint32_t outputs = 2;
2357 if (_session->master_out ()) {
2358 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2361 route->output ()->disconnect (this);
2362 route->panner_shell ()->set_bypassed (true);
2365 for (uint32_t p = 0; p < n_outputs; ++p) {
2366 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2367 std::string bn = BUSNAME;
2368 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2371 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2375 list<boost::shared_ptr<AudioTrack> > tl =
2376 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2380 boost::shared_ptr<ControlList> cl (new ControlList);
2381 cl->push_back (r->monitoring_control ());
2382 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2384 r->input ()->disconnect (this);
2386 to_group.push_back (r);
2387 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2392 RouteGroup* rg = NULL;
2393 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2394 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2395 if ((*i)->name () == pi->name ()) {
2401 rg = new RouteGroup (*_session, pi->name ());
2402 _session->add_route_group (rg);
2403 rg->set_gain (false);
2406 GroupTabs::set_group_color (rg, route->presentation_info().color());
2407 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2414 RouteUI::mark_hidden (bool yn)
2416 if (yn != _route->presentation_info().hidden()) {
2417 _route->presentation_info().set_hidden (yn);
2418 return true; // things changed
2423 boost::shared_ptr<Stripable>
2424 RouteUI::stripable () const