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.
20 #include <boost/algorithm/string.hpp>
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
30 #include "ardour/route_group.h"
31 #include "ardour/dB.h"
32 #include "pbd/memento_command.h"
33 #include "pbd/stacktrace.h"
34 #include "pbd/controllable.h"
35 #include "pbd/enumwriter.h"
37 #include "ardour_ui.h"
40 #include "ardour_button.h"
44 #include "gui_thread.h"
45 #include "ardour_dialog.h"
46 #include "latency_gui.h"
47 #include "mixer_strip.h"
48 #include "automation_time_axis.h"
49 #include "route_time_axis.h"
50 #include "group_tabs.h"
52 #include "ui_config.h"
54 #include "ardour/audio_track.h"
55 #include "ardour/audioengine.h"
56 #include "ardour/filename_extensions.h"
57 #include "ardour/midi_track.h"
58 #include "ardour/internal_send.h"
59 #include "ardour/profile.h"
60 #include "ardour/send.h"
61 #include "ardour/route.h"
62 #include "ardour/session.h"
63 #include "ardour/template_utils.h"
67 using namespace Gtkmm2ext;
68 using namespace ARDOUR;
69 using namespace ARDOUR_UI_UTILS;
73 uint32_t RouteUI::_max_invert_buttons = 3;
74 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
75 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
76 std::string RouteUI::program_port_prefix;
78 RouteUI::RouteUI (ARDOUR::Session* sess)
90 if (program_port_prefix.empty()) {
91 // compare to gtk2_ardour/port_group.cc
92 string lpn (PROGRAM_NAME);
93 boost::to_lower (lpn);
94 program_port_prefix = lpn + ":"; // e.g. "ardour:"
102 gui_object_state().remove_node (route_state_id());
105 _route.reset (); /* drop reference to route, so that it can be cleaned up */
106 route_connections.drop_connections ();
112 delete comment_window;
113 delete input_selector;
114 delete output_selector;
117 send_blink_connection.disconnect ();
118 rec_blink_connection.disconnect ();
124 self_destruct = true;
130 pre_fader_mute_check = 0;
131 post_fader_mute_check = 0;
132 listen_mute_check = 0;
135 solo_isolated_check = 0;
136 solo_isolated_led = 0;
140 denormal_menu_item = 0;
142 multiple_mute_change = false;
143 multiple_solo_change = false;
144 _i_am_the_modifier = 0;
149 setup_invert_buttons ();
151 mute_button = manage (new ArdourButton);
152 mute_button->set_name ("mute button");
153 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
155 solo_button = manage (new ArdourButton);
156 solo_button->set_name ("solo button");
157 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
158 solo_button->set_no_show_all (true);
160 rec_enable_button = manage (new ArdourButton);
161 rec_enable_button->set_name ("record enable button");
162 rec_enable_button->set_icon (ArdourIcon::RecButton);
163 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
165 if (UIConfiguration::instance().get_blink_rec_arm()) {
166 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
169 show_sends_button = manage (new ArdourButton);
170 show_sends_button->set_name ("send alert button");
171 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
173 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
174 monitor_input_button->set_name ("monitor button");
175 monitor_input_button->set_text (_("In"));
176 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
177 monitor_input_button->set_no_show_all (true);
179 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
180 monitor_disk_button->set_name ("monitor button");
181 monitor_disk_button->set_text (_("Disk"));
182 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
183 monitor_disk_button->set_no_show_all (true);
185 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
186 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
187 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
189 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
190 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
192 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
193 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
195 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
196 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
198 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
199 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
200 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
201 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
203 monitor_input_button->set_distinct_led_click (false);
204 monitor_disk_button->set_distinct_led_click (false);
206 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
207 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
209 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
210 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
212 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
218 route_connections.drop_connections ();
226 denormal_menu_item = 0;
230 RouteUI::self_delete ()
236 RouteUI::set_route (boost::shared_ptr<Route> rp)
242 if (set_color_from_route()) {
243 set_color (unique_random_color());
247 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
250 delete input_selector;
253 delete output_selector;
256 mute_button->set_controllable (_route->mute_control());
257 solo_button->set_controllable (_route->solo_control());
259 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
260 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
262 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this, _1), gui_context());
264 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
265 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
266 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
267 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
269 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
270 track_mode_changed();
273 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
274 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
276 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
277 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
279 if (_session->writable() && is_track()) {
280 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
282 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
284 rec_enable_button->show();
285 rec_enable_button->set_controllable (t->rec_enable_control());
287 if (is_midi_track()) {
288 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
289 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
294 /* this will work for busses and tracks, and needs to be called to
295 set up the name entry/name label display.
299 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
300 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
302 update_monitoring_display ();
305 mute_button->unset_flags (Gtk::CAN_FOCUS);
306 solo_button->unset_flags (Gtk::CAN_FOCUS);
310 if (_route->is_monitor() || _route->is_master()) {
311 solo_button->hide ();
318 setup_invert_buttons ();
319 set_invert_button_state ();
321 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
322 bus_send_display_changed (s);
324 update_mute_display ();
325 update_solo_display ();
327 if (!UIConfiguration::instance().get_blink_rec_arm()) {
328 blink_rec_display(true); // set initial rec-en button state
331 route_color_changed();
335 RouteUI::polarity_changed ()
341 set_invert_button_state ();
345 RouteUI::mute_press (GdkEventButton* ev)
347 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
351 //if this is a binding action, let the ArdourButton handle it
352 if ( BindingProxy::is_bind_action(ev) )
355 multiple_mute_change = false;
357 if (Keyboard::is_context_menu_event (ev)) {
363 mute_menu->popup(0,ev->time);
369 if (Keyboard::is_button2_event (ev)) {
370 // button2-click is "momentary"
372 _mute_release = new SoloMuteRelease (_route->muted ());
375 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
377 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
379 /* toggle mute on everything (but
380 * exclude the master and monitor)
382 * because we are going to erase
383 * elements of the list we need to work
387 boost::shared_ptr<RouteList> copy (new RouteList);
389 *copy = *_session->get_routes ();
391 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
392 if ((*i)->is_master() || (*i)->is_monitor()) {
400 _mute_release->routes = copy;
404 _session->set_mute (copy, !_route->muted());
406 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
408 /* Primary-button1 applies change to the mix group even if it is not active
409 NOTE: Primary-button2 is MIDI learn.
412 boost::shared_ptr<RouteList> rl;
414 if (ev->button == 1) {
416 if (_route->route_group()) {
418 rl = _route->route_group()->route_list();
421 _mute_release->routes = rl;
424 rl.reset (new RouteList);
425 rl->push_back (_route);
429 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, true);
434 /* plain click applies change to this route */
436 boost::shared_ptr<RouteList> rl (new RouteList);
437 rl->push_back (_route);
440 _mute_release->routes = rl;
443 _session->set_mute (rl, !_route->muted());
453 RouteUI::mute_release (GdkEventButton* /*ev*/)
457 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
458 delete _mute_release;
466 RouteUI::edit_output_configuration ()
468 if (output_selector == 0) {
470 boost::shared_ptr<Send> send;
471 boost::shared_ptr<IO> output;
473 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
474 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
475 output = send->output();
477 output = _route->output ();
480 output = _route->output ();
483 output_selector = new IOSelectorWindow (_session, output);
486 if (output_selector->is_visible()) {
487 output_selector->get_toplevel()->get_window()->raise();
489 output_selector->present ();
492 //output_selector->set_keep_above (true);
496 RouteUI::edit_input_configuration ()
498 if (input_selector == 0) {
499 input_selector = new IOSelectorWindow (_session, _route->input());
502 if (input_selector->is_visible()) {
503 input_selector->get_toplevel()->get_window()->raise();
505 input_selector->present ();
508 //input_selector->set_keep_above (true);
512 RouteUI::solo_press(GdkEventButton* ev)
514 /* ignore double/triple clicks */
516 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
520 //if this is a binding action, let the ArdourButton handle it
521 if ( BindingProxy::is_bind_action(ev) )
524 multiple_solo_change = false;
526 if (Keyboard::is_context_menu_event (ev)) {
528 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
529 ! (solo_safe_led && solo_safe_led->is_visible())) {
531 if (solo_menu == 0) {
535 solo_menu->popup (1, ev->time);
540 if (Keyboard::is_button2_event (ev)) {
542 // button2-click is "momentary"
543 _solo_release = new SoloMuteRelease (_route->self_soloed());
546 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
548 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
550 /* Primary-Tertiary-click applies change to all routes */
553 _solo_release->routes = _session->get_routes ();
557 if (Config->get_solo_control_is_listen_control()) {
558 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, false);
560 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, false);
563 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
565 // Primary-Secondary-click: exclusively solo this track
568 _solo_release->exclusive = true;
570 boost::shared_ptr<RouteList> routes = _session->get_routes();
572 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
573 if ((*i)->soloed ()) {
574 _solo_release->routes_on->push_back (*i);
576 _solo_release->routes_off->push_back (*i);
581 if (Config->get_solo_control_is_listen_control()) {
582 /* ??? we need a just_one_listen() method */
585 _session->set_just_one_solo (_route, true);
588 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
590 // shift-click: toggle solo isolated status
592 _route->set_solo_isolated (!_route->solo_isolated(), this);
593 delete _solo_release;
596 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
598 /* Primary-button1: solo mix group.
599 NOTE: Primary-button2 is MIDI learn.
602 /* Primary-button1 applies change to the mix group even if it is not active
603 NOTE: Primary-button2 is MIDI learn.
606 boost::shared_ptr<RouteList> rl;
608 if (ev->button == 1) {
609 if (ARDOUR::Profile->get_mixbus() && _route->route_group()) {
611 rl = _route->route_group()->route_list();
614 _solo_release->routes = rl;
617 rl.reset (new RouteList);
618 rl->push_back (_route);
622 if (Config->get_solo_control_is_listen_control()) {
623 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, true);
625 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, true);
629 delete _solo_release;
634 /* click: solo this route */
636 boost::shared_ptr<RouteList> rl (new RouteList);
637 rl->push_back (route());
640 _solo_release->routes = rl;
644 if (Config->get_solo_control_is_listen_control()) {
645 _session->set_listen (rl, !_route->listening_via_monitor());
647 _session->set_solo (rl, !_route->self_soloed());
657 RouteUI::solo_release (GdkEventButton* /*ev*/)
661 if (_solo_release->exclusive) {
665 if (Config->get_solo_control_is_listen_control()) {
666 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, false);
668 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, false);
672 delete _solo_release;
680 RouteUI::rec_enable_press(GdkEventButton* ev)
682 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
686 //if this is a binding action, let the ArdourButton handle it
687 if ( BindingProxy::is_bind_action(ev) )
690 if (!_session->engine().connected()) {
691 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
696 if (is_midi_track()) {
698 /* rec-enable button exits from step editing */
700 if (midi_track()->step_editing()) {
701 midi_track()->set_step_editing (false);
706 if (is_track() && rec_enable_button) {
708 if (Keyboard::is_button2_event (ev)) {
710 //rec arm does not have a momentary mode
713 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
716 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
718 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
720 /* Primary-button1 applies change to the route group (even if it is not active)
721 NOTE: Primary-button2 is MIDI learn.
724 if (ev->button == 1) {
726 boost::shared_ptr<RouteList> rl;
728 if (_route->route_group()) {
730 rl = _route->route_group()->route_list();
733 rl.reset (new RouteList);
734 rl->push_back (_route);
738 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, true);
741 } else if (Keyboard::is_context_menu_event (ev)) {
743 /* do this on release */
747 boost::shared_ptr<RouteList> rl (new RouteList);
748 rl->push_back (route());
750 _session->set_record_enabled (rl, !_route->record_enabled());
758 RouteUI::monitoring_changed ()
760 update_monitoring_display ();
764 RouteUI::update_monitoring_display ()
770 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
776 MonitorState ms = t->monitoring_state();
778 if (t->monitoring_choice() & MonitorInput) {
779 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
781 if (ms & MonitoringInput) {
782 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
784 monitor_input_button->unset_active_state ();
788 if (t->monitoring_choice() & MonitorDisk) {
789 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
791 if (ms & MonitoringDisk) {
792 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
794 monitor_disk_button->unset_active_state ();
800 RouteUI::monitor_input_press(GdkEventButton*)
806 RouteUI::monitor_input_release(GdkEventButton* ev)
808 return monitor_release (ev, MonitorInput);
812 RouteUI::monitor_disk_press (GdkEventButton*)
818 RouteUI::monitor_disk_release (GdkEventButton* ev)
820 return monitor_release (ev, MonitorDisk);
824 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
826 if (ev->button != 1) {
830 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
837 boost::shared_ptr<RouteList> rl;
839 /* XXX for now, monitoring choices are orthogonal. cue monitoring
840 will follow in 3.X but requires mixing the input and playback (disk)
841 signal together, which requires yet more buffers.
844 if (t->monitoring_choice() & monitor_choice) {
845 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
847 /* this line will change when the options are non-orthogonal */
848 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
852 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
853 rl = _session->get_routes ();
855 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
856 if (_route->route_group() && _route->route_group()->is_monitoring()) {
857 rl = _route->route_group()->route_list();
859 rl.reset (new RouteList);
860 rl->push_back (route());
863 rl.reset (new RouteList);
864 rl->push_back (route());
868 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
874 RouteUI::build_record_menu ()
880 /* no rec-button context menu for non-MIDI tracks
883 if (is_midi_track()) {
884 record_menu = new Menu;
885 record_menu->set_name ("ArdourContextMenu");
887 using namespace Menu_Helpers;
888 MenuList& items = record_menu->items();
890 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
891 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
893 if (_route->record_enabled()) {
894 step_edit_item->set_sensitive (false);
897 step_edit_item->set_active (midi_track()->step_editing());
902 RouteUI::toggle_step_edit ()
904 if (!is_midi_track() || _route->record_enabled()) {
908 midi_track()->set_step_editing (step_edit_item->get_active());
912 RouteUI::step_edit_changed (bool yn)
915 if (rec_enable_button) {
916 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
919 start_step_editing ();
921 if (step_edit_item) {
922 step_edit_item->set_active (true);
927 if (rec_enable_button) {
928 rec_enable_button->unset_active_state ();
931 stop_step_editing ();
933 if (step_edit_item) {
934 step_edit_item->set_active (false);
940 RouteUI::rec_enable_release (GdkEventButton* ev)
942 if (Keyboard::is_context_menu_event (ev)) {
943 build_record_menu ();
945 record_menu->popup (1, ev->time);
954 RouteUI::build_sends_menu ()
956 using namespace Menu_Helpers;
958 sends_menu = new Menu;
959 sends_menu->set_name ("ArdourContextMenu");
960 MenuList& items = sends_menu->items();
963 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
967 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
971 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
975 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
979 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
983 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
986 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
990 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
993 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
994 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
995 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1000 RouteUI::create_sends (Placement p, bool include_buses)
1002 _session->globally_add_internal_sends (_route, p, include_buses);
1006 RouteUI::create_selected_sends (Placement p, bool include_buses)
1008 boost::shared_ptr<RouteList> rlist (new RouteList);
1009 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1011 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1012 RouteTimeAxisView* rtv;
1014 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1015 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1016 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1017 rlist->push_back (rui->route());
1023 _session->add_internal_sends (_route, p, rlist);
1027 RouteUI::set_sends_gain_from_track ()
1029 _session->globally_set_send_gains_from_track (_route);
1033 RouteUI::set_sends_gain_to_zero ()
1035 _session->globally_set_send_gains_to_zero (_route);
1039 RouteUI::set_sends_gain_to_unity ()
1041 _session->globally_set_send_gains_to_unity (_route);
1045 RouteUI::show_sends_press(GdkEventButton* ev)
1047 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1051 if (!is_track() && show_sends_button) {
1053 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1055 // do nothing on midi sigc::bind event
1058 } else if (Keyboard::is_context_menu_event (ev)) {
1060 if (sends_menu == 0) {
1061 build_sends_menu ();
1064 sends_menu->popup (0, ev->time);
1068 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1071 set_showing_sends_to (boost::shared_ptr<Route> ());
1073 set_showing_sends_to (_route);
1082 RouteUI::show_sends_release (GdkEventButton*)
1088 RouteUI::send_blink (bool onoff)
1090 if (!show_sends_button) {
1095 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1097 show_sends_button->unset_active_state ();
1101 Gtkmm2ext::ActiveState
1102 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1104 if (r->is_master() || r->is_monitor()) {
1105 return Gtkmm2ext::Off;
1108 if (Config->get_solo_control_is_listen_control()) {
1110 if (r->listening_via_monitor()) {
1111 return Gtkmm2ext::ExplicitActive;
1113 return Gtkmm2ext::Off;
1119 if (!r->self_soloed()) {
1120 return Gtkmm2ext::ImplicitActive;
1122 return Gtkmm2ext::ExplicitActive;
1125 return Gtkmm2ext::Off;
1129 Gtkmm2ext::ActiveState
1130 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1132 if (r->is_master() || r->is_monitor()) {
1133 return Gtkmm2ext::Off;
1136 if (r->solo_isolated()) {
1137 return Gtkmm2ext::ExplicitActive;
1139 return Gtkmm2ext::Off;
1143 Gtkmm2ext::ActiveState
1144 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1146 if (r->is_master() || r->is_monitor()) {
1147 return Gtkmm2ext::Off;
1150 if (r->solo_safe()) {
1151 return Gtkmm2ext::ExplicitActive;
1153 return Gtkmm2ext::Off;
1158 RouteUI::update_solo_display ()
1160 bool yn = _route->solo_safe ();
1162 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1163 solo_safe_check->set_active (yn);
1166 yn = _route->solo_isolated ();
1168 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1169 solo_isolated_check->set_active (yn);
1172 set_button_names ();
1174 if (solo_isolated_led) {
1175 if (_route->solo_isolated()) {
1176 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1178 solo_isolated_led->unset_active_state ();
1182 if (solo_safe_led) {
1183 if (_route->solo_safe()) {
1184 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1186 solo_safe_led->unset_active_state ();
1190 solo_button->set_active_state (solo_active_state (_route));
1192 /* some changes to solo status can affect mute display, so catch up
1195 update_mute_display ();
1199 RouteUI::solo_changed_so_update_mute ()
1201 update_mute_display ();
1205 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1207 if (r->is_monitor()) {
1208 return ActiveState(0);
1212 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1216 return Gtkmm2ext::ExplicitActive;
1217 } else if (r->muted_by_others()) {
1218 return Gtkmm2ext::ImplicitActive;
1220 /* no mute at all */
1221 return Gtkmm2ext::Off;
1228 return Gtkmm2ext::ExplicitActive;
1230 /* no mute at all */
1231 return Gtkmm2ext::Off;
1235 return ActiveState(0);
1239 RouteUI::update_mute_display ()
1245 mute_button->set_active_state (mute_active_state (_session, _route));
1249 RouteUI::route_rec_enable_changed ()
1251 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1252 update_monitoring_display ();
1256 RouteUI::session_rec_enable_changed ()
1258 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1259 update_monitoring_display ();
1263 RouteUI::blink_rec_display (bool blinkOn)
1265 if (!rec_enable_button || !_route) {
1268 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1272 if (_route->record_enabled()) {
1273 switch (_session->record_status ()) {
1274 case Session::Recording:
1275 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1278 case Session::Disabled:
1279 case Session::Enabled:
1280 if ( UIConfiguration::instance().get_blink_rec_arm() )
1281 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1283 rec_enable_button->set_active_state ( ImplicitActive );
1288 if (step_edit_item) {
1289 step_edit_item->set_sensitive (false);
1293 rec_enable_button->unset_active_state ();
1295 if (step_edit_item) {
1296 step_edit_item->set_sensitive (true);
1301 check_rec_enable_sensitivity ();
1305 RouteUI::build_solo_menu (void)
1307 using namespace Menu_Helpers;
1309 solo_menu = new Menu;
1310 solo_menu->set_name ("ArdourContextMenu");
1311 MenuList& items = solo_menu->items();
1312 Gtk::CheckMenuItem* check;
1314 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1315 check->set_active (_route->solo_isolated());
1316 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1317 items.push_back (CheckMenuElem(*check));
1318 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1321 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1322 check->set_active (_route->solo_safe());
1323 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1324 items.push_back (CheckMenuElem(*check));
1325 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1328 //items.push_back (SeparatorElem());
1329 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1334 RouteUI::build_mute_menu(void)
1336 using namespace Menu_Helpers;
1338 mute_menu = new Menu;
1339 mute_menu->set_name ("ArdourContextMenu");
1341 MenuList& items = mute_menu->items();
1343 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1344 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1345 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1346 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1347 pre_fader_mute_check->show_all();
1349 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1350 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1351 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1352 items.push_back (CheckMenuElem(*post_fader_mute_check));
1353 post_fader_mute_check->show_all();
1355 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1356 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1357 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1358 items.push_back (CheckMenuElem(*listen_mute_check));
1359 listen_mute_check->show_all();
1361 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1362 init_mute_menu(MuteMaster::Main, main_mute_check);
1363 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1364 items.push_back (CheckMenuElem(*main_mute_check));
1365 main_mute_check->show_all();
1367 //items.push_back (SeparatorElem());
1368 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1370 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1374 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1376 check->set_active (_route->mute_points() & mp);
1380 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1382 if (check->get_active()) {
1383 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1385 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1390 RouteUI::muting_change ()
1392 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1395 MuteMaster::MutePoint current = _route->mute_points ();
1397 yn = (current & MuteMaster::PreFader);
1399 if (pre_fader_mute_check->get_active() != yn) {
1400 pre_fader_mute_check->set_active (yn);
1403 yn = (current & MuteMaster::PostFader);
1405 if (post_fader_mute_check->get_active() != yn) {
1406 post_fader_mute_check->set_active (yn);
1409 yn = (current & MuteMaster::Listen);
1411 if (listen_mute_check->get_active() != yn) {
1412 listen_mute_check->set_active (yn);
1415 yn = (current & MuteMaster::Main);
1417 if (main_mute_check->get_active() != yn) {
1418 main_mute_check->set_active (yn);
1423 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1425 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1429 bool view = solo_isolated_led->active_state();
1430 bool model = _route->solo_isolated();
1432 /* called BEFORE the view has changed */
1434 if (ev->button == 1) {
1435 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1438 /* disable isolate for all routes */
1439 DisplaySuspender ds;
1440 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1442 /* enable isolate for all routes */
1443 DisplaySuspender ds;
1444 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, true);
1449 if (model == view) {
1451 /* flip just this route */
1453 boost::shared_ptr<RouteList> rl (new RouteList);
1454 rl->push_back (_route);
1455 DisplaySuspender ds;
1456 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1465 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1467 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1471 bool view = solo_safe_led->active_state();
1472 bool model = _route->solo_safe();
1474 if (ev->button == 1) {
1475 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1476 boost::shared_ptr<RouteList> rl (_session->get_routes());
1478 /* disable solo safe for all routes */
1479 DisplaySuspender ds;
1480 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1481 (*i)->set_solo_safe (false, this);
1484 /* enable solo safe for all routes */
1485 DisplaySuspender ds;
1486 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1487 (*i)->set_solo_safe (true, this);
1492 if (model == view) {
1493 /* flip just this route */
1494 _route->set_solo_safe (!view, this);
1503 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1505 bool view = check->get_active();
1506 bool model = _route->solo_isolated();
1508 /* called AFTER the view has changed */
1510 if (model != view) {
1511 _route->set_solo_isolated (view, this);
1516 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1518 _route->set_solo_safe (check->get_active(), this);
1521 /** Ask the user to choose a colour, and then apply that color to my route
1524 RouteUI::choose_color ()
1527 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1534 /** Set the route's own color. This may not be used for display if
1535 * the route is in a group which shares its color with its routes.
1538 RouteUI::set_color (const Gdk::Color & c)
1540 /* leave _color alone in the group case so that tracks can retain their
1541 * own pre-group colors.
1546 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1548 /* note: we use the route state ID here so that color is the same for both
1549 the time axis view and the mixer strip
1552 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1553 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1556 /** @return GUI state ID for things that are common to the route in all its representations */
1558 RouteUI::route_state_id () const
1560 return string_compose (X_("route %1"), _route->id().to_s());
1564 RouteUI::set_color_from_route ()
1566 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1574 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1577 _color.set_green (g);
1578 _color.set_blue (b);
1583 /** @return true if this name should be used for the route, otherwise false */
1585 RouteUI::verify_new_route_name (const std::string& name)
1587 if (name.find (':') == string::npos) {
1591 MessageDialog colon_msg (
1592 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1593 false, MESSAGE_QUESTION, BUTTONS_NONE
1596 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1597 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1599 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1603 RouteUI::route_rename ()
1605 ArdourPrompter name_prompter (true);
1610 name_prompter.set_title (_("Rename Track"));
1612 name_prompter.set_title (_("Rename Bus"));
1614 name_prompter.set_prompt (_("New name:"));
1615 name_prompter.set_initial_text (_route->name());
1616 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1617 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1618 name_prompter.show_all ();
1621 switch (name_prompter.run ()) {
1622 case Gtk::RESPONSE_ACCEPT:
1623 name_prompter.get_result (result);
1624 name_prompter.hide ();
1625 if (result.length()) {
1626 if (verify_new_route_name (result)) {
1627 _route->set_name (result);
1630 /* back to name prompter */
1634 /* nothing entered, just get out of here */
1649 RouteUI::property_changed (const PropertyChange& what_changed)
1651 if (what_changed.contains (ARDOUR::Properties::name)) {
1652 name_label.set_text (_route->name());
1657 RouteUI::toggle_comment_editor ()
1659 // if (ignore_toggle) {
1663 if (comment_window && comment_window->is_visible ()) {
1664 comment_window->hide ();
1666 open_comment_editor ();
1672 RouteUI::open_comment_editor ()
1674 if (comment_window == 0) {
1675 setup_comment_editor ();
1679 title = _route->name();
1680 title += _(": comment editor");
1682 comment_window->set_title (title);
1683 comment_window->present();
1687 RouteUI::setup_comment_editor ()
1689 comment_window = new ArdourWindow (""); // title will be reset to show route
1690 comment_window->set_skip_taskbar_hint (true);
1691 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1692 comment_window->set_default_size (400, 200);
1694 comment_area = manage (new TextView());
1695 comment_area->set_name ("MixerTrackCommentArea");
1696 comment_area->set_wrap_mode (WRAP_WORD);
1697 comment_area->set_editable (true);
1698 comment_area->get_buffer()->set_text (_route->comment());
1699 comment_area->show ();
1701 comment_window->add (*comment_area);
1705 RouteUI::comment_changed (void *src)
1707 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_changed, src)
1710 ignore_comment_edit = true;
1712 comment_area->get_buffer()->set_text (_route->comment());
1714 ignore_comment_edit = false;
1719 RouteUI::comment_editor_done_editing ()
1721 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1723 string const str = comment_area->get_buffer()->get_text();
1724 if (str == _route->comment ()) {
1728 _route->set_comment (str, this);
1732 RouteUI::set_route_active (bool a, bool apply_to_selection)
1734 if (apply_to_selection) {
1735 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1737 _route->set_active (a, this);
1742 RouteUI::duplicate_selected_routes ()
1744 ARDOUR_UI::instance()->start_duplicate_routes();
1748 RouteUI::toggle_denormal_protection ()
1750 if (denormal_menu_item) {
1754 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1756 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1757 _route->set_denormal_protection (x);
1763 RouteUI::denormal_protection_changed ()
1765 if (denormal_menu_item) {
1766 denormal_menu_item->set_active (_route->denormal_protection());
1771 RouteUI::disconnect_input ()
1773 _route->input()->disconnect (this);
1777 RouteUI::disconnect_output ()
1779 _route->output()->disconnect (this);
1783 RouteUI::is_track () const
1785 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1788 boost::shared_ptr<Track>
1789 RouteUI::track() const
1791 return boost::dynamic_pointer_cast<Track>(_route);
1795 RouteUI::is_audio_track () const
1797 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1800 boost::shared_ptr<AudioTrack>
1801 RouteUI::audio_track() const
1803 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1807 RouteUI::is_midi_track () const
1809 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1812 boost::shared_ptr<MidiTrack>
1813 RouteUI::midi_track() const
1815 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1819 RouteUI::has_audio_outputs () const
1821 return (_route->n_outputs().n_audio() > 0);
1825 RouteUI::name() const
1827 return _route->name();
1831 RouteUI::map_frozen ()
1833 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1835 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1838 switch (at->freeze_state()) {
1839 case AudioTrack::Frozen:
1840 rec_enable_button->set_sensitive (false);
1843 rec_enable_button->set_sensitive (true);
1850 RouteUI::adjust_latency ()
1852 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1856 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1859 std::string safe_name;
1862 prompter.get_result (name, true);
1864 safe_name = legalize_for_path (name);
1865 safe_name += template_suffix;
1867 path = Glib::build_filename (dir, safe_name);
1869 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1870 bool overwrite = overwrite_file_dialog (prompter,
1871 _("Confirm Template Overwrite"),
1872 _("A template already exists with that name. Do you want to overwrite it?"));
1879 _route->save_as_template (path, name);
1885 RouteUI::save_as_template ()
1889 dir = ARDOUR::user_route_template_directory ();
1891 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1892 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1896 ArdourPrompter prompter (true); // modal
1898 prompter.set_title (_("Save As Template"));
1899 prompter.set_prompt (_("Template name:"));
1900 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1902 bool finished = false;
1904 switch (prompter.run()) {
1905 case RESPONSE_ACCEPT:
1906 finished = process_save_template_prompter (prompter, dir);
1916 RouteUI::check_rec_enable_sensitivity ()
1918 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1919 rec_enable_button->set_sensitive (false);
1921 rec_enable_button->set_sensitive (true);
1924 update_monitoring_display ();
1928 RouteUI::parameter_changed (string const & p)
1930 /* this handles RC and per-session parameter changes */
1932 if (p == "disable-disarm-during-roll") {
1933 check_rec_enable_sensitivity ();
1934 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1935 set_button_names ();
1936 } else if (p == "auto-input") {
1937 update_monitoring_display ();
1938 } else if (p == "blink-rec-arm") {
1939 if (UIConfiguration::instance().get_blink_rec_arm()) {
1940 rec_blink_connection.disconnect ();
1941 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1943 rec_blink_connection.disconnect ();
1944 RouteUI::blink_rec_display(false);
1950 RouteUI::step_gain_up ()
1952 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1956 RouteUI::page_gain_up ()
1958 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1962 RouteUI::step_gain_down ()
1964 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1968 RouteUI::page_gain_down ()
1970 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1974 RouteUI::open_remote_control_id_dialog ()
1976 ArdourDialog dialog (_("Remote Control ID"));
1977 SpinButton* spin = 0;
1979 dialog.get_vbox()->set_border_width (18);
1981 if (Config->get_remote_model() == UserOrdered) {
1982 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1984 HBox* hbox = manage (new HBox);
1985 hbox->set_spacing (6);
1986 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1987 spin = manage (new SpinButton);
1988 spin->set_digits (0);
1989 spin->set_increments (1, 10);
1990 spin->set_range (0, limit);
1991 spin->set_value (_route->remote_control_id());
1992 hbox->pack_start (*spin);
1993 dialog.get_vbox()->pack_start (*hbox);
1995 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1996 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1998 Label* l = manage (new Label());
1999 if (_route->is_master() || _route->is_monitor()) {
2000 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2001 "The remote control ID of %3 cannot be changed."),
2002 Gtkmm2ext::markup_escape_text (_route->name()),
2003 _route->remote_control_id(),
2004 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2006 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2007 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2008 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2009 (is_track() ? _("track") : _("bus")),
2010 _route->remote_control_id(),
2011 "<span size=\"small\" style=\"italic\">",
2013 Gtkmm2ext::markup_escape_text (_route->name()),
2016 dialog.get_vbox()->pack_start (*l);
2017 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2021 int const r = dialog.run ();
2023 if (r == RESPONSE_ACCEPT && spin) {
2024 _route->set_remote_control_id (spin->get_value_as_int ());
2029 RouteUI::setup_invert_buttons ()
2031 /* remove old invert buttons */
2032 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2033 _invert_button_box.remove (**i);
2036 _invert_buttons.clear ();
2038 if (!_route || !_route->input()) {
2042 uint32_t const N = _route->input()->n_ports().n_audio ();
2044 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2046 for (uint32_t i = 0; i < to_add; ++i) {
2047 ArdourButton* b = manage (new ArdourButton);
2048 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2049 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2051 b->set_name (X_("invert button"));
2054 b->set_text (string_compose (X_("Ø (%1)"), N));
2056 b->set_text (X_("Ø"));
2059 b->set_text (string_compose (X_("Ø%1"), i + 1));
2062 if (N <= _max_invert_buttons) {
2063 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track. Right-click to show menu."), i + 1));
2065 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2068 _invert_buttons.push_back (b);
2069 _invert_button_box.pack_start (*b);
2072 _invert_button_box.set_spacing (1);
2073 _invert_button_box.show_all ();
2077 RouteUI::set_invert_button_state ()
2079 uint32_t const N = _route->input()->n_ports().n_audio();
2080 if (N > _max_invert_buttons) {
2082 /* One button for many channels; explicit active if all channels are inverted,
2083 implicit active if some are, off if none are.
2086 ArdourButton* b = _invert_buttons.front ();
2088 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2089 b->set_active_state (Gtkmm2ext::ExplicitActive);
2090 } else if (_route->phase_invert().any()) {
2091 b->set_active_state (Gtkmm2ext::ImplicitActive);
2093 b->set_active_state (Gtkmm2ext::Off);
2098 /* One button per channel; just set active */
2101 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2102 (*i)->set_active (_route->phase_invert (j));
2109 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2111 if (ev->button == 1 && i < _invert_buttons.size()) {
2112 uint32_t const N = _route->input()->n_ports().n_audio ();
2113 if (N <= _max_invert_buttons) {
2114 /* left-click inverts phase so long as we have a button per channel */
2115 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2124 RouteUI::invert_press (GdkEventButton* ev)
2126 using namespace Menu_Helpers;
2128 uint32_t const N = _route->input()->n_ports().n_audio();
2129 if (N <= _max_invert_buttons && ev->button != 3) {
2130 /* If we have an invert button per channel, we only pop
2131 up a menu on right-click; left click is handled
2137 delete _invert_menu;
2138 _invert_menu = new Menu;
2139 _invert_menu->set_name ("ArdourContextMenu");
2140 MenuList& items = _invert_menu->items ();
2142 for (uint32_t i = 0; i < N; ++i) {
2143 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2144 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2145 ++_i_am_the_modifier;
2146 e->set_active (_route->phase_invert (i));
2147 --_i_am_the_modifier;
2150 _invert_menu->popup (0, ev->time);
2156 RouteUI::invert_menu_toggled (uint32_t c)
2158 if (_i_am_the_modifier) {
2162 _route->set_phase_invert (c, !_route->phase_invert (c));
2166 RouteUI::set_invert_sensitive (bool yn)
2168 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2169 (*b)->set_sensitive (yn);
2174 RouteUI::request_redraw ()
2177 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2181 /** The Route's gui_changed signal has been emitted */
2183 RouteUI::route_gui_changed (string what_changed)
2185 if (what_changed == "color") {
2186 if (set_color_from_route () == 0) {
2187 route_color_changed ();
2193 RouteUI::track_mode_changed (void)
2196 switch (track()->mode()) {
2197 case ARDOUR::NonLayered:
2198 case ARDOUR::Normal:
2199 rec_enable_button->set_icon (ArdourIcon::RecButton);
2201 case ARDOUR::Destructive:
2202 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2205 rec_enable_button->queue_draw();
2208 /** @return the color that this route should use; it maybe its own,
2209 or it maybe that of its route group.
2212 RouteUI::color () const
2214 RouteGroup* g = _route->route_group ();
2216 if (g && g->is_color()) {
2218 set_color_from_rgba (c, GroupTabs::group_color (g));
2226 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2228 _showing_sends_to = send_to;
2229 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2233 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2235 if (_route == send_to) {
2236 show_sends_button->set_active (true);
2237 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2239 show_sends_button->set_active (false);
2240 send_blink_connection.disconnect ();
2245 RouteUI::route_group() const
2247 return _route->route_group();