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) {
613 if (ARDOUR::Profile->get_mixbus() && _route->route_group()) {
615 rl = _route->route_group()->route_list();
618 _solo_release->routes = rl;
621 rl.reset (new RouteList);
622 rl->push_back (_route);
626 if (Config->get_solo_control_is_listen_control()) {
627 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
629 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
633 delete _solo_release;
638 /* click: solo this route */
640 boost::shared_ptr<RouteList> rl (new RouteList);
641 rl->push_back (route());
644 _solo_release->routes = rl;
648 if (Config->get_solo_control_is_listen_control()) {
649 _session->set_listen (rl, !_route->listening_via_monitor());
651 _session->set_solo (rl, !_route->self_soloed());
661 RouteUI::solo_release (GdkEventButton* /*ev*/)
665 if (_solo_release->exclusive) {
669 if (Config->get_solo_control_is_listen_control()) {
670 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
672 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
676 delete _solo_release;
684 RouteUI::rec_enable_press(GdkEventButton* ev)
686 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
690 //if this is a binding action, let the ArdourButton handle it
691 if ( BindingProxy::is_bind_action(ev) )
694 if (!_session->engine().connected()) {
695 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
700 if (is_midi_track()) {
702 /* rec-enable button exits from step editing */
704 if (midi_track()->step_editing()) {
705 midi_track()->set_step_editing (false);
710 if (is_track() && rec_enable_button) {
712 if (Keyboard::is_button2_event (ev)) {
714 //rec arm does not have a momentary mode
717 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
720 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
722 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
724 /* Primary-button1 applies change to the route group (even if it is not active)
725 NOTE: Primary-button2 is MIDI learn.
728 if (ev->button == 1) {
730 boost::shared_ptr<RouteList> rl;
732 if (_route->route_group()) {
734 rl = _route->route_group()->route_list();
737 rl.reset (new RouteList);
738 rl->push_back (_route);
742 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
745 } else if (Keyboard::is_context_menu_event (ev)) {
747 /* do this on release */
751 boost::shared_ptr<RouteList> rl (new RouteList);
752 rl->push_back (route());
754 _session->set_record_enabled (rl, !_route->record_enabled());
762 RouteUI::monitoring_changed ()
764 update_monitoring_display ();
768 RouteUI::update_monitoring_display ()
774 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
780 MonitorState ms = t->monitoring_state();
782 if (t->monitoring_choice() & MonitorInput) {
783 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
785 if (ms & MonitoringInput) {
786 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
788 monitor_input_button->unset_active_state ();
792 if (t->monitoring_choice() & MonitorDisk) {
793 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
795 if (ms & MonitoringDisk) {
796 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
798 monitor_disk_button->unset_active_state ();
804 RouteUI::monitor_input_press(GdkEventButton*)
810 RouteUI::monitor_input_release(GdkEventButton* ev)
812 return monitor_release (ev, MonitorInput);
816 RouteUI::monitor_disk_press (GdkEventButton*)
822 RouteUI::monitor_disk_release (GdkEventButton* ev)
824 return monitor_release (ev, MonitorDisk);
828 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
830 if (ev->button != 1) {
834 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
841 boost::shared_ptr<RouteList> rl;
843 /* XXX for now, monitoring choices are orthogonal. cue monitoring
844 will follow in 3.X but requires mixing the input and playback (disk)
845 signal together, which requires yet more buffers.
848 if (t->monitoring_choice() & monitor_choice) {
849 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
851 /* this line will change when the options are non-orthogonal */
852 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
856 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
857 rl = _session->get_routes ();
859 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
860 if (_route->route_group() && _route->route_group()->is_monitoring()) {
861 rl = _route->route_group()->route_list();
863 rl.reset (new RouteList);
864 rl->push_back (route());
867 rl.reset (new RouteList);
868 rl->push_back (route());
872 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
878 RouteUI::build_record_menu ()
884 /* no rec-button context menu for non-MIDI tracks
887 if (is_midi_track()) {
888 record_menu = new Menu;
889 record_menu->set_name ("ArdourContextMenu");
891 using namespace Menu_Helpers;
892 MenuList& items = record_menu->items();
894 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
895 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
897 if (_route->record_enabled()) {
898 step_edit_item->set_sensitive (false);
901 step_edit_item->set_active (midi_track()->step_editing());
906 RouteUI::toggle_step_edit ()
908 if (!is_midi_track() || _route->record_enabled()) {
912 midi_track()->set_step_editing (step_edit_item->get_active());
916 RouteUI::step_edit_changed (bool yn)
919 if (rec_enable_button) {
920 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
923 start_step_editing ();
925 if (step_edit_item) {
926 step_edit_item->set_active (true);
931 if (rec_enable_button) {
932 rec_enable_button->unset_active_state ();
935 stop_step_editing ();
937 if (step_edit_item) {
938 step_edit_item->set_active (false);
944 RouteUI::rec_enable_release (GdkEventButton* ev)
946 if (Keyboard::is_context_menu_event (ev)) {
947 build_record_menu ();
949 record_menu->popup (1, ev->time);
958 RouteUI::build_sends_menu ()
960 using namespace Menu_Helpers;
962 sends_menu = new Menu;
963 sends_menu->set_name ("ArdourContextMenu");
964 MenuList& items = sends_menu->items();
967 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
971 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
975 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
979 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
983 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
987 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
990 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
994 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
997 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
998 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
999 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1004 RouteUI::create_sends (Placement p, bool include_buses)
1006 _session->globally_add_internal_sends (_route, p, include_buses);
1010 RouteUI::create_selected_sends (Placement p, bool include_buses)
1012 boost::shared_ptr<RouteList> rlist (new RouteList);
1013 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1015 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1016 RouteTimeAxisView* rtv;
1018 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1019 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1020 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1021 rlist->push_back (rui->route());
1027 _session->add_internal_sends (_route, p, rlist);
1031 RouteUI::set_sends_gain_from_track ()
1033 _session->globally_set_send_gains_from_track (_route);
1037 RouteUI::set_sends_gain_to_zero ()
1039 _session->globally_set_send_gains_to_zero (_route);
1043 RouteUI::set_sends_gain_to_unity ()
1045 _session->globally_set_send_gains_to_unity (_route);
1049 RouteUI::show_sends_press(GdkEventButton* ev)
1051 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1055 if (!is_track() && show_sends_button) {
1057 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1059 // do nothing on midi sigc::bind event
1062 } else if (Keyboard::is_context_menu_event (ev)) {
1064 if (sends_menu == 0) {
1065 build_sends_menu ();
1068 sends_menu->popup (0, ev->time);
1072 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1075 set_showing_sends_to (boost::shared_ptr<Route> ());
1077 set_showing_sends_to (_route);
1086 RouteUI::show_sends_release (GdkEventButton*)
1092 RouteUI::send_blink (bool onoff)
1094 if (!show_sends_button) {
1099 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1101 show_sends_button->unset_active_state ();
1105 Gtkmm2ext::ActiveState
1106 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1108 if (r->is_master() || r->is_monitor()) {
1109 return Gtkmm2ext::Off;
1112 if (Config->get_solo_control_is_listen_control()) {
1114 if (r->listening_via_monitor()) {
1115 return Gtkmm2ext::ExplicitActive;
1117 return Gtkmm2ext::Off;
1123 if (!r->self_soloed()) {
1124 return Gtkmm2ext::ImplicitActive;
1126 return Gtkmm2ext::ExplicitActive;
1129 return Gtkmm2ext::Off;
1133 Gtkmm2ext::ActiveState
1134 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1136 if (r->is_master() || r->is_monitor()) {
1137 return Gtkmm2ext::Off;
1140 if (r->solo_isolated()) {
1141 return Gtkmm2ext::ExplicitActive;
1143 return Gtkmm2ext::Off;
1147 Gtkmm2ext::ActiveState
1148 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1150 if (r->is_master() || r->is_monitor()) {
1151 return Gtkmm2ext::Off;
1154 if (r->solo_safe()) {
1155 return Gtkmm2ext::ExplicitActive;
1157 return Gtkmm2ext::Off;
1162 RouteUI::update_solo_display ()
1164 bool yn = _route->solo_safe ();
1166 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1167 solo_safe_check->set_active (yn);
1170 yn = _route->solo_isolated ();
1172 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1173 solo_isolated_check->set_active (yn);
1176 set_button_names ();
1178 if (solo_isolated_led) {
1179 if (_route->solo_isolated()) {
1180 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1182 solo_isolated_led->unset_active_state ();
1186 if (solo_safe_led) {
1187 if (_route->solo_safe()) {
1188 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1190 solo_safe_led->unset_active_state ();
1194 solo_button->set_active_state (solo_active_state (_route));
1196 /* some changes to solo status can affect mute display, so catch up
1199 update_mute_display ();
1203 RouteUI::solo_changed_so_update_mute ()
1205 update_mute_display ();
1209 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1211 if (r->is_monitor()) {
1212 return ActiveState(0);
1216 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1220 return Gtkmm2ext::ExplicitActive;
1221 } else if (r->muted_by_others()) {
1222 return Gtkmm2ext::ImplicitActive;
1224 /* no mute at all */
1225 return Gtkmm2ext::Off;
1232 return Gtkmm2ext::ExplicitActive;
1234 /* no mute at all */
1235 return Gtkmm2ext::Off;
1239 return ActiveState(0);
1243 RouteUI::update_mute_display ()
1249 mute_button->set_active_state (mute_active_state (_session, _route));
1253 RouteUI::route_rec_enable_changed ()
1255 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1256 update_monitoring_display ();
1260 RouteUI::session_rec_enable_changed ()
1262 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1263 update_monitoring_display ();
1267 RouteUI::blink_rec_display (bool blinkOn)
1269 if (!rec_enable_button || !_route) {
1272 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1276 if (_route->record_enabled()) {
1277 switch (_session->record_status ()) {
1278 case Session::Recording:
1279 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1282 case Session::Disabled:
1283 case Session::Enabled:
1284 if ( UIConfiguration::instance().get_blink_rec_arm() )
1285 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1287 rec_enable_button->set_active_state ( ImplicitActive );
1292 if (step_edit_item) {
1293 step_edit_item->set_sensitive (false);
1297 rec_enable_button->unset_active_state ();
1299 if (step_edit_item) {
1300 step_edit_item->set_sensitive (true);
1305 check_rec_enable_sensitivity ();
1309 RouteUI::build_solo_menu (void)
1311 using namespace Menu_Helpers;
1313 solo_menu = new Menu;
1314 solo_menu->set_name ("ArdourContextMenu");
1315 MenuList& items = solo_menu->items();
1316 Gtk::CheckMenuItem* check;
1318 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1319 check->set_active (_route->solo_isolated());
1320 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1321 items.push_back (CheckMenuElem(*check));
1322 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1325 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1326 check->set_active (_route->solo_safe());
1327 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1328 items.push_back (CheckMenuElem(*check));
1329 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1332 //items.push_back (SeparatorElem());
1333 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1338 RouteUI::build_mute_menu(void)
1340 using namespace Menu_Helpers;
1342 mute_menu = new Menu;
1343 mute_menu->set_name ("ArdourContextMenu");
1345 MenuList& items = mute_menu->items();
1347 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1348 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1349 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1350 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1351 pre_fader_mute_check->show_all();
1353 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1354 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1355 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1356 items.push_back (CheckMenuElem(*post_fader_mute_check));
1357 post_fader_mute_check->show_all();
1359 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1360 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1361 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1362 items.push_back (CheckMenuElem(*listen_mute_check));
1363 listen_mute_check->show_all();
1365 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1366 init_mute_menu(MuteMaster::Main, main_mute_check);
1367 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1368 items.push_back (CheckMenuElem(*main_mute_check));
1369 main_mute_check->show_all();
1371 //items.push_back (SeparatorElem());
1372 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1374 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1378 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1380 check->set_active (_route->mute_points() & mp);
1384 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1386 if (check->get_active()) {
1387 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1389 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1394 RouteUI::muting_change ()
1396 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1399 MuteMaster::MutePoint current = _route->mute_points ();
1401 yn = (current & MuteMaster::PreFader);
1403 if (pre_fader_mute_check->get_active() != yn) {
1404 pre_fader_mute_check->set_active (yn);
1407 yn = (current & MuteMaster::PostFader);
1409 if (post_fader_mute_check->get_active() != yn) {
1410 post_fader_mute_check->set_active (yn);
1413 yn = (current & MuteMaster::Listen);
1415 if (listen_mute_check->get_active() != yn) {
1416 listen_mute_check->set_active (yn);
1419 yn = (current & MuteMaster::Main);
1421 if (main_mute_check->get_active() != yn) {
1422 main_mute_check->set_active (yn);
1427 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1429 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1433 bool view = solo_isolated_led->active_state();
1434 bool model = _route->solo_isolated();
1436 /* called BEFORE the view has changed */
1438 if (ev->button == 1) {
1439 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1442 /* disable isolate for all routes */
1443 DisplaySuspender ds;
1444 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1446 /* enable isolate for all routes */
1447 DisplaySuspender ds;
1448 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1453 if (model == view) {
1455 /* flip just this route */
1457 boost::shared_ptr<RouteList> rl (new RouteList);
1458 rl->push_back (_route);
1459 DisplaySuspender ds;
1460 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1469 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1471 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1475 bool view = solo_safe_led->active_state();
1476 bool model = _route->solo_safe();
1478 if (ev->button == 1) {
1479 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1480 boost::shared_ptr<RouteList> rl (_session->get_routes());
1482 /* disable solo safe for all routes */
1483 DisplaySuspender ds;
1484 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1485 (*i)->set_solo_safe (false, Controllable::NoGroup);
1488 /* enable solo safe for all routes */
1489 DisplaySuspender ds;
1490 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1491 (*i)->set_solo_safe (true, Controllable::NoGroup);
1496 if (model == view) {
1497 /* flip just this route */
1498 _route->set_solo_safe (!view, Controllable::NoGroup);
1507 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1509 bool view = check->get_active();
1510 bool model = _route->solo_isolated();
1512 /* called AFTER the view has changed */
1514 if (model != view) {
1515 _route->set_solo_isolated (view, Controllable::UseGroup);
1520 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1522 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1525 /** Ask the user to choose a colour, and then apply that color to my route
1528 RouteUI::choose_color ()
1531 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1538 /** Set the route's own color. This may not be used for display if
1539 * the route is in a group which shares its color with its routes.
1542 RouteUI::set_color (const Gdk::Color & c)
1544 /* leave _color alone in the group case so that tracks can retain their
1545 * own pre-group colors.
1550 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1552 /* note: we use the route state ID here so that color is the same for both
1553 the time axis view and the mixer strip
1556 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1557 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1560 /** @return GUI state ID for things that are common to the route in all its representations */
1562 RouteUI::route_state_id () const
1564 return string_compose (X_("route %1"), _route->id().to_s());
1568 RouteUI::set_color_from_route ()
1570 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1578 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1581 _color.set_green (g);
1582 _color.set_blue (b);
1587 /** @return true if this name should be used for the route, otherwise false */
1589 RouteUI::verify_new_route_name (const std::string& name)
1591 if (name.find (':') == string::npos) {
1595 MessageDialog colon_msg (
1596 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1597 false, MESSAGE_QUESTION, BUTTONS_NONE
1600 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1601 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1603 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1607 RouteUI::route_rename ()
1609 ArdourPrompter name_prompter (true);
1614 name_prompter.set_title (_("Rename Track"));
1616 name_prompter.set_title (_("Rename Bus"));
1618 name_prompter.set_prompt (_("New name:"));
1619 name_prompter.set_initial_text (_route->name());
1620 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1621 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1622 name_prompter.show_all ();
1625 switch (name_prompter.run ()) {
1626 case Gtk::RESPONSE_ACCEPT:
1627 name_prompter.get_result (result);
1628 name_prompter.hide ();
1629 if (result.length()) {
1630 if (verify_new_route_name (result)) {
1631 _route->set_name (result);
1634 /* back to name prompter */
1638 /* nothing entered, just get out of here */
1653 RouteUI::property_changed (const PropertyChange& what_changed)
1655 if (what_changed.contains (ARDOUR::Properties::name)) {
1656 name_label.set_text (_route->name());
1661 RouteUI::toggle_comment_editor ()
1663 // if (ignore_toggle) {
1667 if (comment_window && comment_window->is_visible ()) {
1668 comment_window->hide ();
1670 open_comment_editor ();
1676 RouteUI::open_comment_editor ()
1678 if (comment_window == 0) {
1679 setup_comment_editor ();
1683 title = _route->name();
1684 title += _(": comment editor");
1686 comment_window->set_title (title);
1687 comment_window->present();
1691 RouteUI::setup_comment_editor ()
1693 comment_window = new ArdourWindow (""); // title will be reset to show route
1694 comment_window->set_skip_taskbar_hint (true);
1695 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1696 comment_window->set_default_size (400, 200);
1698 comment_area = manage (new TextView());
1699 comment_area->set_name ("MixerTrackCommentArea");
1700 comment_area->set_wrap_mode (WRAP_WORD);
1701 comment_area->set_editable (true);
1702 comment_area->get_buffer()->set_text (_route->comment());
1703 comment_area->show ();
1705 comment_window->add (*comment_area);
1709 RouteUI::comment_changed ()
1711 ignore_comment_edit = true;
1713 comment_area->get_buffer()->set_text (_route->comment());
1715 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), Controllable::UseGroup);
1956 RouteUI::page_gain_up ()
1958 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1962 RouteUI::step_gain_down ()
1964 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1968 RouteUI::page_gain_down ()
1970 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
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();