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_frame ());
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_frame ());
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_frame ());
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 (!_session->engine().connected()) {
777 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
782 if (is_midi_track()) {
784 /* rec-enable button exits from step editing */
786 if (midi_track()->step_editing()) {
787 midi_track()->set_step_editing (false);
792 if (is_track() && rec_enable_button) {
794 if (Keyboard::is_button2_event (ev)) {
796 //rec arm does not have a momentary mode
799 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
801 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
803 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
805 /* Primary-button1 applies change to the route group (even if it is not active)
806 NOTE: Primary-button2 is MIDI learn.
809 if (ev->button == 1) {
811 boost::shared_ptr<RouteList> rl;
813 rl.reset (new RouteList);
814 rl->push_back (_route);
816 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
819 } else if (Keyboard::is_context_menu_event (ev)) {
821 /* do this on release */
825 boost::shared_ptr<Track> trk = track();
826 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
834 RouteUI::update_monitoring_display ()
840 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
846 MonitorState ms = t->monitoring_state();
848 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
849 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
851 if (ms & MonitoringInput) {
852 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
854 monitor_input_button->unset_active_state ();
858 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
859 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
861 if (ms & MonitoringDisk) {
862 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
864 monitor_disk_button->unset_active_state ();
870 RouteUI::monitor_input_press(GdkEventButton*)
876 RouteUI::monitor_input_release(GdkEventButton* ev)
878 return monitor_release (ev, MonitorInput);
882 RouteUI::monitor_disk_press (GdkEventButton*)
888 RouteUI::monitor_disk_release (GdkEventButton* ev)
890 return monitor_release (ev, MonitorDisk);
894 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
896 if (ev->button != 1) {
900 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
907 boost::shared_ptr<RouteList> rl;
909 /* XXX for now, monitoring choices are orthogonal. cue monitoring
910 will follow in 3.X but requires mixing the input and playback (disk)
911 signal together, which requires yet more buffers.
914 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
915 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
917 /* this line will change when the options are non-orthogonal */
918 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
922 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
923 /* Primary-Tertiary-click applies change to all routes */
924 rl = _session->get_routes ();
925 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
926 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
927 /* Primary-click overrides group */
928 rl.reset (new RouteList);
929 rl->push_back (route());
930 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
932 rl.reset (new RouteList);
933 rl->push_back (route());
934 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
941 RouteUI::build_record_menu ()
944 record_menu = new Menu;
945 record_menu->set_name ("ArdourContextMenu");
946 using namespace Menu_Helpers;
947 MenuList& items = record_menu->items();
949 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
950 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
952 if (is_midi_track()) {
953 items.push_back (SeparatorElem());
954 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
955 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
959 if (step_edit_item) {
960 if (track()->rec_enable_control()->get_value()) {
961 step_edit_item->set_sensitive (false);
963 step_edit_item->set_active (midi_track()->step_editing());
966 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
967 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
972 RouteUI::toggle_step_edit ()
974 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
978 midi_track()->set_step_editing (step_edit_item->get_active());
982 RouteUI::toggle_rec_safe ()
984 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
990 /* This check is made inside the control too, but dong it here can't
994 if (_route->rec_enable_control()->get_value()) {
998 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
1002 RouteUI::step_edit_changed (bool yn)
1005 if (rec_enable_button) {
1006 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1009 start_step_editing ();
1011 if (step_edit_item) {
1012 step_edit_item->set_active (true);
1017 if (rec_enable_button) {
1018 rec_enable_button->unset_active_state ();
1021 stop_step_editing ();
1023 if (step_edit_item) {
1024 step_edit_item->set_active (false);
1030 RouteUI::rec_enable_release (GdkEventButton* ev)
1032 if (Keyboard::is_context_menu_event (ev)) {
1033 build_record_menu ();
1035 record_menu->popup (1, ev->time);
1044 RouteUI::build_sends_menu ()
1046 using namespace Menu_Helpers;
1048 sends_menu = new Menu;
1049 sends_menu->set_name ("ArdourContextMenu");
1050 MenuList& items = sends_menu->items();
1053 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1057 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1061 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1065 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1069 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1073 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1076 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1080 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1083 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1084 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1085 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1090 RouteUI::create_sends (Placement p, bool include_buses)
1092 _session->globally_add_internal_sends (_route, p, include_buses);
1096 RouteUI::create_selected_sends (Placement p, bool include_buses)
1098 boost::shared_ptr<RouteList> rlist (new RouteList);
1099 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1101 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1102 RouteTimeAxisView* rtv;
1104 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1105 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1106 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1107 rlist->push_back (rui->route());
1113 _session->add_internal_sends (_route, p, rlist);
1117 RouteUI::set_sends_gain_from_track ()
1119 _session->globally_set_send_gains_from_track (_route);
1123 RouteUI::set_sends_gain_to_zero ()
1125 _session->globally_set_send_gains_to_zero (_route);
1129 RouteUI::set_sends_gain_to_unity ()
1131 _session->globally_set_send_gains_to_unity (_route);
1135 RouteUI::show_sends_press(GdkEventButton* ev)
1137 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1141 if (!is_track() && show_sends_button) {
1143 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1145 // do nothing on midi sigc::bind event
1148 } else if (Keyboard::is_context_menu_event (ev)) {
1150 if (sends_menu == 0) {
1151 build_sends_menu ();
1154 sends_menu->popup (0, ev->time);
1158 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1161 set_showing_sends_to (boost::shared_ptr<Route> ());
1163 set_showing_sends_to (_route);
1172 RouteUI::show_sends_release (GdkEventButton*)
1178 RouteUI::send_blink (bool onoff)
1180 if (!show_sends_button) {
1185 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1187 show_sends_button->unset_active_state ();
1191 Gtkmm2ext::ActiveState
1192 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1194 boost::shared_ptr<SoloControl> sc = s->solo_control();
1197 return Gtkmm2ext::Off;
1200 if (!sc->can_solo()) {
1201 return Gtkmm2ext::Off;
1205 if (sc->self_soloed()) {
1206 return Gtkmm2ext::ExplicitActive;
1207 } else if (sc->soloed_by_others()) {
1208 return Gtkmm2ext::ImplicitActive;
1210 return Gtkmm2ext::Off;
1214 Gtkmm2ext::ActiveState
1215 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1217 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1220 return Gtkmm2ext::Off;
1223 if (s->is_master() || s->is_monitor()) {
1224 return Gtkmm2ext::Off;
1227 if (sc->solo_isolated()) {
1228 return Gtkmm2ext::ExplicitActive;
1230 return Gtkmm2ext::Off;
1234 Gtkmm2ext::ActiveState
1235 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1237 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1240 return Gtkmm2ext::Off;
1243 if (s->is_master() || s->is_monitor()) {
1244 return Gtkmm2ext::Off;
1247 if (sc->solo_safe()) {
1248 return Gtkmm2ext::ExplicitActive;
1250 return Gtkmm2ext::Off;
1255 RouteUI::update_solo_display ()
1257 bool yn = _route->solo_safe_control()->solo_safe ();
1259 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1260 solo_safe_check->set_active (yn);
1263 yn = _route->solo_isolate_control()->solo_isolated ();
1265 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1266 solo_isolated_check->set_active (yn);
1269 set_button_names ();
1271 if (solo_isolated_led) {
1272 if (_route->solo_isolate_control()->solo_isolated()) {
1273 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1275 solo_isolated_led->unset_active_state ();
1279 if (solo_safe_led) {
1280 if (_route->solo_safe_control()->solo_safe()) {
1281 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1283 solo_safe_led->unset_active_state ();
1287 solo_button->set_active_state (solo_active_state (_route));
1289 /* some changes to solo status can affect mute display, so catch up
1292 update_mute_display ();
1296 RouteUI::solo_changed_so_update_mute ()
1298 update_mute_display ();
1302 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1304 boost::shared_ptr<MuteControl> mc = s->mute_control();
1306 if (s->is_monitor()) {
1307 return Gtkmm2ext::Off;
1311 return Gtkmm2ext::Off;
1314 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1316 if (mc->muted_by_self ()) {
1318 return Gtkmm2ext::ExplicitActive;
1319 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1320 /* this will reflect both solo mutes AND master mutes */
1321 return Gtkmm2ext::ImplicitActive;
1323 /* no mute at all */
1324 return Gtkmm2ext::Off;
1329 if (mc->muted_by_self()) {
1331 return Gtkmm2ext::ExplicitActive;
1332 } else if (mc->muted_by_masters ()) {
1333 /* this shows only master mutes, not mute-by-others-soloing */
1334 return Gtkmm2ext::ImplicitActive;
1336 /* no mute at all */
1337 return Gtkmm2ext::Off;
1341 return ActiveState(0);
1345 RouteUI::update_mute_display ()
1351 mute_button->set_active_state (mute_active_state (_session, _route));
1356 RouteUI::route_rec_enable_changed ()
1358 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1362 RouteUI::session_rec_enable_changed ()
1364 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1368 RouteUI::blink_rec_display (bool blinkOn)
1370 if (!rec_enable_button || !_route) {
1374 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1382 if (track()->rec_enable_control()->get_value()) {
1383 switch (_session->record_status ()) {
1384 case Session::Recording:
1385 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1388 case Session::Disabled:
1389 case Session::Enabled:
1390 if (UIConfiguration::instance().get_blink_rec_arm()) {
1391 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1393 rec_enable_button->set_active_state ( ImplicitActive );
1398 if (step_edit_item) {
1399 step_edit_item->set_sensitive (false);
1403 rec_enable_button->unset_active_state ();
1405 if (step_edit_item) {
1406 step_edit_item->set_sensitive (true);
1410 check_rec_enable_sensitivity ();
1414 RouteUI::build_solo_menu (void)
1416 using namespace Menu_Helpers;
1418 solo_menu = new Menu;
1419 solo_menu->set_name ("ArdourContextMenu");
1420 MenuList& items = solo_menu->items();
1421 Gtk::CheckMenuItem* check;
1423 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1424 check->set_active (_route->solo_isolate_control()->solo_isolated());
1425 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1426 items.push_back (CheckMenuElem(*check));
1427 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1430 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1431 check->set_active (_route->solo_safe_control()->solo_safe());
1432 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1433 items.push_back (CheckMenuElem(*check));
1434 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1439 RouteUI::build_mute_menu(void)
1441 using namespace Menu_Helpers;
1443 mute_menu = new Menu;
1444 mute_menu->set_name ("ArdourContextMenu");
1446 MenuList& items = mute_menu->items();
1448 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1449 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1450 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1451 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1452 pre_fader_mute_check->show_all();
1454 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1455 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1456 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1457 items.push_back (CheckMenuElem(*post_fader_mute_check));
1458 post_fader_mute_check->show_all();
1460 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1461 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1462 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1463 items.push_back (CheckMenuElem(*listen_mute_check));
1464 listen_mute_check->show_all();
1466 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1467 init_mute_menu(MuteMaster::Main, main_mute_check);
1468 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1469 items.push_back (CheckMenuElem(*main_mute_check));
1470 main_mute_check->show_all();
1472 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1476 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1478 check->set_active (_route->mute_control()->mute_points() & mp);
1482 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1484 if (check->get_active()) {
1485 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1487 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1492 RouteUI::muting_change ()
1494 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1497 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1499 yn = (current & MuteMaster::PreFader);
1501 if (pre_fader_mute_check->get_active() != yn) {
1502 pre_fader_mute_check->set_active (yn);
1505 yn = (current & MuteMaster::PostFader);
1507 if (post_fader_mute_check->get_active() != yn) {
1508 post_fader_mute_check->set_active (yn);
1511 yn = (current & MuteMaster::Listen);
1513 if (listen_mute_check->get_active() != yn) {
1514 listen_mute_check->set_active (yn);
1517 yn = (current & MuteMaster::Main);
1519 if (main_mute_check->get_active() != yn) {
1520 main_mute_check->set_active (yn);
1525 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1527 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1531 bool view = solo_isolated_led->active_state();
1532 bool model = _route->solo_isolate_control()->solo_isolated();
1534 /* called BEFORE the view has changed */
1536 if (ev->button == 1) {
1537 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1540 /* disable isolate for all routes */
1541 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1543 /* enable isolate for all routes */
1544 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1549 if (model == view) {
1551 /* flip just this route */
1553 boost::shared_ptr<RouteList> rl (new RouteList);
1554 rl->push_back (_route);
1555 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1564 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1566 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1570 bool view = solo_safe_led->active_state();
1571 bool model = _route->solo_safe_control()->solo_safe();
1573 if (ev->button == 1) {
1574 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1575 boost::shared_ptr<RouteList> rl (_session->get_routes());
1577 /* disable solo safe for all routes */
1578 DisplaySuspender ds;
1579 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1580 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1583 /* enable solo safe for all routes */
1584 DisplaySuspender ds;
1585 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1586 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1591 if (model == view) {
1592 /* flip just this route */
1593 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1602 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1604 bool view = check->get_active();
1605 bool model = _route->solo_isolate_control()->solo_isolated();
1607 /* called AFTER the view has changed */
1609 if (model != view) {
1610 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1615 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1617 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1621 RouteUI::delete_patch_change_dialog ()
1626 delete _route->patch_selector_dialog ();
1627 _route->set_patch_selector_dialog (0);
1630 PatchChangeGridDialog*
1631 RouteUI::patch_change_dialog () const
1633 return _route->patch_selector_dialog ();
1637 RouteUI::select_midi_patch ()
1639 if (patch_change_dialog ()) {
1640 patch_change_dialog()->present ();
1644 /* note: RouteTimeAxisView is resoponsible to updating
1645 * the Dialog (PatchChangeGridDialog::refresh())
1646 * when the midnam model changes.
1648 PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1649 _route->set_patch_selector_dialog (d);
1653 /** Ask the user to choose a colour, and then apply that color to my route */
1655 RouteUI::choose_color ()
1657 _color_picker.popup (_route);
1660 /** Set the route's own color. This may not be used for display if
1661 * the route is in a group which shares its color with its routes.
1664 RouteUI::set_color (uint32_t c)
1666 _route->presentation_info().set_color (c);
1669 /** @return GUI state ID for things that are common to the route in all its representations */
1671 RouteUI::route_state_id () const
1673 return string_compose (X_("route %1"), _route->id().to_s());
1677 RouteUI::set_color_from_route ()
1679 if (_route->presentation_info().color_set()) {
1680 return 0; /* nothing to do */
1683 return 1; /* pick a color */
1686 /** @return true if this name should be used for the route, otherwise false */
1688 RouteUI::verify_new_route_name (const std::string& name)
1690 if (name.find (':') == string::npos) {
1694 MessageDialog colon_msg (
1695 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1696 false, MESSAGE_QUESTION, BUTTONS_NONE
1699 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1700 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1702 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1706 RouteUI::route_rename ()
1708 ArdourWidgets::Prompter name_prompter (true);
1713 name_prompter.set_title (_("Rename Track"));
1715 name_prompter.set_title (_("Rename Bus"));
1717 name_prompter.set_prompt (_("New name:"));
1718 name_prompter.set_initial_text (_route->name());
1719 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1720 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1721 name_prompter.show_all ();
1724 switch (name_prompter.run ()) {
1725 case Gtk::RESPONSE_ACCEPT:
1726 name_prompter.get_result (result);
1727 name_prompter.hide ();
1728 if (result.length()) {
1729 if (verify_new_route_name (result)) {
1730 _route->set_name (result);
1733 /* back to name prompter */
1737 /* nothing entered, just get out of here */
1752 RouteUI::toggle_comment_editor ()
1754 // if (ignore_toggle) {
1758 if (comment_window && comment_window->is_visible ()) {
1759 comment_window->hide ();
1761 open_comment_editor ();
1767 RouteUI::open_comment_editor ()
1769 if (comment_window == 0) {
1770 setup_comment_editor ();
1774 title = _route->name();
1775 title += _(": comment editor");
1777 comment_window->set_title (title);
1778 comment_window->present();
1782 RouteUI::setup_comment_editor ()
1784 comment_window = new ArdourWindow (""); // title will be reset to show route
1785 comment_window->set_skip_taskbar_hint (true);
1786 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1787 comment_window->set_default_size (400, 200);
1789 comment_area = manage (new TextView());
1790 comment_area->set_name ("MixerTrackCommentArea");
1791 comment_area->set_wrap_mode (WRAP_WORD);
1792 comment_area->set_editable (true);
1793 comment_area->get_buffer()->set_text (_route->comment());
1794 comment_area->show ();
1796 comment_window->add (*comment_area);
1800 RouteUI::comment_changed ()
1802 ignore_comment_edit = true;
1804 comment_area->get_buffer()->set_text (_route->comment());
1806 ignore_comment_edit = false;
1810 RouteUI::comment_editor_done_editing ()
1812 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1814 string const str = comment_area->get_buffer()->get_text();
1815 if (str == _route->comment ()) {
1819 _route->set_comment (str, this);
1823 RouteUI::set_route_active (bool a, bool apply_to_selection)
1825 if (apply_to_selection) {
1826 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1828 _route->set_active (a, this);
1833 RouteUI::duplicate_selected_routes ()
1835 ARDOUR_UI::instance()->start_duplicate_routes();
1839 RouteUI::toggle_denormal_protection ()
1841 if (denormal_menu_item) {
1845 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1847 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1848 _route->set_denormal_protection (x);
1854 RouteUI::denormal_protection_changed ()
1856 if (denormal_menu_item) {
1857 denormal_menu_item->set_active (_route->denormal_protection());
1862 RouteUI::disconnect_input ()
1864 _route->input()->disconnect (this);
1868 RouteUI::disconnect_output ()
1870 _route->output()->disconnect (this);
1874 RouteUI::is_track () const
1876 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1879 boost::shared_ptr<Track>
1880 RouteUI::track() const
1882 return boost::dynamic_pointer_cast<Track>(_route);
1886 RouteUI::is_audio_track () const
1888 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1891 boost::shared_ptr<AudioTrack>
1892 RouteUI::audio_track() const
1894 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1898 RouteUI::is_midi_track () const
1900 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1903 boost::shared_ptr<MidiTrack>
1904 RouteUI::midi_track() const
1906 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1910 RouteUI::has_audio_outputs () const
1912 return (_route->n_outputs().n_audio() > 0);
1916 RouteUI::map_frozen ()
1918 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1920 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1923 check_rec_enable_sensitivity ();
1928 RouteUI::adjust_latency ()
1930 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1935 RouteUI::save_as_template_dialog_response (int response, SaveTemplateDialog* d)
1937 if (response == RESPONSE_ACCEPT) {
1938 const string name = d->get_template_name ();
1939 const string desc = d->get_description ();
1940 const string path = Glib::build_filename(ARDOUR::user_route_template_directory (), name + ARDOUR::template_suffix);
1942 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { /* file already exists. */
1943 bool overwrite = overwrite_file_dialog (*d,
1944 _("Confirm Template Overwrite"),
1945 _("A template already exists with that name. Do you want to overwrite it?"));
1952 _route->save_as_template (path, name, desc);
1959 RouteUI::save_as_template ()
1961 const std::string dir = ARDOUR::user_route_template_directory ();
1963 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1964 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1968 SaveTemplateDialog* d = new SaveTemplateDialog (_route->name(), _route->comment());
1969 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::save_as_template_dialog_response), d));
1974 RouteUI::check_rec_enable_sensitivity ()
1976 if (!rec_enable_button) {
1977 assert (0); // This should not happen
1980 if (!_session->writable()) {
1981 rec_enable_button->set_sensitive (false);
1985 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1986 rec_enable_button->set_sensitive (false);
1987 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1988 rec_enable_button->set_sensitive (false);
1990 rec_enable_button->set_sensitive (true);
1992 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1993 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1995 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1997 update_monitoring_display ();
2001 RouteUI::parameter_changed (string const & p)
2003 /* this handles RC and per-session parameter changes */
2005 if (p == "disable-disarm-during-roll") {
2006 check_rec_enable_sensitivity ();
2007 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2008 set_button_names ();
2009 } else if (p == "session-monitoring") {
2010 update_monitoring_display ();
2011 } else if (p == "auto-input") {
2012 update_monitoring_display ();
2013 } else if (p == "blink-rec-arm") {
2014 if (UIConfiguration::instance().get_blink_rec_arm()) {
2015 rec_blink_connection.disconnect ();
2016 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2018 rec_blink_connection.disconnect ();
2019 RouteUI::blink_rec_display(false);
2025 RouteUI::setup_invert_buttons ()
2027 /* remove old invert buttons */
2028 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2029 _invert_button_box.remove (**i);
2032 _invert_buttons.clear ();
2034 if (!_route || !_route->input()) {
2038 uint32_t const N = _route->input()->n_ports().n_audio ();
2040 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2042 for (uint32_t i = 0; i < to_add; ++i) {
2043 ArdourButton* b = manage (new ArdourButton);
2044 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2045 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2047 b->set_name (X_("invert button"));
2050 b->set_text (string_compose (X_("Ø (%1)"), N));
2052 b->set_text (X_("Ø"));
2055 b->set_text (string_compose (X_("Ø%1"), i + 1));
2058 if (N <= _max_invert_buttons) {
2059 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));
2061 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2064 _invert_buttons.push_back (b);
2065 _invert_button_box.pack_start (*b);
2068 _invert_button_box.set_spacing (1);
2069 _invert_button_box.show_all ();
2073 RouteUI::set_invert_button_state ()
2075 uint32_t const N = _route->input()->n_ports().n_audio();
2076 if (N > _max_invert_buttons) {
2078 /* One button for many channels; explicit active if all channels are inverted,
2079 implicit active if some are, off if none are.
2082 ArdourButton* b = _invert_buttons.front ();
2084 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2085 b->set_active_state (Gtkmm2ext::ExplicitActive);
2086 } else if (_route->phase_control()->any()) {
2087 b->set_active_state (Gtkmm2ext::ImplicitActive);
2089 b->set_active_state (Gtkmm2ext::Off);
2094 /* One button per channel; just set active */
2097 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2098 (*i)->set_active (_route->phase_control()->inverted (j));
2105 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2107 if (ev->button == 1 && i < _invert_buttons.size()) {
2108 uint32_t const N = _route->input()->n_ports().n_audio ();
2109 if (N <= _max_invert_buttons) {
2110 /* left-click inverts phase so long as we have a button per channel */
2111 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2120 RouteUI::invert_press (GdkEventButton* ev)
2122 using namespace Menu_Helpers;
2124 uint32_t const N = _route->input()->n_ports().n_audio();
2125 if (N <= _max_invert_buttons && ev->button != 3) {
2126 /* If we have an invert button per channel, we only pop
2127 up a menu on right-click; left click is handled
2133 delete _invert_menu;
2134 _invert_menu = new Menu;
2135 _invert_menu->set_name ("ArdourContextMenu");
2136 MenuList& items = _invert_menu->items ();
2138 for (uint32_t i = 0; i < N; ++i) {
2139 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2140 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2141 ++_i_am_the_modifier;
2142 e->set_active (_route->phase_control()->inverted (i));
2143 --_i_am_the_modifier;
2146 _invert_menu->popup (0, ev->time);
2152 RouteUI::invert_menu_toggled (uint32_t c)
2154 if (_i_am_the_modifier) {
2159 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2163 RouteUI::set_invert_sensitive (bool yn)
2165 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2166 (*b)->set_sensitive (yn);
2170 /** The Route's gui_changed signal has been emitted */
2172 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2174 if (what_changed.contains (Properties::color)) {
2175 if (set_color_from_route () == 0) {
2176 route_color_changed ();
2182 RouteUI::track_mode_changed (void)
2185 switch (track()->mode()) {
2186 case ARDOUR::NonLayered:
2187 case ARDOUR::Normal:
2188 rec_enable_button->set_icon (ArdourIcon::RecButton);
2190 case ARDOUR::Destructive:
2191 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2194 rec_enable_button->queue_draw();
2197 /** @return the color that this route should use; it maybe its own,
2198 * or it maybe that of its route group.
2201 RouteUI::route_color () const
2204 RouteGroup* g = _route->route_group ();
2207 if (g && g->is_color()) {
2208 set_color_from_rgba (c, GroupTabs::group_color (g));
2210 set_color_from_rgba (c, _route->presentation_info().color());
2217 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2219 _showing_sends_to = send_to;
2220 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2224 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2226 if (_route == send_to) {
2227 show_sends_button->set_active (true);
2228 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2230 show_sends_button->set_active (false);
2231 send_blink_connection.disconnect ();
2236 RouteUI::route_group() const
2238 return _route->route_group();
2242 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2243 : WM::ProxyBase (name, string())
2244 , _route (boost::weak_ptr<Route> (route))
2246 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2249 RoutePinWindowProxy::~RoutePinWindowProxy()
2254 ARDOUR::SessionHandlePtr*
2255 RoutePinWindowProxy::session_handle ()
2257 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2258 if (aw) { return aw; }
2263 RoutePinWindowProxy::get (bool create)
2265 boost::shared_ptr<Route> r = _route.lock ();
2274 _window = new PluginPinDialog (r);
2275 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2277 aw->set_session (_session);
2279 _window->show_all ();
2285 RoutePinWindowProxy::route_going_away ()
2289 WM::Manager::instance().remove (this);
2290 going_away_connection.disconnect();
2295 RouteUI::maybe_add_route_print_mgr ()
2297 if (_route->pinmgr_proxy ()) {
2300 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2301 string_compose ("RPM-%1", _route->id()), _route);
2302 wp->set_session (_session);
2304 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2306 wp->set_state (*ui_xml, 0);
2310 void* existing_ui = _route->pinmgr_proxy ();
2312 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2315 _route->set_pingmgr_proxy (wp);
2317 WM::Manager::instance().register_window (wp);
2321 RouteUI::manage_pins ()
2323 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2331 RouteUI::fan_out (bool to_busses, bool group)
2333 DisplaySuspender ds;
2334 boost::shared_ptr<ARDOUR::Route> route = _route;
2335 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2338 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2339 if (route->n_outputs ().n_audio () != n_outputs) {
2340 MessageDialog msg (string_compose (
2341 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2342 n_outputs, route->n_outputs ().n_audio ()));
2347 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2349 /* count busses and channels/bus */
2350 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2351 std::map<std::string, uint32_t> busnames;
2352 for (uint32_t p = 0; p < n_outputs; ++p) {
2353 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2354 std::string bn = BUSNAME;
2358 if (busnames.size () < 2) {
2359 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2364 uint32_t outputs = 2;
2365 if (_session->master_out ()) {
2366 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2369 route->output ()->disconnect (this);
2370 route->panner_shell ()->set_bypassed (true);
2373 for (uint32_t p = 0; p < n_outputs; ++p) {
2374 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2375 std::string bn = BUSNAME;
2376 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2379 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2383 list<boost::shared_ptr<AudioTrack> > tl =
2384 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2388 boost::shared_ptr<ControlList> cl (new ControlList);
2389 cl->push_back (r->monitoring_control ());
2390 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2392 r->input ()->disconnect (this);
2394 to_group.push_back (r);
2395 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2400 RouteGroup* rg = NULL;
2401 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2402 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2403 if ((*i)->name () == pi->name ()) {
2409 rg = new RouteGroup (*_session, pi->name ());
2410 _session->add_route_group (rg);
2411 rg->set_gain (false);
2414 GroupTabs::set_group_color (rg, route->presentation_info().color());
2415 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2422 RouteUI::mark_hidden (bool yn)
2424 if (yn != _route->presentation_info().hidden()) {
2425 _route->presentation_info().set_hidden (yn);
2426 return true; // things changed
2431 boost::shared_ptr<Stripable>
2432 RouteUI::stripable () const