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 <gtkmm/stock.h>
25 #include "pbd/memento_command.h"
26 #include "pbd/stacktrace.h"
27 #include "pbd/controllable.h"
28 #include "pbd/enumwriter.h"
30 #include "ardour/dB.h"
31 #include "ardour/route_group.h"
32 #include "ardour/solo_isolate_control.h"
33 #include "ardour/vca.h"
34 #include "ardour/vca_manager.h"
35 #include "ardour/audio_track.h"
36 #include "ardour/audio_port.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/filename_extensions.h"
39 #include "ardour/midi_track.h"
40 #include "ardour/monitor_control.h"
41 #include "ardour/internal_send.h"
42 #include "ardour/panner_shell.h"
43 #include "ardour/profile.h"
44 #include "ardour/phase_control.h"
45 #include "ardour/send.h"
46 #include "ardour/route.h"
47 #include "ardour/session.h"
48 #include "ardour/template_utils.h"
50 #include "gtkmm2ext/gtk_ui.h"
51 #include "gtkmm2ext/doi.h"
52 #include "gtkmm2ext/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
55 #include "widgets/ardour_button.h"
56 #include "widgets/binding_proxy.h"
57 #include "widgets/prompter.h"
59 #include "ardour_dialog.h"
60 #include "ardour_ui.h"
61 #include "automation_time_axis.h"
63 #include "group_tabs.h"
64 #include "gui_object.h"
65 #include "gui_thread.h"
67 #include "latency_gui.h"
68 #include "mixer_strip.h"
69 #include "patch_change_widget.h"
70 #include "plugin_pin_dialog.h"
71 #include "rgb_macros.h"
72 #include "route_time_axis.h"
74 #include "save_template_dialog.h"
76 #include "ui_config.h"
82 using namespace Gtkmm2ext;
83 using namespace ARDOUR;
84 using namespace ARDOUR_UI_UTILS;
85 using namespace ArdourWidgets;
89 uint32_t RouteUI::_max_invert_buttons = 3;
90 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
91 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
92 std::string RouteUI::program_port_prefix;
94 RouteUI::RouteUI (ARDOUR::Session* sess)
95 : monitor_input_button (0)
96 , monitor_disk_button (0)
104 , output_selector (0)
107 if (program_port_prefix.empty()) {
108 // compare to gtk2_ardour/port_group.cc
109 string lpn (PROGRAM_NAME);
110 boost::to_lower (lpn);
111 program_port_prefix = lpn + ":"; // e.g. "ardour:"
122 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
125 delete_patch_change_dialog ();
127 _route.reset (); /* drop reference to route, so that it can be cleaned up */
128 route_connections.drop_connections ();
134 delete comment_window;
135 delete input_selector;
136 delete output_selector;
137 delete monitor_input_button;
138 delete monitor_disk_button;
141 send_blink_connection.disconnect ();
142 rec_blink_connection.disconnect ();
148 self_destruct = true;
154 pre_fader_mute_check = 0;
155 post_fader_mute_check = 0;
156 listen_mute_check = 0;
159 solo_isolated_check = 0;
160 solo_isolated_led = 0;
164 denormal_menu_item = 0;
167 multiple_mute_change = false;
168 multiple_solo_change = false;
169 _i_am_the_modifier = 0;
174 setup_invert_buttons ();
176 mute_button = manage (new ArdourButton);
177 mute_button->set_name ("mute button");
178 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
180 solo_button = manage (new ArdourButton);
181 solo_button->set_name ("solo button");
182 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
183 solo_button->set_no_show_all (true);
185 rec_enable_button = manage (new ArdourButton);
186 rec_enable_button->set_name ("record enable button");
187 rec_enable_button->set_icon (ArdourIcon::RecButton);
188 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
190 if (UIConfiguration::instance().get_blink_rec_arm()) {
191 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
194 show_sends_button = manage (new ArdourButton);
195 show_sends_button->set_name ("send alert button");
196 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
198 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_input_button->set_name ("monitor button");
200 monitor_input_button->set_text (_("In"));
201 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
202 monitor_input_button->set_no_show_all (true);
204 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
205 monitor_disk_button->set_name ("monitor button");
206 monitor_disk_button->set_text (_("Disk"));
207 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
208 monitor_disk_button->set_no_show_all (true);
210 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
211 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
212 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
214 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
215 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
216 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
218 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
219 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
221 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
222 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
224 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
225 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
226 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
227 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
229 monitor_input_button->set_distinct_led_click (false);
230 monitor_disk_button->set_distinct_led_click (false);
232 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
233 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
235 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
236 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
238 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
244 route_connections.drop_connections ();
252 delete_patch_change_dialog ();
253 _color_picker.reset ();
255 denormal_menu_item = 0;
259 RouteUI::self_delete ()
265 RouteUI::set_route (boost::shared_ptr<Route> rp)
271 if ( !_route->presentation_info().color_set() ) {
272 /* deal with older 4.x color, which was stored in the GUI object state */
274 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
278 /* old v4.x or earlier session. Use this information */
280 int red, green, blue;
285 /* old color format version was:
287 16bit value for red:16 bit value for green:16 bit value for blue
302 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
306 if (set_color_from_route()) {
307 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
311 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
314 delete input_selector;
317 delete output_selector;
320 mute_button->set_controllable (_route->mute_control());
321 solo_button->set_controllable (_route->solo_control());
323 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
325 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
327 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
328 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
329 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
330 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
331 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
332 _route->fan_out.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::fan_out, this, true, true), gui_context());
335 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
336 track_mode_changed();
340 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
341 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
343 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
345 if (_session->writable() && is_track()) {
346 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
348 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
349 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
351 rec_enable_button->show();
352 rec_enable_button->set_controllable (t->rec_enable_control());
354 if (is_midi_track()) {
355 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
356 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
361 /* this will work for busses and tracks, and needs to be called to
362 set up the name entry/name label display.
366 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
367 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
369 update_monitoring_display ();
372 mute_button->unset_flags (Gtk::CAN_FOCUS);
373 solo_button->unset_flags (Gtk::CAN_FOCUS);
377 if (_route->is_monitor() || _route->is_master()) {
378 solo_button->hide ();
385 setup_invert_buttons ();
386 set_invert_button_state ();
388 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
389 bus_send_display_changed (s);
391 update_mute_display ();
392 update_solo_display ();
394 if (!UIConfiguration::instance().get_blink_rec_arm()) {
395 blink_rec_display(true); // set initial rec-en button state
398 check_rec_enable_sensitivity ();
399 maybe_add_route_print_mgr ();
400 route_color_changed();
401 route_gui_changed (PropertyChange (Properties::selected));
405 RouteUI::polarity_changed ()
411 set_invert_button_state ();
415 RouteUI::mute_press (GdkEventButton* ev)
417 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
421 //if this is a binding action, let the ArdourButton handle it
422 if (BindingProxy::is_bind_action(ev) )
425 multiple_mute_change = false;
427 if (Keyboard::is_context_menu_event (ev)) {
433 mute_menu->popup(0,ev->time);
439 if (Keyboard::is_button2_event (ev)) {
440 // button2-click is "momentary"
442 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
445 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
447 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
449 /* toggle mute on everything (but
450 * exclude the master and monitor)
452 * because we are going to erase
453 * elements of the list we need to work
457 boost::shared_ptr<RouteList> copy (new RouteList);
459 *copy = *_session->get_routes ();
461 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
462 if ((*i)->is_master() || (*i)->is_monitor()) {
470 _mute_release->routes = copy;
473 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
475 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
477 /* Primary-button1 inverts the implication of
478 the group being active. If the group is
479 active (for mute), then this modifier means
480 "do not apply to mute". If the group is
481 inactive (for mute), then this modifier
482 means "apply to route". This is all
483 accomplished by passing just the actual
484 route, along with the InverseGroup group
487 NOTE: Primary-button2 is MIDI learn.
490 boost::shared_ptr<RouteList> rl;
492 if (ev->button == 1) {
494 rl.reset (new RouteList);
495 rl->push_back (_route);
498 _mute_release->routes = rl;
501 boost::shared_ptr<MuteControl> mc = _route->mute_control();
502 mc->start_touch (_session->audible_sample ());
503 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
508 /* plain click applies change to this route */
510 boost::shared_ptr<RouteList> rl (new RouteList);
511 rl->push_back (_route);
514 _mute_release->routes = rl;
517 boost::shared_ptr<MuteControl> mc = _route->mute_control();
518 mc->start_touch (_session->audible_sample ());
519 mc->set_value (!_route->muted_by_self(), Controllable::UseGroup);
528 RouteUI::mute_release (GdkEventButton* /*ev*/)
531 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
532 delete _mute_release;
536 _route->mute_control()->stop_touch (_session->audible_sample ());
542 RouteUI::edit_output_configuration ()
544 if (output_selector == 0) {
546 boost::shared_ptr<Send> send;
547 boost::shared_ptr<IO> output;
549 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
550 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
551 output = send->output();
553 output = _route->output ();
556 output = _route->output ();
559 output_selector = new IOSelectorWindow (_session, output);
562 if (output_selector->is_visible()) {
563 output_selector->get_toplevel()->get_window()->raise();
565 output_selector->present ();
568 //output_selector->set_keep_above (true);
572 RouteUI::edit_input_configuration ()
574 if (input_selector == 0) {
575 input_selector = new IOSelectorWindow (_session, _route->input());
578 if (input_selector->is_visible()) {
579 input_selector->get_toplevel()->get_window()->raise();
581 input_selector->present ();
584 //input_selector->set_keep_above (true);
588 RouteUI::solo_press(GdkEventButton* ev)
590 /* ignore double/triple clicks */
592 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
596 //if this is a binding action, let the ArdourButton handle it
597 if (BindingProxy::is_bind_action(ev) )
600 multiple_solo_change = false;
602 if (Keyboard::is_context_menu_event (ev)) {
604 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
605 ! (solo_safe_led && solo_safe_led->is_visible())) {
607 if (solo_menu == 0) {
611 solo_menu->popup (1, ev->time);
616 if (Keyboard::is_button2_event (ev)) {
618 // button2-click is "momentary"
619 _solo_release = new SoloMuteRelease (_route->self_soloed());
622 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
624 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
626 /* Primary-Tertiary-click applies change to all routes */
629 _solo_release->routes = _session->get_routes ();
632 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
634 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
636 /* Primary-Secondary-click: exclusively solo this track */
639 _solo_release->exclusive = true;
641 _solo_release->routes_on.reset (new RouteList);
642 _solo_release->routes_off.reset (new RouteList);
644 boost::shared_ptr<RouteList> routes = _session->get_routes();
645 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
647 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
651 if ((*i)->soloed ()) {
652 _solo_release->routes_on->push_back (*i);
654 _solo_release->routes_off->push_back (*i);
659 boost::shared_ptr<RouteList> rl (new RouteList);
660 boost::shared_ptr<RouteList> routes = _session->get_routes();
661 for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
663 if ((0 == _route->mixbus()) != (0 == (*i)->mixbus ())) {
667 if ((*i)->soloed ()) {
671 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), false, Controllable::UseGroup);
673 if (Config->get_solo_control_is_listen_control()) {
674 /* ??? we need a just_one_listen() method */
677 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
680 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
682 // shift-click: toggle solo isolated status
684 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
685 delete _solo_release;
688 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
690 /* Primary-button1: solo mix group.
691 NOTE: Primary-button2 is MIDI learn.
694 /* Primary-button1 applies change to the mix group even if it is not active
695 NOTE: Primary-button2 is MIDI learn.
698 boost::shared_ptr<RouteList> rl;
700 if (ev->button == 1) {
702 /* Primary-button1 inverts the implication of
703 the group being active. If the group is
704 active (for solo), then this modifier means
705 "do not apply to solo". If the group is
706 inactive (for mute), then this modifier
707 means "apply to route". This is all
708 accomplished by passing just the actual
709 route, along with the InverseGroup group
712 NOTE: Primary-button2 is MIDI learn.
715 rl.reset (new RouteList);
716 rl->push_back (_route);
719 _solo_release->routes = rl;
722 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
725 delete _solo_release;
730 /* click: solo this route */
732 boost::shared_ptr<RouteList> rl (new RouteList);
733 rl->push_back (route());
736 _solo_release->routes = rl;
739 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
748 RouteUI::solo_release (GdkEventButton* /*ev*/)
751 if (_solo_release->exclusive) {
752 _session->set_controls (route_list_to_control_list (_solo_release->routes_off, &Stripable::solo_control), 0.0, Controllable::NoGroup);
753 _session->set_controls (route_list_to_control_list (_solo_release->routes_on, &Stripable::solo_control), 1.0, Controllable::NoGroup);
755 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
758 delete _solo_release;
766 RouteUI::rec_enable_press(GdkEventButton* ev)
768 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
772 //if this is a binding action, let the ArdourButton handle it
773 if (BindingProxy::is_bind_action(ev) )
776 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
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 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
908 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
910 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() | monitor_choice);
913 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
914 /* Primary-Tertiary-click applies change to all routes */
915 rl = _session->get_routes ();
916 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
917 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
918 /* Primary-click overrides group */
919 rl.reset (new RouteList);
920 rl->push_back (route());
921 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
923 rl.reset (new RouteList);
924 rl->push_back (route());
925 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
932 RouteUI::build_record_menu ()
935 record_menu = new Menu;
936 record_menu->set_name ("ArdourContextMenu");
937 using namespace Menu_Helpers;
938 MenuList& items = record_menu->items();
940 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
941 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
943 if (is_midi_track()) {
944 items.push_back (SeparatorElem());
945 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
946 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
950 if (step_edit_item) {
951 if (track()->rec_enable_control()->get_value()) {
952 step_edit_item->set_sensitive (false);
954 step_edit_item->set_active (midi_track()->step_editing());
957 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
958 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
963 RouteUI::toggle_step_edit ()
965 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
969 midi_track()->set_step_editing (step_edit_item->get_active());
973 RouteUI::toggle_rec_safe ()
975 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
981 /* This check is made inside the control too, but dong it here can't
985 if (_route->rec_enable_control()->get_value()) {
989 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
993 RouteUI::step_edit_changed (bool yn)
996 if (rec_enable_button) {
997 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1000 start_step_editing ();
1002 if (step_edit_item) {
1003 step_edit_item->set_active (true);
1008 if (rec_enable_button) {
1009 rec_enable_button->unset_active_state ();
1012 stop_step_editing ();
1014 if (step_edit_item) {
1015 step_edit_item->set_active (false);
1021 RouteUI::rec_enable_release (GdkEventButton* ev)
1023 if (Keyboard::is_context_menu_event (ev)) {
1024 build_record_menu ();
1026 record_menu->popup (1, ev->time);
1035 RouteUI::build_sends_menu ()
1037 using namespace Menu_Helpers;
1039 sends_menu = new Menu;
1040 sends_menu->set_name ("ArdourContextMenu");
1041 MenuList& items = sends_menu->items();
1044 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1048 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1052 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1056 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1060 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1064 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1067 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1071 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1074 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1075 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1076 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1081 RouteUI::create_sends (Placement p, bool include_buses)
1083 _session->globally_add_internal_sends (_route, p, include_buses);
1087 RouteUI::create_selected_sends (Placement p, bool include_buses)
1089 boost::shared_ptr<RouteList> rlist (new RouteList);
1090 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1092 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1093 RouteTimeAxisView* rtv;
1095 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1096 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1097 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1098 rlist->push_back (rui->route());
1104 _session->add_internal_sends (_route, p, rlist);
1108 RouteUI::set_sends_gain_from_track ()
1110 _session->globally_set_send_gains_from_track (_route);
1114 RouteUI::set_sends_gain_to_zero ()
1116 _session->globally_set_send_gains_to_zero (_route);
1120 RouteUI::set_sends_gain_to_unity ()
1122 _session->globally_set_send_gains_to_unity (_route);
1126 RouteUI::show_sends_press(GdkEventButton* ev)
1128 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1132 if (!is_track() && show_sends_button) {
1134 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1136 // do nothing on midi sigc::bind event
1139 } else if (Keyboard::is_context_menu_event (ev)) {
1141 if (sends_menu == 0) {
1142 build_sends_menu ();
1145 sends_menu->popup (0, ev->time);
1149 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1152 set_showing_sends_to (boost::shared_ptr<Route> ());
1154 set_showing_sends_to (_route);
1163 RouteUI::show_sends_release (GdkEventButton*)
1169 RouteUI::send_blink (bool onoff)
1171 if (!show_sends_button) {
1176 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1178 show_sends_button->unset_active_state ();
1182 Gtkmm2ext::ActiveState
1183 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1185 boost::shared_ptr<SoloControl> sc = s->solo_control();
1188 return Gtkmm2ext::Off;
1191 if (!sc->can_solo()) {
1192 return Gtkmm2ext::Off;
1196 if (sc->self_soloed()) {
1197 return Gtkmm2ext::ExplicitActive;
1198 } else if (sc->soloed_by_others()) {
1199 return Gtkmm2ext::ImplicitActive;
1201 return Gtkmm2ext::Off;
1205 Gtkmm2ext::ActiveState
1206 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1208 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1211 return Gtkmm2ext::Off;
1214 if (s->is_master() || s->is_monitor()) {
1215 return Gtkmm2ext::Off;
1218 if (sc->solo_isolated()) {
1219 return Gtkmm2ext::ExplicitActive;
1221 return Gtkmm2ext::Off;
1225 Gtkmm2ext::ActiveState
1226 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1228 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1231 return Gtkmm2ext::Off;
1234 if (s->is_master() || s->is_monitor()) {
1235 return Gtkmm2ext::Off;
1238 if (sc->solo_safe()) {
1239 return Gtkmm2ext::ExplicitActive;
1241 return Gtkmm2ext::Off;
1246 RouteUI::update_solo_display ()
1248 bool yn = _route->solo_safe_control()->solo_safe ();
1250 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1251 solo_safe_check->set_active (yn);
1254 yn = _route->solo_isolate_control()->solo_isolated ();
1256 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1257 solo_isolated_check->set_active (yn);
1260 set_button_names ();
1262 if (solo_isolated_led) {
1263 if (_route->solo_isolate_control()->solo_isolated()) {
1264 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1266 solo_isolated_led->unset_active_state ();
1270 if (solo_safe_led) {
1271 if (_route->solo_safe_control()->solo_safe()) {
1272 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1274 solo_safe_led->unset_active_state ();
1278 solo_button->set_active_state (solo_active_state (_route));
1280 /* some changes to solo status can affect mute display, so catch up
1283 update_mute_display ();
1287 RouteUI::solo_changed_so_update_mute ()
1289 update_mute_display ();
1293 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1295 boost::shared_ptr<MuteControl> mc = s->mute_control();
1297 if (s->is_monitor()) {
1298 return Gtkmm2ext::Off;
1302 return Gtkmm2ext::Off;
1305 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1307 if (mc->muted_by_self ()) {
1309 return Gtkmm2ext::ExplicitActive;
1310 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1311 /* this will reflect both solo mutes AND master mutes */
1312 return Gtkmm2ext::ImplicitActive;
1314 /* no mute at all */
1315 return Gtkmm2ext::Off;
1320 if (mc->muted_by_self()) {
1322 return Gtkmm2ext::ExplicitActive;
1323 } else if (mc->muted_by_masters ()) {
1324 /* this shows only master mutes, not mute-by-others-soloing */
1325 return Gtkmm2ext::ImplicitActive;
1327 /* no mute at all */
1328 return Gtkmm2ext::Off;
1332 return ActiveState(0);
1336 RouteUI::update_mute_display ()
1342 mute_button->set_active_state (mute_active_state (_session, _route));
1347 RouteUI::route_rec_enable_changed ()
1349 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1353 RouteUI::session_rec_enable_changed ()
1355 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1359 RouteUI::blink_rec_display (bool blinkOn)
1361 if (!rec_enable_button || !_route) {
1365 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1373 if (track()->rec_enable_control()->get_value()) {
1374 switch (_session->record_status ()) {
1375 case Session::Recording:
1376 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1379 case Session::Disabled:
1380 case Session::Enabled:
1381 if (UIConfiguration::instance().get_blink_rec_arm()) {
1382 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1384 rec_enable_button->set_active_state ( ImplicitActive );
1389 if (step_edit_item) {
1390 step_edit_item->set_sensitive (false);
1394 rec_enable_button->unset_active_state ();
1396 if (step_edit_item) {
1397 step_edit_item->set_sensitive (true);
1401 check_rec_enable_sensitivity ();
1405 RouteUI::build_solo_menu (void)
1407 using namespace Menu_Helpers;
1409 solo_menu = new Menu;
1410 solo_menu->set_name ("ArdourContextMenu");
1411 MenuList& items = solo_menu->items();
1412 Gtk::CheckMenuItem* check;
1414 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1415 check->set_active (_route->solo_isolate_control()->solo_isolated());
1416 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1417 items.push_back (CheckMenuElem(*check));
1418 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1421 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1422 check->set_active (_route->solo_safe_control()->solo_safe());
1423 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1424 items.push_back (CheckMenuElem(*check));
1425 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1430 RouteUI::build_mute_menu(void)
1432 using namespace Menu_Helpers;
1434 mute_menu = new Menu;
1435 mute_menu->set_name ("ArdourContextMenu");
1437 MenuList& items = mute_menu->items();
1439 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1440 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1441 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1442 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1443 pre_fader_mute_check->show_all();
1445 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1446 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1447 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1448 items.push_back (CheckMenuElem(*post_fader_mute_check));
1449 post_fader_mute_check->show_all();
1451 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1452 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1453 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1454 items.push_back (CheckMenuElem(*listen_mute_check));
1455 listen_mute_check->show_all();
1457 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1458 init_mute_menu(MuteMaster::Main, main_mute_check);
1459 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1460 items.push_back (CheckMenuElem(*main_mute_check));
1461 main_mute_check->show_all();
1463 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1467 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1469 check->set_active (_route->mute_control()->mute_points() & mp);
1473 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1475 if (check->get_active()) {
1476 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1478 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1483 RouteUI::muting_change ()
1485 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1488 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1490 yn = (current & MuteMaster::PreFader);
1492 if (pre_fader_mute_check->get_active() != yn) {
1493 pre_fader_mute_check->set_active (yn);
1496 yn = (current & MuteMaster::PostFader);
1498 if (post_fader_mute_check->get_active() != yn) {
1499 post_fader_mute_check->set_active (yn);
1502 yn = (current & MuteMaster::Listen);
1504 if (listen_mute_check->get_active() != yn) {
1505 listen_mute_check->set_active (yn);
1508 yn = (current & MuteMaster::Main);
1510 if (main_mute_check->get_active() != yn) {
1511 main_mute_check->set_active (yn);
1516 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1518 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1522 bool view = solo_isolated_led->active_state();
1523 bool model = _route->solo_isolate_control()->solo_isolated();
1525 /* called BEFORE the view has changed */
1527 if (ev->button == 1) {
1528 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1531 /* disable isolate for all routes */
1532 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1534 /* enable isolate for all routes */
1535 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1540 if (model == view) {
1542 /* flip just this route */
1544 boost::shared_ptr<RouteList> rl (new RouteList);
1545 rl->push_back (_route);
1546 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1555 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1557 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1561 bool view = solo_safe_led->active_state();
1562 bool model = _route->solo_safe_control()->solo_safe();
1564 if (ev->button == 1) {
1565 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1566 boost::shared_ptr<RouteList> rl (_session->get_routes());
1568 /* disable solo safe for all routes */
1569 DisplaySuspender ds;
1570 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1571 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1574 /* enable solo safe for all routes */
1575 DisplaySuspender ds;
1576 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1577 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1582 if (model == view) {
1583 /* flip just this route */
1584 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1593 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1595 bool view = check->get_active();
1596 bool model = _route->solo_isolate_control()->solo_isolated();
1598 /* called AFTER the view has changed */
1600 if (model != view) {
1601 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1606 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1608 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1612 RouteUI::delete_patch_change_dialog ()
1617 delete _route->patch_selector_dialog ();
1618 _route->set_patch_selector_dialog (0);
1621 PatchChangeGridDialog*
1622 RouteUI::patch_change_dialog () const
1624 return _route->patch_selector_dialog ();
1628 RouteUI::select_midi_patch ()
1630 if (patch_change_dialog ()) {
1631 patch_change_dialog()->present ();
1635 /* note: RouteTimeAxisView is resoponsible to updating
1636 * the Dialog (PatchChangeGridDialog::refresh())
1637 * when the midnam model changes.
1639 PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1640 _route->set_patch_selector_dialog (d);
1644 /** Ask the user to choose a colour, and then apply that color to my route */
1646 RouteUI::choose_color ()
1648 _color_picker.popup (_route);
1651 /** Set the route's own color. This may not be used for display if
1652 * the route is in a group which shares its color with its routes.
1655 RouteUI::set_color (uint32_t c)
1657 _route->presentation_info().set_color (c);
1660 /** @return GUI state ID for things that are common to the route in all its representations */
1662 RouteUI::route_state_id () const
1664 return string_compose (X_("route %1"), _route->id().to_s());
1668 RouteUI::set_color_from_route ()
1670 if (_route->presentation_info().color_set()) {
1671 return 0; /* nothing to do */
1674 return 1; /* pick a color */
1677 /** @return true if this name should be used for the route, otherwise false */
1679 RouteUI::verify_new_route_name (const std::string& name)
1681 if (name.find (':') == string::npos) {
1685 MessageDialog colon_msg (
1686 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1687 false, MESSAGE_QUESTION, BUTTONS_NONE
1690 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1691 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1693 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1697 RouteUI::route_rename ()
1699 ArdourWidgets::Prompter name_prompter (true);
1704 name_prompter.set_title (_("Rename Track"));
1706 name_prompter.set_title (_("Rename Bus"));
1708 name_prompter.set_prompt (_("New name:"));
1709 name_prompter.set_initial_text (_route->name());
1710 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1711 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1712 name_prompter.show_all ();
1715 switch (name_prompter.run ()) {
1716 case Gtk::RESPONSE_ACCEPT:
1717 name_prompter.get_result (result);
1718 name_prompter.hide ();
1719 if (result.length()) {
1720 if (verify_new_route_name (result)) {
1721 _route->set_name (result);
1724 /* back to name prompter */
1728 /* nothing entered, just get out of here */
1743 RouteUI::toggle_comment_editor ()
1745 // if (ignore_toggle) {
1749 if (comment_window && comment_window->is_visible ()) {
1750 comment_window->hide ();
1752 open_comment_editor ();
1758 RouteUI::open_comment_editor ()
1760 if (comment_window == 0) {
1761 setup_comment_editor ();
1765 title = _route->name();
1766 title += _(": comment editor");
1768 comment_window->set_title (title);
1769 comment_window->present();
1773 RouteUI::setup_comment_editor ()
1775 comment_window = new ArdourWindow (""); // title will be reset to show route
1776 comment_window->set_skip_taskbar_hint (true);
1777 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1778 comment_window->set_default_size (400, 200);
1780 comment_area = manage (new TextView());
1781 comment_area->set_name ("MixerTrackCommentArea");
1782 comment_area->set_wrap_mode (WRAP_WORD);
1783 comment_area->set_editable (true);
1784 comment_area->get_buffer()->set_text (_route->comment());
1785 comment_area->show ();
1787 comment_window->add (*comment_area);
1791 RouteUI::comment_changed ()
1793 ignore_comment_edit = true;
1795 comment_area->get_buffer()->set_text (_route->comment());
1797 ignore_comment_edit = false;
1801 RouteUI::comment_editor_done_editing ()
1803 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1805 string const str = comment_area->get_buffer()->get_text();
1806 if (str == _route->comment ()) {
1810 _route->set_comment (str, this);
1814 RouteUI::set_route_active (bool a, bool apply_to_selection)
1816 if (apply_to_selection) {
1817 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1819 _route->set_active (a, this);
1824 RouteUI::duplicate_selected_routes ()
1826 ARDOUR_UI::instance()->start_duplicate_routes();
1830 RouteUI::toggle_denormal_protection ()
1832 if (denormal_menu_item) {
1836 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1838 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1839 _route->set_denormal_protection (x);
1845 RouteUI::denormal_protection_changed ()
1847 if (denormal_menu_item) {
1848 denormal_menu_item->set_active (_route->denormal_protection());
1853 RouteUI::disconnect_input ()
1855 _route->input()->disconnect (this);
1859 RouteUI::disconnect_output ()
1861 _route->output()->disconnect (this);
1865 RouteUI::is_track () const
1867 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1870 boost::shared_ptr<Track>
1871 RouteUI::track() const
1873 return boost::dynamic_pointer_cast<Track>(_route);
1877 RouteUI::is_audio_track () const
1879 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1882 boost::shared_ptr<AudioTrack>
1883 RouteUI::audio_track() const
1885 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1889 RouteUI::is_midi_track () const
1891 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1894 boost::shared_ptr<MidiTrack>
1895 RouteUI::midi_track() const
1897 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1901 RouteUI::has_audio_outputs () const
1903 return (_route->n_outputs().n_audio() > 0);
1907 RouteUI::map_frozen ()
1909 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1911 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1914 check_rec_enable_sensitivity ();
1919 RouteUI::adjust_latency ()
1921 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->sample_rate(), AudioEngine::instance()->samples_per_cycle());
1926 RouteUI::save_as_template_dialog_response (int response, SaveTemplateDialog* d)
1928 if (response == RESPONSE_ACCEPT) {
1929 const string name = d->get_template_name ();
1930 const string desc = d->get_description ();
1931 const string path = Glib::build_filename(ARDOUR::user_route_template_directory (), name + ARDOUR::template_suffix);
1933 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { /* file already exists. */
1934 bool overwrite = overwrite_file_dialog (*d,
1935 _("Confirm Template Overwrite"),
1936 _("A template already exists with that name. Do you want to overwrite it?"));
1943 _route->save_as_template (path, name, desc);
1950 RouteUI::save_as_template ()
1952 const std::string dir = ARDOUR::user_route_template_directory ();
1954 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1955 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1959 SaveTemplateDialog* d = new SaveTemplateDialog (_route->name(), _route->comment());
1960 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::save_as_template_dialog_response), d));
1965 RouteUI::check_rec_enable_sensitivity ()
1967 if (!rec_enable_button) {
1968 assert (0); // This should not happen
1971 if (!_session->writable()) {
1972 rec_enable_button->set_sensitive (false);
1976 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1977 rec_enable_button->set_sensitive (false);
1978 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1979 rec_enable_button->set_sensitive (false);
1981 rec_enable_button->set_sensitive (true);
1983 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1984 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1986 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1988 update_monitoring_display ();
1992 RouteUI::parameter_changed (string const & p)
1994 /* this handles RC and per-session parameter changes */
1996 if (p == "disable-disarm-during-roll") {
1997 check_rec_enable_sensitivity ();
1998 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1999 set_button_names ();
2000 } else if (p == "session-monitoring") {
2001 update_monitoring_display ();
2002 } else if (p == "auto-input") {
2003 update_monitoring_display ();
2004 } else if (p == "blink-rec-arm") {
2005 if (UIConfiguration::instance().get_blink_rec_arm()) {
2006 rec_blink_connection.disconnect ();
2007 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2009 rec_blink_connection.disconnect ();
2010 RouteUI::blink_rec_display(false);
2016 RouteUI::setup_invert_buttons ()
2018 /* remove old invert buttons */
2019 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2020 _invert_button_box.remove (**i);
2023 _invert_buttons.clear ();
2025 if (!_route || !_route->input()) {
2029 uint32_t const N = _route->input()->n_ports().n_audio ();
2031 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2033 for (uint32_t i = 0; i < to_add; ++i) {
2034 ArdourButton* b = manage (new ArdourButton);
2035 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2036 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2038 b->set_name (X_("invert button"));
2041 b->set_text (string_compose (X_("Ø (%1)"), N));
2043 b->set_text (X_("Ø"));
2046 b->set_text (string_compose (X_("Ø%1"), i + 1));
2049 if (N <= _max_invert_buttons) {
2050 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));
2052 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2055 _invert_buttons.push_back (b);
2056 _invert_button_box.pack_start (*b);
2059 _invert_button_box.set_spacing (1);
2060 _invert_button_box.show_all ();
2064 RouteUI::set_invert_button_state ()
2066 uint32_t const N = _route->input()->n_ports().n_audio();
2067 if (N > _max_invert_buttons) {
2069 /* One button for many channels; explicit active if all channels are inverted,
2070 implicit active if some are, off if none are.
2073 ArdourButton* b = _invert_buttons.front ();
2075 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2076 b->set_active_state (Gtkmm2ext::ExplicitActive);
2077 } else if (_route->phase_control()->any()) {
2078 b->set_active_state (Gtkmm2ext::ImplicitActive);
2080 b->set_active_state (Gtkmm2ext::Off);
2085 /* One button per channel; just set active */
2088 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2089 (*i)->set_active (_route->phase_control()->inverted (j));
2096 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2098 if (ev->button == 1 && i < _invert_buttons.size()) {
2099 uint32_t const N = _route->input()->n_ports().n_audio ();
2100 if (N <= _max_invert_buttons) {
2101 /* left-click inverts phase so long as we have a button per channel */
2102 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2111 RouteUI::invert_press (GdkEventButton* ev)
2113 using namespace Menu_Helpers;
2115 uint32_t const N = _route->input()->n_ports().n_audio();
2116 if (N <= _max_invert_buttons && ev->button != 3) {
2117 /* If we have an invert button per channel, we only pop
2118 up a menu on right-click; left click is handled
2124 delete _invert_menu;
2125 _invert_menu = new Menu;
2126 _invert_menu->set_name ("ArdourContextMenu");
2127 MenuList& items = _invert_menu->items ();
2129 for (uint32_t i = 0; i < N; ++i) {
2130 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2131 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2132 ++_i_am_the_modifier;
2133 e->set_active (_route->phase_control()->inverted (i));
2134 --_i_am_the_modifier;
2137 _invert_menu->popup (0, ev->time);
2143 RouteUI::invert_menu_toggled (uint32_t c)
2145 if (_i_am_the_modifier) {
2150 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2154 RouteUI::set_invert_sensitive (bool yn)
2156 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2157 (*b)->set_sensitive (yn);
2161 /** The Route's gui_changed signal has been emitted */
2163 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2165 if (what_changed.contains (Properties::color)) {
2166 if (set_color_from_route () == 0) {
2167 route_color_changed ();
2173 RouteUI::track_mode_changed (void)
2176 switch (track()->mode()) {
2177 case ARDOUR::NonLayered:
2178 case ARDOUR::Normal:
2179 rec_enable_button->set_icon (ArdourIcon::RecButton);
2181 case ARDOUR::Destructive:
2182 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2185 rec_enable_button->queue_draw();
2188 /** @return the color that this route should use; it maybe its own,
2189 * or it maybe that of its route group.
2192 RouteUI::route_color () const
2195 RouteGroup* g = _route->route_group ();
2198 if (g && g->is_color()) {
2199 set_color_from_rgba (c, GroupTabs::group_color (g));
2201 set_color_from_rgba (c, _route->presentation_info().color());
2208 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2210 _showing_sends_to = send_to;
2211 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2215 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2217 if (_route == send_to) {
2218 show_sends_button->set_active (true);
2219 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2221 show_sends_button->set_active (false);
2222 send_blink_connection.disconnect ();
2227 RouteUI::route_group() const
2229 return _route->route_group();
2233 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2234 : WM::ProxyBase (name, string())
2235 , _route (boost::weak_ptr<Route> (route))
2237 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2240 RoutePinWindowProxy::~RoutePinWindowProxy()
2245 ARDOUR::SessionHandlePtr*
2246 RoutePinWindowProxy::session_handle ()
2248 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2249 if (aw) { return aw; }
2254 RoutePinWindowProxy::get (bool create)
2256 boost::shared_ptr<Route> r = _route.lock ();
2265 _window = new PluginPinDialog (r);
2266 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2268 aw->set_session (_session);
2270 _window->show_all ();
2276 RoutePinWindowProxy::route_going_away ()
2280 WM::Manager::instance().remove (this);
2281 going_away_connection.disconnect();
2286 RouteUI::maybe_add_route_print_mgr ()
2288 if (_route->pinmgr_proxy ()) {
2291 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2292 string_compose ("RPM-%1", _route->id()), _route);
2293 wp->set_session (_session);
2295 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2297 wp->set_state (*ui_xml, 0);
2301 void* existing_ui = _route->pinmgr_proxy ();
2303 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2306 _route->set_pingmgr_proxy (wp);
2308 WM::Manager::instance().register_window (wp);
2312 RouteUI::manage_pins ()
2314 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2322 RouteUI::fan_out (bool to_busses, bool group)
2324 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
2328 DisplaySuspender ds;
2329 boost::shared_ptr<ARDOUR::Route> route = _route;
2330 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2333 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2334 if (route->n_outputs ().n_audio () != n_outputs) {
2335 MessageDialog msg (string_compose (
2336 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2337 n_outputs, route->n_outputs ().n_audio ()));
2342 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2344 /* count busses and channels/bus */
2345 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2346 std::map<std::string, uint32_t> busnames;
2347 for (uint32_t p = 0; p < n_outputs; ++p) {
2348 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2349 std::string bn = BUSNAME;
2353 if (busnames.size () < 2) {
2354 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2359 uint32_t outputs = 2;
2360 if (_session->master_out ()) {
2361 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2364 route->output ()->disconnect (this);
2365 route->panner_shell ()->set_bypassed (true);
2368 for (uint32_t p = 0; p < n_outputs; ++p) {
2369 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2370 std::string bn = BUSNAME;
2371 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2375 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2379 list<boost::shared_ptr<AudioTrack> > tl =
2380 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2384 boost::shared_ptr<ControlList> cl (new ControlList);
2385 cl->push_back (r->monitoring_control ());
2386 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2389 if (!to_group.empty()) {
2390 boost::shared_ptr<RouteList> rl (&to_group);
2391 _session->remove_routes (rl);
2395 r->input ()->disconnect (this);
2397 to_group.push_back (r);
2398 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2403 RouteGroup* rg = NULL;
2404 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2405 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2406 if ((*i)->name () == pi->name ()) {
2412 rg = new RouteGroup (*_session, pi->name ());
2413 _session->add_route_group (rg);
2414 rg->set_gain (false);
2417 GroupTabs::set_group_color (rg, route->presentation_info().color());
2418 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2425 RouteUI::mark_hidden (bool yn)
2427 if (yn != _route->presentation_info().hidden()) {
2428 _route->presentation_info().set_hidden (yn);
2429 return true; // things changed
2434 boost::shared_ptr<Stripable>
2435 RouteUI::stripable () const
2441 RouteUI::set_disk_io_point (DiskIOPoint diop)
2443 if (_route && is_track()) {
2444 track()->set_disk_io_point (diop);