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), 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 inverts the implication of
409 the group being active. If the group is
410 active (for mute), then this modifier means
411 "do not apply to mute". If the group is
412 inactive (for mute), then this modifier
413 means "apply to route". This is all
414 accomplished by passing just the actual
415 route, along with the InverseGroup group
418 NOTE: Primary-button2 is MIDI learn.
421 boost::shared_ptr<RouteList> rl;
423 if (ev->button == 1) {
425 rl.reset (new RouteList);
426 rl->push_back (_route);
429 _mute_release->routes = rl;
433 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
438 /* plain click applies change to this route */
440 boost::shared_ptr<RouteList> rl (new RouteList);
441 rl->push_back (_route);
444 _mute_release->routes = rl;
447 _session->set_mute (rl, !_route->muted());
457 RouteUI::mute_release (GdkEventButton* /*ev*/)
461 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
462 delete _mute_release;
470 RouteUI::edit_output_configuration ()
472 if (output_selector == 0) {
474 boost::shared_ptr<Send> send;
475 boost::shared_ptr<IO> output;
477 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
478 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
479 output = send->output();
481 output = _route->output ();
484 output = _route->output ();
487 output_selector = new IOSelectorWindow (_session, output);
490 if (output_selector->is_visible()) {
491 output_selector->get_toplevel()->get_window()->raise();
493 output_selector->present ();
496 //output_selector->set_keep_above (true);
500 RouteUI::edit_input_configuration ()
502 if (input_selector == 0) {
503 input_selector = new IOSelectorWindow (_session, _route->input());
506 if (input_selector->is_visible()) {
507 input_selector->get_toplevel()->get_window()->raise();
509 input_selector->present ();
512 //input_selector->set_keep_above (true);
516 RouteUI::solo_press(GdkEventButton* ev)
518 /* ignore double/triple clicks */
520 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
524 //if this is a binding action, let the ArdourButton handle it
525 if ( BindingProxy::is_bind_action(ev) )
528 multiple_solo_change = false;
530 if (Keyboard::is_context_menu_event (ev)) {
532 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
533 ! (solo_safe_led && solo_safe_led->is_visible())) {
535 if (solo_menu == 0) {
539 solo_menu->popup (1, ev->time);
544 if (Keyboard::is_button2_event (ev)) {
546 // button2-click is "momentary"
547 _solo_release = new SoloMuteRelease (_route->self_soloed());
550 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
552 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
554 /* Primary-Tertiary-click applies change to all routes */
557 _solo_release->routes = _session->get_routes ();
561 if (Config->get_solo_control_is_listen_control()) {
562 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::NoGroup);
564 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, Controllable::NoGroup);
567 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
569 // Primary-Secondary-click: exclusively solo this track
572 _solo_release->exclusive = true;
574 boost::shared_ptr<RouteList> routes = _session->get_routes();
576 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
577 if ((*i)->soloed ()) {
578 _solo_release->routes_on->push_back (*i);
580 _solo_release->routes_off->push_back (*i);
585 if (Config->get_solo_control_is_listen_control()) {
586 /* ??? we need a just_one_listen() method */
589 _session->set_just_one_solo (_route, true);
592 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
594 // shift-click: toggle solo isolated status
596 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
597 delete _solo_release;
600 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
602 /* Primary-button1: solo mix group.
603 NOTE: Primary-button2 is MIDI learn.
606 /* Primary-button1 applies change to the mix group even if it is not active
607 NOTE: Primary-button2 is MIDI learn.
610 boost::shared_ptr<RouteList> rl;
612 if (ev->button == 1) {
614 /* Primary-button1 inverts the implication of
615 the group being active. If the group is
616 active (for solo), then this modifier means
617 "do not apply to solo". If the group is
618 inactive (for mute), then this modifier
619 means "apply to route". This is all
620 accomplished by passing just the actual
621 route, along with the InverseGroup group
624 NOTE: Primary-button2 is MIDI learn.
627 rl.reset (new RouteList);
628 rl->push_back (_route);
631 _solo_release->routes = rl;
636 if (Config->get_solo_control_is_listen_control()) {
637 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
639 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
643 delete _solo_release;
648 /* click: solo this route */
650 boost::shared_ptr<RouteList> rl (new RouteList);
651 rl->push_back (route());
654 _solo_release->routes = rl;
658 if (Config->get_solo_control_is_listen_control()) {
659 _session->set_listen (rl, !_route->listening_via_monitor());
661 _session->set_solo (rl, !_route->self_soloed());
671 RouteUI::solo_release (GdkEventButton* /*ev*/)
675 if (_solo_release->exclusive) {
679 if (Config->get_solo_control_is_listen_control()) {
680 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
682 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
686 delete _solo_release;
694 RouteUI::rec_enable_press(GdkEventButton* ev)
696 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
700 //if this is a binding action, let the ArdourButton handle it
701 if ( BindingProxy::is_bind_action(ev) )
704 if (!_session->engine().connected()) {
705 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
710 if (is_midi_track()) {
712 /* rec-enable button exits from step editing */
714 if (midi_track()->step_editing()) {
715 midi_track()->set_step_editing (false);
720 if (is_track() && rec_enable_button) {
722 if (Keyboard::is_button2_event (ev)) {
724 //rec arm does not have a momentary mode
727 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
730 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
732 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
734 /* Primary-button1 applies change to the route group (even if it is not active)
735 NOTE: Primary-button2 is MIDI learn.
738 if (ev->button == 1) {
740 boost::shared_ptr<RouteList> rl;
742 rl.reset (new RouteList);
743 rl->push_back (_route);
746 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
749 } else if (Keyboard::is_context_menu_event (ev)) {
751 /* do this on release */
755 boost::shared_ptr<RouteList> rl (new RouteList);
756 rl->push_back (route());
758 _session->set_record_enabled (rl, !_route->record_enabled());
766 RouteUI::monitoring_changed ()
768 update_monitoring_display ();
772 RouteUI::update_monitoring_display ()
778 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
784 MonitorState ms = t->monitoring_state();
786 if (t->monitoring_choice() & MonitorInput) {
787 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
789 if (ms & MonitoringInput) {
790 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
792 monitor_input_button->unset_active_state ();
796 if (t->monitoring_choice() & MonitorDisk) {
797 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
799 if (ms & MonitoringDisk) {
800 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
802 monitor_disk_button->unset_active_state ();
808 RouteUI::monitor_input_press(GdkEventButton*)
814 RouteUI::monitor_input_release(GdkEventButton* ev)
816 return monitor_release (ev, MonitorInput);
820 RouteUI::monitor_disk_press (GdkEventButton*)
826 RouteUI::monitor_disk_release (GdkEventButton* ev)
828 return monitor_release (ev, MonitorDisk);
832 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
834 if (ev->button != 1) {
838 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
845 boost::shared_ptr<RouteList> rl;
847 /* XXX for now, monitoring choices are orthogonal. cue monitoring
848 will follow in 3.X but requires mixing the input and playback (disk)
849 signal together, which requires yet more buffers.
852 if (t->monitoring_choice() & monitor_choice) {
853 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
855 /* this line will change when the options are non-orthogonal */
856 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
860 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
861 rl = _session->get_routes ();
863 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
864 if (_route->route_group() && _route->route_group()->is_monitoring()) {
865 rl = _route->route_group()->route_list();
867 rl.reset (new RouteList);
868 rl->push_back (route());
871 rl.reset (new RouteList);
872 rl->push_back (route());
876 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
882 RouteUI::build_record_menu ()
888 /* no rec-button context menu for non-MIDI tracks
891 if (is_midi_track()) {
892 record_menu = new Menu;
893 record_menu->set_name ("ArdourContextMenu");
895 using namespace Menu_Helpers;
896 MenuList& items = record_menu->items();
898 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
899 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
901 if (_route->record_enabled()) {
902 step_edit_item->set_sensitive (false);
905 step_edit_item->set_active (midi_track()->step_editing());
910 RouteUI::toggle_step_edit ()
912 if (!is_midi_track() || _route->record_enabled()) {
916 midi_track()->set_step_editing (step_edit_item->get_active());
920 RouteUI::step_edit_changed (bool yn)
923 if (rec_enable_button) {
924 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
927 start_step_editing ();
929 if (step_edit_item) {
930 step_edit_item->set_active (true);
935 if (rec_enable_button) {
936 rec_enable_button->unset_active_state ();
939 stop_step_editing ();
941 if (step_edit_item) {
942 step_edit_item->set_active (false);
948 RouteUI::rec_enable_release (GdkEventButton* ev)
950 if (Keyboard::is_context_menu_event (ev)) {
951 build_record_menu ();
953 record_menu->popup (1, ev->time);
962 RouteUI::build_sends_menu ()
964 using namespace Menu_Helpers;
966 sends_menu = new Menu;
967 sends_menu->set_name ("ArdourContextMenu");
968 MenuList& items = sends_menu->items();
971 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
975 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
979 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
983 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
987 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
991 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
994 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
998 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1001 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1002 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1003 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1008 RouteUI::create_sends (Placement p, bool include_buses)
1010 _session->globally_add_internal_sends (_route, p, include_buses);
1014 RouteUI::create_selected_sends (Placement p, bool include_buses)
1016 boost::shared_ptr<RouteList> rlist (new RouteList);
1017 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1019 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1020 RouteTimeAxisView* rtv;
1022 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1023 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1024 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1025 rlist->push_back (rui->route());
1031 _session->add_internal_sends (_route, p, rlist);
1035 RouteUI::set_sends_gain_from_track ()
1037 _session->globally_set_send_gains_from_track (_route);
1041 RouteUI::set_sends_gain_to_zero ()
1043 _session->globally_set_send_gains_to_zero (_route);
1047 RouteUI::set_sends_gain_to_unity ()
1049 _session->globally_set_send_gains_to_unity (_route);
1053 RouteUI::show_sends_press(GdkEventButton* ev)
1055 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1059 if (!is_track() && show_sends_button) {
1061 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1063 // do nothing on midi sigc::bind event
1066 } else if (Keyboard::is_context_menu_event (ev)) {
1068 if (sends_menu == 0) {
1069 build_sends_menu ();
1072 sends_menu->popup (0, ev->time);
1076 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1079 set_showing_sends_to (boost::shared_ptr<Route> ());
1081 set_showing_sends_to (_route);
1090 RouteUI::show_sends_release (GdkEventButton*)
1096 RouteUI::send_blink (bool onoff)
1098 if (!show_sends_button) {
1103 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1105 show_sends_button->unset_active_state ();
1109 Gtkmm2ext::ActiveState
1110 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1112 if (r->is_master() || r->is_monitor()) {
1113 return Gtkmm2ext::Off;
1116 if (Config->get_solo_control_is_listen_control()) {
1118 if (r->listening_via_monitor()) {
1119 return Gtkmm2ext::ExplicitActive;
1121 return Gtkmm2ext::Off;
1127 if (!r->self_soloed()) {
1128 return Gtkmm2ext::ImplicitActive;
1130 return Gtkmm2ext::ExplicitActive;
1133 return Gtkmm2ext::Off;
1137 Gtkmm2ext::ActiveState
1138 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1140 if (r->is_master() || r->is_monitor()) {
1141 return Gtkmm2ext::Off;
1144 if (r->solo_isolated()) {
1145 return Gtkmm2ext::ExplicitActive;
1147 return Gtkmm2ext::Off;
1151 Gtkmm2ext::ActiveState
1152 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1154 if (r->is_master() || r->is_monitor()) {
1155 return Gtkmm2ext::Off;
1158 if (r->solo_safe()) {
1159 return Gtkmm2ext::ExplicitActive;
1161 return Gtkmm2ext::Off;
1166 RouteUI::update_solo_display ()
1168 bool yn = _route->solo_safe ();
1170 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1171 solo_safe_check->set_active (yn);
1174 yn = _route->solo_isolated ();
1176 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1177 solo_isolated_check->set_active (yn);
1180 set_button_names ();
1182 if (solo_isolated_led) {
1183 if (_route->solo_isolated()) {
1184 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1186 solo_isolated_led->unset_active_state ();
1190 if (solo_safe_led) {
1191 if (_route->solo_safe()) {
1192 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1194 solo_safe_led->unset_active_state ();
1198 solo_button->set_active_state (solo_active_state (_route));
1200 /* some changes to solo status can affect mute display, so catch up
1203 update_mute_display ();
1207 RouteUI::solo_changed_so_update_mute ()
1209 update_mute_display ();
1213 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1215 if (r->is_monitor()) {
1216 return ActiveState(0);
1220 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1224 return Gtkmm2ext::ExplicitActive;
1225 } else if (r->muted_by_others()) {
1226 return Gtkmm2ext::ImplicitActive;
1228 /* no mute at all */
1229 return Gtkmm2ext::Off;
1236 return Gtkmm2ext::ExplicitActive;
1238 /* no mute at all */
1239 return Gtkmm2ext::Off;
1243 return ActiveState(0);
1247 RouteUI::update_mute_display ()
1253 mute_button->set_active_state (mute_active_state (_session, _route));
1257 RouteUI::route_rec_enable_changed ()
1259 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1260 update_monitoring_display ();
1264 RouteUI::session_rec_enable_changed ()
1266 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1267 update_monitoring_display ();
1271 RouteUI::blink_rec_display (bool blinkOn)
1273 if (!rec_enable_button || !_route) {
1276 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1280 if (_route->record_enabled()) {
1281 switch (_session->record_status ()) {
1282 case Session::Recording:
1283 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1286 case Session::Disabled:
1287 case Session::Enabled:
1288 if ( UIConfiguration::instance().get_blink_rec_arm() )
1289 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1291 rec_enable_button->set_active_state ( ImplicitActive );
1296 if (step_edit_item) {
1297 step_edit_item->set_sensitive (false);
1301 rec_enable_button->unset_active_state ();
1303 if (step_edit_item) {
1304 step_edit_item->set_sensitive (true);
1309 check_rec_enable_sensitivity ();
1313 RouteUI::build_solo_menu (void)
1315 using namespace Menu_Helpers;
1317 solo_menu = new Menu;
1318 solo_menu->set_name ("ArdourContextMenu");
1319 MenuList& items = solo_menu->items();
1320 Gtk::CheckMenuItem* check;
1322 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1323 check->set_active (_route->solo_isolated());
1324 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1325 items.push_back (CheckMenuElem(*check));
1326 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1329 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1330 check->set_active (_route->solo_safe());
1331 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1332 items.push_back (CheckMenuElem(*check));
1333 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1336 //items.push_back (SeparatorElem());
1337 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1342 RouteUI::build_mute_menu(void)
1344 using namespace Menu_Helpers;
1346 mute_menu = new Menu;
1347 mute_menu->set_name ("ArdourContextMenu");
1349 MenuList& items = mute_menu->items();
1351 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1352 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1353 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1354 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1355 pre_fader_mute_check->show_all();
1357 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1358 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1359 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1360 items.push_back (CheckMenuElem(*post_fader_mute_check));
1361 post_fader_mute_check->show_all();
1363 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1364 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1365 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1366 items.push_back (CheckMenuElem(*listen_mute_check));
1367 listen_mute_check->show_all();
1369 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1370 init_mute_menu(MuteMaster::Main, main_mute_check);
1371 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1372 items.push_back (CheckMenuElem(*main_mute_check));
1373 main_mute_check->show_all();
1375 //items.push_back (SeparatorElem());
1376 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1378 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1382 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1384 check->set_active (_route->mute_points() & mp);
1388 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1390 if (check->get_active()) {
1391 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1393 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1398 RouteUI::muting_change ()
1400 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1403 MuteMaster::MutePoint current = _route->mute_points ();
1405 yn = (current & MuteMaster::PreFader);
1407 if (pre_fader_mute_check->get_active() != yn) {
1408 pre_fader_mute_check->set_active (yn);
1411 yn = (current & MuteMaster::PostFader);
1413 if (post_fader_mute_check->get_active() != yn) {
1414 post_fader_mute_check->set_active (yn);
1417 yn = (current & MuteMaster::Listen);
1419 if (listen_mute_check->get_active() != yn) {
1420 listen_mute_check->set_active (yn);
1423 yn = (current & MuteMaster::Main);
1425 if (main_mute_check->get_active() != yn) {
1426 main_mute_check->set_active (yn);
1431 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1433 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1437 bool view = solo_isolated_led->active_state();
1438 bool model = _route->solo_isolated();
1440 /* called BEFORE the view has changed */
1442 if (ev->button == 1) {
1443 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1446 /* disable isolate for all routes */
1447 DisplaySuspender ds;
1448 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1450 /* enable isolate for all routes */
1451 DisplaySuspender ds;
1452 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1457 if (model == view) {
1459 /* flip just this route */
1461 boost::shared_ptr<RouteList> rl (new RouteList);
1462 rl->push_back (_route);
1463 DisplaySuspender ds;
1464 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1473 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1475 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1479 bool view = solo_safe_led->active_state();
1480 bool model = _route->solo_safe();
1482 if (ev->button == 1) {
1483 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1484 boost::shared_ptr<RouteList> rl (_session->get_routes());
1486 /* disable solo safe for all routes */
1487 DisplaySuspender ds;
1488 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1489 (*i)->set_solo_safe (false, Controllable::NoGroup);
1492 /* enable solo safe for all routes */
1493 DisplaySuspender ds;
1494 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1495 (*i)->set_solo_safe (true, Controllable::NoGroup);
1500 if (model == view) {
1501 /* flip just this route */
1502 _route->set_solo_safe (!view, Controllable::NoGroup);
1511 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1513 bool view = check->get_active();
1514 bool model = _route->solo_isolated();
1516 /* called AFTER the view has changed */
1518 if (model != view) {
1519 _route->set_solo_isolated (view, Controllable::UseGroup);
1524 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1526 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1529 /** Ask the user to choose a colour, and then apply that color to my route
1532 RouteUI::choose_color ()
1535 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1542 /** Set the route's own color. This may not be used for display if
1543 * the route is in a group which shares its color with its routes.
1546 RouteUI::set_color (const Gdk::Color & c)
1548 /* leave _color alone in the group case so that tracks can retain their
1549 * own pre-group colors.
1554 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1556 /* note: we use the route state ID here so that color is the same for both
1557 the time axis view and the mixer strip
1560 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1561 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1564 /** @return GUI state ID for things that are common to the route in all its representations */
1566 RouteUI::route_state_id () const
1568 return string_compose (X_("route %1"), _route->id().to_s());
1572 RouteUI::set_color_from_route ()
1574 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1582 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1585 _color.set_green (g);
1586 _color.set_blue (b);
1591 /** @return true if this name should be used for the route, otherwise false */
1593 RouteUI::verify_new_route_name (const std::string& name)
1595 if (name.find (':') == string::npos) {
1599 MessageDialog colon_msg (
1600 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1601 false, MESSAGE_QUESTION, BUTTONS_NONE
1604 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1605 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1607 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1611 RouteUI::route_rename ()
1613 ArdourPrompter name_prompter (true);
1618 name_prompter.set_title (_("Rename Track"));
1620 name_prompter.set_title (_("Rename Bus"));
1622 name_prompter.set_prompt (_("New name:"));
1623 name_prompter.set_initial_text (_route->name());
1624 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1625 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1626 name_prompter.show_all ();
1629 switch (name_prompter.run ()) {
1630 case Gtk::RESPONSE_ACCEPT:
1631 name_prompter.get_result (result);
1632 name_prompter.hide ();
1633 if (result.length()) {
1634 if (verify_new_route_name (result)) {
1635 _route->set_name (result);
1638 /* back to name prompter */
1642 /* nothing entered, just get out of here */
1657 RouteUI::property_changed (const PropertyChange& what_changed)
1659 if (what_changed.contains (ARDOUR::Properties::name)) {
1660 name_label.set_text (_route->name());
1665 RouteUI::toggle_comment_editor ()
1667 // if (ignore_toggle) {
1671 if (comment_window && comment_window->is_visible ()) {
1672 comment_window->hide ();
1674 open_comment_editor ();
1680 RouteUI::open_comment_editor ()
1682 if (comment_window == 0) {
1683 setup_comment_editor ();
1687 title = _route->name();
1688 title += _(": comment editor");
1690 comment_window->set_title (title);
1691 comment_window->present();
1695 RouteUI::setup_comment_editor ()
1697 comment_window = new ArdourWindow (""); // title will be reset to show route
1698 comment_window->set_skip_taskbar_hint (true);
1699 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1700 comment_window->set_default_size (400, 200);
1702 comment_area = manage (new TextView());
1703 comment_area->set_name ("MixerTrackCommentArea");
1704 comment_area->set_wrap_mode (WRAP_WORD);
1705 comment_area->set_editable (true);
1706 comment_area->get_buffer()->set_text (_route->comment());
1707 comment_area->show ();
1709 comment_window->add (*comment_area);
1713 RouteUI::comment_changed ()
1715 ignore_comment_edit = true;
1717 comment_area->get_buffer()->set_text (_route->comment());
1719 ignore_comment_edit = false;
1723 RouteUI::comment_editor_done_editing ()
1725 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1727 string const str = comment_area->get_buffer()->get_text();
1728 if (str == _route->comment ()) {
1732 _route->set_comment (str, this);
1736 RouteUI::set_route_active (bool a, bool apply_to_selection)
1738 if (apply_to_selection) {
1739 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1741 _route->set_active (a, this);
1746 RouteUI::duplicate_selected_routes ()
1748 ARDOUR_UI::instance()->start_duplicate_routes();
1752 RouteUI::toggle_denormal_protection ()
1754 if (denormal_menu_item) {
1758 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1760 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1761 _route->set_denormal_protection (x);
1767 RouteUI::denormal_protection_changed ()
1769 if (denormal_menu_item) {
1770 denormal_menu_item->set_active (_route->denormal_protection());
1775 RouteUI::disconnect_input ()
1777 _route->input()->disconnect (this);
1781 RouteUI::disconnect_output ()
1783 _route->output()->disconnect (this);
1787 RouteUI::is_track () const
1789 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1792 boost::shared_ptr<Track>
1793 RouteUI::track() const
1795 return boost::dynamic_pointer_cast<Track>(_route);
1799 RouteUI::is_audio_track () const
1801 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1804 boost::shared_ptr<AudioTrack>
1805 RouteUI::audio_track() const
1807 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1811 RouteUI::is_midi_track () const
1813 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1816 boost::shared_ptr<MidiTrack>
1817 RouteUI::midi_track() const
1819 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1823 RouteUI::has_audio_outputs () const
1825 return (_route->n_outputs().n_audio() > 0);
1829 RouteUI::name() const
1831 return _route->name();
1835 RouteUI::map_frozen ()
1837 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1839 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1842 switch (at->freeze_state()) {
1843 case AudioTrack::Frozen:
1844 rec_enable_button->set_sensitive (false);
1847 rec_enable_button->set_sensitive (true);
1854 RouteUI::adjust_latency ()
1856 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1860 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1863 std::string safe_name;
1866 prompter.get_result (name, true);
1868 safe_name = legalize_for_path (name);
1869 safe_name += template_suffix;
1871 path = Glib::build_filename (dir, safe_name);
1873 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1874 bool overwrite = overwrite_file_dialog (prompter,
1875 _("Confirm Template Overwrite"),
1876 _("A template already exists with that name. Do you want to overwrite it?"));
1883 _route->save_as_template (path, name);
1889 RouteUI::save_as_template ()
1893 dir = ARDOUR::user_route_template_directory ();
1895 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1896 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1900 ArdourPrompter prompter (true); // modal
1902 prompter.set_title (_("Save As Template"));
1903 prompter.set_prompt (_("Template name:"));
1904 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1906 bool finished = false;
1908 switch (prompter.run()) {
1909 case RESPONSE_ACCEPT:
1910 finished = process_save_template_prompter (prompter, dir);
1920 RouteUI::check_rec_enable_sensitivity ()
1922 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1923 rec_enable_button->set_sensitive (false);
1925 rec_enable_button->set_sensitive (true);
1928 update_monitoring_display ();
1932 RouteUI::parameter_changed (string const & p)
1934 /* this handles RC and per-session parameter changes */
1936 if (p == "disable-disarm-during-roll") {
1937 check_rec_enable_sensitivity ();
1938 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1939 set_button_names ();
1940 } else if (p == "auto-input") {
1941 update_monitoring_display ();
1942 } else if (p == "blink-rec-arm") {
1943 if (UIConfiguration::instance().get_blink_rec_arm()) {
1944 rec_blink_connection.disconnect ();
1945 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1947 rec_blink_connection.disconnect ();
1948 RouteUI::blink_rec_display(false);
1954 RouteUI::step_gain_up ()
1956 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1960 RouteUI::page_gain_up ()
1962 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1966 RouteUI::step_gain_down ()
1968 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1972 RouteUI::page_gain_down ()
1974 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1978 RouteUI::open_remote_control_id_dialog ()
1980 ArdourDialog dialog (_("Remote Control ID"));
1981 SpinButton* spin = 0;
1983 dialog.get_vbox()->set_border_width (18);
1985 if (Config->get_remote_model() == UserOrdered) {
1986 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1988 HBox* hbox = manage (new HBox);
1989 hbox->set_spacing (6);
1990 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1991 spin = manage (new SpinButton);
1992 spin->set_digits (0);
1993 spin->set_increments (1, 10);
1994 spin->set_range (0, limit);
1995 spin->set_value (_route->remote_control_id());
1996 hbox->pack_start (*spin);
1997 dialog.get_vbox()->pack_start (*hbox);
1999 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2000 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2002 Label* l = manage (new Label());
2003 if (_route->is_master() || _route->is_monitor()) {
2004 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2005 "The remote control ID of %3 cannot be changed."),
2006 Gtkmm2ext::markup_escape_text (_route->name()),
2007 _route->remote_control_id(),
2008 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2010 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2011 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2012 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2013 (is_track() ? _("track") : _("bus")),
2014 _route->remote_control_id(),
2015 "<span size=\"small\" style=\"italic\">",
2017 Gtkmm2ext::markup_escape_text (_route->name()),
2020 dialog.get_vbox()->pack_start (*l);
2021 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2025 int const r = dialog.run ();
2027 if (r == RESPONSE_ACCEPT && spin) {
2028 _route->set_remote_control_id (spin->get_value_as_int ());
2033 RouteUI::setup_invert_buttons ()
2035 /* remove old invert buttons */
2036 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2037 _invert_button_box.remove (**i);
2040 _invert_buttons.clear ();
2042 if (!_route || !_route->input()) {
2046 uint32_t const N = _route->input()->n_ports().n_audio ();
2048 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2050 for (uint32_t i = 0; i < to_add; ++i) {
2051 ArdourButton* b = manage (new ArdourButton);
2052 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2053 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2055 b->set_name (X_("invert button"));
2058 b->set_text (string_compose (X_("Ø (%1)"), N));
2060 b->set_text (X_("Ø"));
2063 b->set_text (string_compose (X_("Ø%1"), i + 1));
2066 if (N <= _max_invert_buttons) {
2067 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));
2069 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2072 _invert_buttons.push_back (b);
2073 _invert_button_box.pack_start (*b);
2076 _invert_button_box.set_spacing (1);
2077 _invert_button_box.show_all ();
2081 RouteUI::set_invert_button_state ()
2083 uint32_t const N = _route->input()->n_ports().n_audio();
2084 if (N > _max_invert_buttons) {
2086 /* One button for many channels; explicit active if all channels are inverted,
2087 implicit active if some are, off if none are.
2090 ArdourButton* b = _invert_buttons.front ();
2092 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2093 b->set_active_state (Gtkmm2ext::ExplicitActive);
2094 } else if (_route->phase_invert().any()) {
2095 b->set_active_state (Gtkmm2ext::ImplicitActive);
2097 b->set_active_state (Gtkmm2ext::Off);
2102 /* One button per channel; just set active */
2105 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2106 (*i)->set_active (_route->phase_invert (j));
2113 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2115 if (ev->button == 1 && i < _invert_buttons.size()) {
2116 uint32_t const N = _route->input()->n_ports().n_audio ();
2117 if (N <= _max_invert_buttons) {
2118 /* left-click inverts phase so long as we have a button per channel */
2119 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2128 RouteUI::invert_press (GdkEventButton* ev)
2130 using namespace Menu_Helpers;
2132 uint32_t const N = _route->input()->n_ports().n_audio();
2133 if (N <= _max_invert_buttons && ev->button != 3) {
2134 /* If we have an invert button per channel, we only pop
2135 up a menu on right-click; left click is handled
2141 delete _invert_menu;
2142 _invert_menu = new Menu;
2143 _invert_menu->set_name ("ArdourContextMenu");
2144 MenuList& items = _invert_menu->items ();
2146 for (uint32_t i = 0; i < N; ++i) {
2147 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2148 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2149 ++_i_am_the_modifier;
2150 e->set_active (_route->phase_invert (i));
2151 --_i_am_the_modifier;
2154 _invert_menu->popup (0, ev->time);
2160 RouteUI::invert_menu_toggled (uint32_t c)
2162 if (_i_am_the_modifier) {
2166 _route->set_phase_invert (c, !_route->phase_invert (c));
2170 RouteUI::set_invert_sensitive (bool yn)
2172 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2173 (*b)->set_sensitive (yn);
2178 RouteUI::request_redraw ()
2181 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2185 /** The Route's gui_changed signal has been emitted */
2187 RouteUI::route_gui_changed (string what_changed)
2189 if (what_changed == "color") {
2190 if (set_color_from_route () == 0) {
2191 route_color_changed ();
2197 RouteUI::track_mode_changed (void)
2200 switch (track()->mode()) {
2201 case ARDOUR::NonLayered:
2202 case ARDOUR::Normal:
2203 rec_enable_button->set_icon (ArdourIcon::RecButton);
2205 case ARDOUR::Destructive:
2206 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2209 rec_enable_button->queue_draw();
2212 /** @return the color that this route should use; it maybe its own,
2213 or it maybe that of its route group.
2216 RouteUI::color () const
2218 RouteGroup* g = _route->route_group ();
2220 if (g && g->is_color()) {
2222 set_color_from_rgba (c, GroupTabs::group_color (g));
2230 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2232 _showing_sends_to = send_to;
2233 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2237 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2239 if (_route == send_to) {
2240 show_sends_button->set_active (true);
2241 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2243 show_sends_button->set_active (false);
2244 send_blink_connection.disconnect ();
2249 RouteUI::route_group() const
2251 return _route->route_group();