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 (!_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 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
910 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
912 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() | monitor_choice);
915 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
916 /* Primary-Tertiary-click applies change to all routes */
917 rl = _session->get_routes ();
918 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::NoGroup);
919 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
920 /* Primary-click overrides group */
921 rl.reset (new RouteList);
922 rl->push_back (route());
923 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::InverseGroup);
925 rl.reset (new RouteList);
926 rl->push_back (route());
927 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
934 RouteUI::build_record_menu ()
937 record_menu = new Menu;
938 record_menu->set_name ("ArdourContextMenu");
939 using namespace Menu_Helpers;
940 MenuList& items = record_menu->items();
942 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
943 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
945 if (is_midi_track()) {
946 items.push_back (SeparatorElem());
947 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
948 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
952 if (step_edit_item) {
953 if (track()->rec_enable_control()->get_value()) {
954 step_edit_item->set_sensitive (false);
956 step_edit_item->set_active (midi_track()->step_editing());
959 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
960 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
965 RouteUI::toggle_step_edit ()
967 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
971 midi_track()->set_step_editing (step_edit_item->get_active());
975 RouteUI::toggle_rec_safe ()
977 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
983 /* This check is made inside the control too, but dong it here can't
987 if (_route->rec_enable_control()->get_value()) {
991 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
995 RouteUI::step_edit_changed (bool yn)
998 if (rec_enable_button) {
999 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1002 start_step_editing ();
1004 if (step_edit_item) {
1005 step_edit_item->set_active (true);
1010 if (rec_enable_button) {
1011 rec_enable_button->unset_active_state ();
1014 stop_step_editing ();
1016 if (step_edit_item) {
1017 step_edit_item->set_active (false);
1023 RouteUI::rec_enable_release (GdkEventButton* ev)
1025 if (Keyboard::is_context_menu_event (ev)) {
1026 build_record_menu ();
1028 record_menu->popup (1, ev->time);
1037 RouteUI::build_sends_menu ()
1039 using namespace Menu_Helpers;
1041 sends_menu = new Menu;
1042 sends_menu->set_name ("ArdourContextMenu");
1043 MenuList& items = sends_menu->items();
1046 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
1050 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1054 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1058 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1062 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1066 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1069 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1073 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1076 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1077 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1078 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1083 RouteUI::create_sends (Placement p, bool include_buses)
1085 _session->globally_add_internal_sends (_route, p, include_buses);
1089 RouteUI::create_selected_sends (Placement p, bool include_buses)
1091 boost::shared_ptr<RouteList> rlist (new RouteList);
1092 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1094 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1095 RouteTimeAxisView* rtv;
1097 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1098 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1099 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1100 rlist->push_back (rui->route());
1106 _session->add_internal_sends (_route, p, rlist);
1110 RouteUI::set_sends_gain_from_track ()
1112 _session->globally_set_send_gains_from_track (_route);
1116 RouteUI::set_sends_gain_to_zero ()
1118 _session->globally_set_send_gains_to_zero (_route);
1122 RouteUI::set_sends_gain_to_unity ()
1124 _session->globally_set_send_gains_to_unity (_route);
1128 RouteUI::show_sends_press(GdkEventButton* ev)
1130 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1134 if (!is_track() && show_sends_button) {
1136 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1138 // do nothing on midi sigc::bind event
1141 } else if (Keyboard::is_context_menu_event (ev)) {
1143 if (sends_menu == 0) {
1144 build_sends_menu ();
1147 sends_menu->popup (0, ev->time);
1151 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1154 set_showing_sends_to (boost::shared_ptr<Route> ());
1156 set_showing_sends_to (_route);
1165 RouteUI::show_sends_release (GdkEventButton*)
1171 RouteUI::send_blink (bool onoff)
1173 if (!show_sends_button) {
1178 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1180 show_sends_button->unset_active_state ();
1184 Gtkmm2ext::ActiveState
1185 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1187 boost::shared_ptr<SoloControl> sc = s->solo_control();
1190 return Gtkmm2ext::Off;
1193 if (!sc->can_solo()) {
1194 return Gtkmm2ext::Off;
1198 if (sc->self_soloed()) {
1199 return Gtkmm2ext::ExplicitActive;
1200 } else if (sc->soloed_by_others()) {
1201 return Gtkmm2ext::ImplicitActive;
1203 return Gtkmm2ext::Off;
1207 Gtkmm2ext::ActiveState
1208 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1210 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1213 return Gtkmm2ext::Off;
1216 if (s->is_master() || s->is_monitor()) {
1217 return Gtkmm2ext::Off;
1220 if (sc->solo_isolated()) {
1221 return Gtkmm2ext::ExplicitActive;
1223 return Gtkmm2ext::Off;
1227 Gtkmm2ext::ActiveState
1228 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1230 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1233 return Gtkmm2ext::Off;
1236 if (s->is_master() || s->is_monitor()) {
1237 return Gtkmm2ext::Off;
1240 if (sc->solo_safe()) {
1241 return Gtkmm2ext::ExplicitActive;
1243 return Gtkmm2ext::Off;
1248 RouteUI::update_solo_display ()
1250 bool yn = _route->solo_safe_control()->solo_safe ();
1252 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1253 solo_safe_check->set_active (yn);
1256 yn = _route->solo_isolate_control()->solo_isolated ();
1258 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1259 solo_isolated_check->set_active (yn);
1262 set_button_names ();
1264 if (solo_isolated_led) {
1265 if (_route->solo_isolate_control()->solo_isolated()) {
1266 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1268 solo_isolated_led->unset_active_state ();
1272 if (solo_safe_led) {
1273 if (_route->solo_safe_control()->solo_safe()) {
1274 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1276 solo_safe_led->unset_active_state ();
1280 solo_button->set_active_state (solo_active_state (_route));
1282 /* some changes to solo status can affect mute display, so catch up
1285 update_mute_display ();
1289 RouteUI::solo_changed_so_update_mute ()
1291 update_mute_display ();
1295 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1297 boost::shared_ptr<MuteControl> mc = s->mute_control();
1299 if (s->is_monitor()) {
1300 return Gtkmm2ext::Off;
1304 return Gtkmm2ext::Off;
1307 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1309 if (mc->muted_by_self ()) {
1311 return Gtkmm2ext::ExplicitActive;
1312 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1313 /* this will reflect both solo mutes AND master mutes */
1314 return Gtkmm2ext::ImplicitActive;
1316 /* no mute at all */
1317 return Gtkmm2ext::Off;
1322 if (mc->muted_by_self()) {
1324 return Gtkmm2ext::ExplicitActive;
1325 } else if (mc->muted_by_masters ()) {
1326 /* this shows only master mutes, not mute-by-others-soloing */
1327 return Gtkmm2ext::ImplicitActive;
1329 /* no mute at all */
1330 return Gtkmm2ext::Off;
1334 return ActiveState(0);
1338 RouteUI::update_mute_display ()
1344 mute_button->set_active_state (mute_active_state (_session, _route));
1349 RouteUI::route_rec_enable_changed ()
1351 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1355 RouteUI::session_rec_enable_changed ()
1357 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1361 RouteUI::blink_rec_display (bool blinkOn)
1363 if (!rec_enable_button || !_route) {
1367 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1375 if (track()->rec_enable_control()->get_value()) {
1376 switch (_session->record_status ()) {
1377 case Session::Recording:
1378 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1381 case Session::Disabled:
1382 case Session::Enabled:
1383 if (UIConfiguration::instance().get_blink_rec_arm()) {
1384 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1386 rec_enable_button->set_active_state ( ImplicitActive );
1391 if (step_edit_item) {
1392 step_edit_item->set_sensitive (false);
1396 rec_enable_button->unset_active_state ();
1398 if (step_edit_item) {
1399 step_edit_item->set_sensitive (true);
1403 check_rec_enable_sensitivity ();
1407 RouteUI::build_solo_menu (void)
1409 using namespace Menu_Helpers;
1411 solo_menu = new Menu;
1412 solo_menu->set_name ("ArdourContextMenu");
1413 MenuList& items = solo_menu->items();
1414 Gtk::CheckMenuItem* check;
1416 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1417 check->set_active (_route->solo_isolate_control()->solo_isolated());
1418 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1419 items.push_back (CheckMenuElem(*check));
1420 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1423 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1424 check->set_active (_route->solo_safe_control()->solo_safe());
1425 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1426 items.push_back (CheckMenuElem(*check));
1427 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1432 RouteUI::build_mute_menu(void)
1434 using namespace Menu_Helpers;
1436 mute_menu = new Menu;
1437 mute_menu->set_name ("ArdourContextMenu");
1439 MenuList& items = mute_menu->items();
1441 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1442 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1443 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1444 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1445 pre_fader_mute_check->show_all();
1447 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1448 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1449 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1450 items.push_back (CheckMenuElem(*post_fader_mute_check));
1451 post_fader_mute_check->show_all();
1453 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1454 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1455 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1456 items.push_back (CheckMenuElem(*listen_mute_check));
1457 listen_mute_check->show_all();
1459 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1460 init_mute_menu(MuteMaster::Main, main_mute_check);
1461 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1462 items.push_back (CheckMenuElem(*main_mute_check));
1463 main_mute_check->show_all();
1465 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1469 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1471 check->set_active (_route->mute_control()->mute_points() & mp);
1475 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1477 if (check->get_active()) {
1478 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1480 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1485 RouteUI::muting_change ()
1487 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1490 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1492 yn = (current & MuteMaster::PreFader);
1494 if (pre_fader_mute_check->get_active() != yn) {
1495 pre_fader_mute_check->set_active (yn);
1498 yn = (current & MuteMaster::PostFader);
1500 if (post_fader_mute_check->get_active() != yn) {
1501 post_fader_mute_check->set_active (yn);
1504 yn = (current & MuteMaster::Listen);
1506 if (listen_mute_check->get_active() != yn) {
1507 listen_mute_check->set_active (yn);
1510 yn = (current & MuteMaster::Main);
1512 if (main_mute_check->get_active() != yn) {
1513 main_mute_check->set_active (yn);
1518 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1520 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1524 bool view = solo_isolated_led->active_state();
1525 bool model = _route->solo_isolate_control()->solo_isolated();
1527 /* called BEFORE the view has changed */
1529 if (ev->button == 1) {
1530 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1533 /* disable isolate for all routes */
1534 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1536 /* enable isolate for all routes */
1537 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1542 if (model == view) {
1544 /* flip just this route */
1546 boost::shared_ptr<RouteList> rl (new RouteList);
1547 rl->push_back (_route);
1548 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1557 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1559 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1563 bool view = solo_safe_led->active_state();
1564 bool model = _route->solo_safe_control()->solo_safe();
1566 if (ev->button == 1) {
1567 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1568 boost::shared_ptr<RouteList> rl (_session->get_routes());
1570 /* disable solo safe for all routes */
1571 DisplaySuspender ds;
1572 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1573 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1576 /* enable solo safe for all routes */
1577 DisplaySuspender ds;
1578 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1579 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1584 if (model == view) {
1585 /* flip just this route */
1586 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1595 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1597 bool view = check->get_active();
1598 bool model = _route->solo_isolate_control()->solo_isolated();
1600 /* called AFTER the view has changed */
1602 if (model != view) {
1603 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1608 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1610 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1614 RouteUI::delete_patch_change_dialog ()
1619 delete _route->patch_selector_dialog ();
1620 _route->set_patch_selector_dialog (0);
1623 PatchChangeGridDialog*
1624 RouteUI::patch_change_dialog () const
1626 return _route->patch_selector_dialog ();
1630 RouteUI::select_midi_patch ()
1632 if (patch_change_dialog ()) {
1633 patch_change_dialog()->present ();
1637 /* note: RouteTimeAxisView is resoponsible to updating
1638 * the Dialog (PatchChangeGridDialog::refresh())
1639 * when the midnam model changes.
1641 PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1642 _route->set_patch_selector_dialog (d);
1646 /** Ask the user to choose a colour, and then apply that color to my route */
1648 RouteUI::choose_color ()
1650 _color_picker.popup (_route);
1653 /** Set the route's own color. This may not be used for display if
1654 * the route is in a group which shares its color with its routes.
1657 RouteUI::set_color (uint32_t c)
1659 _route->presentation_info().set_color (c);
1662 /** @return GUI state ID for things that are common to the route in all its representations */
1664 RouteUI::route_state_id () const
1666 return string_compose (X_("route %1"), _route->id().to_s());
1670 RouteUI::set_color_from_route ()
1672 if (_route->presentation_info().color_set()) {
1673 return 0; /* nothing to do */
1676 return 1; /* pick a color */
1679 /** @return true if this name should be used for the route, otherwise false */
1681 RouteUI::verify_new_route_name (const std::string& name)
1683 if (name.find (':') == string::npos) {
1687 MessageDialog colon_msg (
1688 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1689 false, MESSAGE_QUESTION, BUTTONS_NONE
1692 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1693 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1695 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1699 RouteUI::route_rename ()
1701 ArdourWidgets::Prompter name_prompter (true);
1706 name_prompter.set_title (_("Rename Track"));
1708 name_prompter.set_title (_("Rename Bus"));
1710 name_prompter.set_prompt (_("New name:"));
1711 name_prompter.set_initial_text (_route->name());
1712 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1713 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1714 name_prompter.show_all ();
1717 switch (name_prompter.run ()) {
1718 case Gtk::RESPONSE_ACCEPT:
1719 name_prompter.get_result (result);
1720 name_prompter.hide ();
1721 if (result.length()) {
1722 if (verify_new_route_name (result)) {
1723 _route->set_name (result);
1726 /* back to name prompter */
1730 /* nothing entered, just get out of here */
1745 RouteUI::toggle_comment_editor ()
1747 // if (ignore_toggle) {
1751 if (comment_window && comment_window->is_visible ()) {
1752 comment_window->hide ();
1754 open_comment_editor ();
1760 RouteUI::open_comment_editor ()
1762 if (comment_window == 0) {
1763 setup_comment_editor ();
1767 title = _route->name();
1768 title += _(": comment editor");
1770 comment_window->set_title (title);
1771 comment_window->present();
1775 RouteUI::setup_comment_editor ()
1777 comment_window = new ArdourWindow (""); // title will be reset to show route
1778 comment_window->set_skip_taskbar_hint (true);
1779 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1780 comment_window->set_default_size (400, 200);
1782 comment_area = manage (new TextView());
1783 comment_area->set_name ("MixerTrackCommentArea");
1784 comment_area->set_wrap_mode (WRAP_WORD);
1785 comment_area->set_editable (true);
1786 comment_area->get_buffer()->set_text (_route->comment());
1787 comment_area->show ();
1789 comment_window->add (*comment_area);
1793 RouteUI::comment_changed ()
1795 ignore_comment_edit = true;
1797 comment_area->get_buffer()->set_text (_route->comment());
1799 ignore_comment_edit = false;
1803 RouteUI::comment_editor_done_editing ()
1805 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1807 string const str = comment_area->get_buffer()->get_text();
1808 if (str == _route->comment ()) {
1812 _route->set_comment (str, this);
1816 RouteUI::set_route_active (bool a, bool apply_to_selection)
1818 if (apply_to_selection) {
1819 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1821 _route->set_active (a, this);
1826 RouteUI::duplicate_selected_routes ()
1828 ARDOUR_UI::instance()->start_duplicate_routes();
1832 RouteUI::toggle_denormal_protection ()
1834 if (denormal_menu_item) {
1838 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1840 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1841 _route->set_denormal_protection (x);
1847 RouteUI::denormal_protection_changed ()
1849 if (denormal_menu_item) {
1850 denormal_menu_item->set_active (_route->denormal_protection());
1855 RouteUI::disconnect_input ()
1857 _route->input()->disconnect (this);
1861 RouteUI::disconnect_output ()
1863 _route->output()->disconnect (this);
1867 RouteUI::is_track () const
1869 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1872 boost::shared_ptr<Track>
1873 RouteUI::track() const
1875 return boost::dynamic_pointer_cast<Track>(_route);
1879 RouteUI::is_audio_track () const
1881 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1884 boost::shared_ptr<AudioTrack>
1885 RouteUI::audio_track() const
1887 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1891 RouteUI::is_midi_track () const
1893 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1896 boost::shared_ptr<MidiTrack>
1897 RouteUI::midi_track() const
1899 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1903 RouteUI::has_audio_outputs () const
1905 return (_route->n_outputs().n_audio() > 0);
1909 RouteUI::map_frozen ()
1911 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1913 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1916 check_rec_enable_sensitivity ();
1921 RouteUI::adjust_latency ()
1923 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->sample_rate(), AudioEngine::instance()->samples_per_cycle());
1928 RouteUI::save_as_template_dialog_response (int response, SaveTemplateDialog* d)
1930 if (response == RESPONSE_ACCEPT) {
1931 const string name = d->get_template_name ();
1932 const string desc = d->get_description ();
1933 const string path = Glib::build_filename(ARDOUR::user_route_template_directory (), name + ARDOUR::template_suffix);
1935 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { /* file already exists. */
1936 bool overwrite = overwrite_file_dialog (*d,
1937 _("Confirm Template Overwrite"),
1938 _("A template already exists with that name. Do you want to overwrite it?"));
1945 _route->save_as_template (path, name, desc);
1952 RouteUI::save_as_template ()
1954 const std::string dir = ARDOUR::user_route_template_directory ();
1956 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1957 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1961 SaveTemplateDialog* d = new SaveTemplateDialog (_route->name(), _route->comment());
1962 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::save_as_template_dialog_response), d));
1967 RouteUI::check_rec_enable_sensitivity ()
1969 if (!rec_enable_button) {
1970 assert (0); // This should not happen
1973 if (!_session->writable()) {
1974 rec_enable_button->set_sensitive (false);
1978 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1979 rec_enable_button->set_sensitive (false);
1980 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1981 rec_enable_button->set_sensitive (false);
1983 rec_enable_button->set_sensitive (true);
1985 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1986 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1988 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1990 update_monitoring_display ();
1994 RouteUI::parameter_changed (string const & p)
1996 /* this handles RC and per-session parameter changes */
1998 if (p == "disable-disarm-during-roll") {
1999 check_rec_enable_sensitivity ();
2000 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2001 set_button_names ();
2002 } else if (p == "session-monitoring") {
2003 update_monitoring_display ();
2004 } else if (p == "auto-input") {
2005 update_monitoring_display ();
2006 } else if (p == "blink-rec-arm") {
2007 if (UIConfiguration::instance().get_blink_rec_arm()) {
2008 rec_blink_connection.disconnect ();
2009 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2011 rec_blink_connection.disconnect ();
2012 RouteUI::blink_rec_display(false);
2018 RouteUI::setup_invert_buttons ()
2020 /* remove old invert buttons */
2021 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2022 _invert_button_box.remove (**i);
2025 _invert_buttons.clear ();
2027 if (!_route || !_route->input()) {
2031 uint32_t const N = _route->input()->n_ports().n_audio ();
2033 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2035 for (uint32_t i = 0; i < to_add; ++i) {
2036 ArdourButton* b = manage (new ArdourButton);
2037 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2038 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2040 b->set_name (X_("invert button"));
2043 b->set_text (string_compose (X_("Ø (%1)"), N));
2045 b->set_text (X_("Ø"));
2048 b->set_text (string_compose (X_("Ø%1"), i + 1));
2051 if (N <= _max_invert_buttons) {
2052 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));
2054 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2057 _invert_buttons.push_back (b);
2058 _invert_button_box.pack_start (*b);
2061 _invert_button_box.set_spacing (1);
2062 _invert_button_box.show_all ();
2066 RouteUI::set_invert_button_state ()
2068 uint32_t const N = _route->input()->n_ports().n_audio();
2069 if (N > _max_invert_buttons) {
2071 /* One button for many channels; explicit active if all channels are inverted,
2072 implicit active if some are, off if none are.
2075 ArdourButton* b = _invert_buttons.front ();
2077 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2078 b->set_active_state (Gtkmm2ext::ExplicitActive);
2079 } else if (_route->phase_control()->any()) {
2080 b->set_active_state (Gtkmm2ext::ImplicitActive);
2082 b->set_active_state (Gtkmm2ext::Off);
2087 /* One button per channel; just set active */
2090 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2091 (*i)->set_active (_route->phase_control()->inverted (j));
2098 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2100 if (ev->button == 1 && i < _invert_buttons.size()) {
2101 uint32_t const N = _route->input()->n_ports().n_audio ();
2102 if (N <= _max_invert_buttons) {
2103 /* left-click inverts phase so long as we have a button per channel */
2104 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2113 RouteUI::invert_press (GdkEventButton* ev)
2115 using namespace Menu_Helpers;
2117 uint32_t const N = _route->input()->n_ports().n_audio();
2118 if (N <= _max_invert_buttons && ev->button != 3) {
2119 /* If we have an invert button per channel, we only pop
2120 up a menu on right-click; left click is handled
2126 delete _invert_menu;
2127 _invert_menu = new Menu;
2128 _invert_menu->set_name ("ArdourContextMenu");
2129 MenuList& items = _invert_menu->items ();
2131 for (uint32_t i = 0; i < N; ++i) {
2132 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2133 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2134 ++_i_am_the_modifier;
2135 e->set_active (_route->phase_control()->inverted (i));
2136 --_i_am_the_modifier;
2139 _invert_menu->popup (0, ev->time);
2145 RouteUI::invert_menu_toggled (uint32_t c)
2147 if (_i_am_the_modifier) {
2152 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2156 RouteUI::set_invert_sensitive (bool yn)
2158 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2159 (*b)->set_sensitive (yn);
2163 /** The Route's gui_changed signal has been emitted */
2165 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2167 if (what_changed.contains (Properties::color)) {
2168 if (set_color_from_route () == 0) {
2169 route_color_changed ();
2175 RouteUI::track_mode_changed (void)
2178 switch (track()->mode()) {
2179 case ARDOUR::NonLayered:
2180 case ARDOUR::Normal:
2181 rec_enable_button->set_icon (ArdourIcon::RecButton);
2183 case ARDOUR::Destructive:
2184 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2187 rec_enable_button->queue_draw();
2190 /** @return the color that this route should use; it maybe its own,
2191 * or it maybe that of its route group.
2194 RouteUI::route_color () const
2197 RouteGroup* g = _route->route_group ();
2200 if (g && g->is_color()) {
2201 set_color_from_rgba (c, GroupTabs::group_color (g));
2203 set_color_from_rgba (c, _route->presentation_info().color());
2210 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2212 _showing_sends_to = send_to;
2213 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2217 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2219 if (_route == send_to) {
2220 show_sends_button->set_active (true);
2221 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2223 show_sends_button->set_active (false);
2224 send_blink_connection.disconnect ();
2229 RouteUI::route_group() const
2231 return _route->route_group();
2235 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2236 : WM::ProxyBase (name, string())
2237 , _route (boost::weak_ptr<Route> (route))
2239 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2242 RoutePinWindowProxy::~RoutePinWindowProxy()
2247 ARDOUR::SessionHandlePtr*
2248 RoutePinWindowProxy::session_handle ()
2250 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2251 if (aw) { return aw; }
2256 RoutePinWindowProxy::get (bool create)
2258 boost::shared_ptr<Route> r = _route.lock ();
2267 _window = new PluginPinDialog (r);
2268 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2270 aw->set_session (_session);
2272 _window->show_all ();
2278 RoutePinWindowProxy::route_going_away ()
2282 WM::Manager::instance().remove (this);
2283 going_away_connection.disconnect();
2288 RouteUI::maybe_add_route_print_mgr ()
2290 if (_route->pinmgr_proxy ()) {
2293 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2294 string_compose ("RPM-%1", _route->id()), _route);
2295 wp->set_session (_session);
2297 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2299 wp->set_state (*ui_xml, 0);
2303 void* existing_ui = _route->pinmgr_proxy ();
2305 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2308 _route->set_pingmgr_proxy (wp);
2310 WM::Manager::instance().register_window (wp);
2314 RouteUI::manage_pins ()
2316 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2324 RouteUI::fan_out (bool to_busses, bool group)
2326 DisplaySuspender ds;
2327 boost::shared_ptr<ARDOUR::Route> route = _route;
2328 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2331 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2332 if (route->n_outputs ().n_audio () != n_outputs) {
2333 MessageDialog msg (string_compose (
2334 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2335 n_outputs, route->n_outputs ().n_audio ()));
2340 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2342 /* count busses and channels/bus */
2343 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2344 std::map<std::string, uint32_t> busnames;
2345 for (uint32_t p = 0; p < n_outputs; ++p) {
2346 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2347 std::string bn = BUSNAME;
2351 if (busnames.size () < 2) {
2352 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2357 uint32_t outputs = 2;
2358 if (_session->master_out ()) {
2359 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2362 route->output ()->disconnect (this);
2363 route->panner_shell ()->set_bypassed (true);
2366 for (uint32_t p = 0; p < n_outputs; ++p) {
2367 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2368 std::string bn = BUSNAME;
2369 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2372 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2376 list<boost::shared_ptr<AudioTrack> > tl =
2377 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2381 boost::shared_ptr<ControlList> cl (new ControlList);
2382 cl->push_back (r->monitoring_control ());
2383 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2385 r->input ()->disconnect (this);
2387 to_group.push_back (r);
2388 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2393 RouteGroup* rg = NULL;
2394 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2395 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2396 if ((*i)->name () == pi->name ()) {
2402 rg = new RouteGroup (*_session, pi->name ());
2403 _session->add_route_group (rg);
2404 rg->set_gain (false);
2407 GroupTabs::set_group_color (rg, route->presentation_info().color());
2408 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2415 RouteUI::mark_hidden (bool yn)
2417 if (yn != _route->presentation_info().hidden()) {
2418 _route->presentation_info().set_hidden (yn);
2419 return true; // things changed
2424 boost::shared_ptr<Stripable>
2425 RouteUI::stripable () const
2431 RouteUI::set_disk_io_point (DiskIOPoint diop)
2433 if (_route && is_track()) {
2434 track()->set_disk_io_point (diop);