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"
43 #include "plugin_pin_dialog.h"
45 #include "gui_thread.h"
46 #include "ardour_dialog.h"
47 #include "latency_gui.h"
48 #include "mixer_strip.h"
49 #include "automation_time_axis.h"
50 #include "route_time_axis.h"
51 #include "group_tabs.h"
53 #include "ui_config.h"
55 #include "ardour/audio_track.h"
56 #include "ardour/audioengine.h"
57 #include "ardour/filename_extensions.h"
58 #include "ardour/midi_track.h"
59 #include "ardour/internal_send.h"
60 #include "ardour/profile.h"
61 #include "ardour/send.h"
62 #include "ardour/route.h"
63 #include "ardour/session.h"
64 #include "ardour/template_utils.h"
68 using namespace Gtkmm2ext;
69 using namespace ARDOUR;
70 using namespace ARDOUR_UI_UTILS;
74 uint32_t RouteUI::_max_invert_buttons = 3;
75 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
76 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
77 std::string RouteUI::program_port_prefix;
79 RouteUI::RouteUI (ARDOUR::Session* sess)
91 if (program_port_prefix.empty()) {
92 // compare to gtk2_ardour/port_group.cc
93 string lpn (PROGRAM_NAME);
94 boost::to_lower (lpn);
95 program_port_prefix = lpn + ":"; // e.g. "ardour:"
103 gui_object_state().remove_node (route_state_id());
106 _route.reset (); /* drop reference to route, so that it can be cleaned up */
107 route_connections.drop_connections ();
113 delete comment_window;
114 delete input_selector;
115 delete output_selector;
118 send_blink_connection.disconnect ();
119 rec_blink_connection.disconnect ();
125 self_destruct = true;
131 pre_fader_mute_check = 0;
132 post_fader_mute_check = 0;
133 listen_mute_check = 0;
136 solo_isolated_check = 0;
137 solo_isolated_led = 0;
141 denormal_menu_item = 0;
144 multiple_mute_change = false;
145 multiple_solo_change = false;
146 _i_am_the_modifier = 0;
152 setup_invert_buttons ();
154 mute_button = manage (new ArdourButton);
155 mute_button->set_name ("mute button");
156 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
158 solo_button = manage (new ArdourButton);
159 solo_button->set_name ("solo button");
160 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
161 solo_button->set_no_show_all (true);
163 rec_enable_button = manage (new ArdourButton);
164 rec_enable_button->set_name ("record enable button");
165 rec_enable_button->set_icon (ArdourIcon::RecButton);
166 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
168 if (UIConfiguration::instance().get_blink_rec_arm()) {
169 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
172 show_sends_button = manage (new ArdourButton);
173 show_sends_button->set_name ("send alert button");
174 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
176 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
177 monitor_input_button->set_name ("monitor button");
178 monitor_input_button->set_text (_("In"));
179 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
180 monitor_input_button->set_no_show_all (true);
182 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
183 monitor_disk_button->set_name ("monitor button");
184 monitor_disk_button->set_text (_("Disk"));
185 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
186 monitor_disk_button->set_no_show_all (true);
188 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
189 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
190 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
192 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
193 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
195 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
196 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
198 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
199 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
201 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
202 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
203 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
204 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
206 monitor_input_button->set_distinct_led_click (false);
207 monitor_disk_button->set_distinct_led_click (false);
209 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
210 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
212 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
213 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
215 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
221 route_connections.drop_connections ();
229 denormal_menu_item = 0;
233 RouteUI::self_delete ()
239 RouteUI::set_route (boost::shared_ptr<Route> rp)
245 if (set_color_from_route()) {
246 set_color (unique_random_color());
250 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
253 delete input_selector;
256 delete output_selector;
259 mute_button->set_controllable (_route->mute_control());
260 solo_button->set_controllable (_route->solo_control());
262 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
263 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
265 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
267 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
268 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
269 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
270 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
272 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
273 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
274 track_mode_changed();
277 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
278 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
280 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
281 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
283 if (_session->writable() && is_track()) {
284 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
286 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
287 t->RecordSafeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
289 rec_enable_button->show();
290 rec_enable_button->set_controllable (t->rec_enable_control());
292 if (is_midi_track()) {
293 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
294 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
299 /* this will work for busses and tracks, and needs to be called to
300 set up the name entry/name label display.
304 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
305 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
307 update_monitoring_display ();
310 mute_button->unset_flags (Gtk::CAN_FOCUS);
311 solo_button->unset_flags (Gtk::CAN_FOCUS);
315 if (_route->is_monitor() || _route->is_master()) {
316 solo_button->hide ();
323 setup_invert_buttons ();
324 set_invert_button_state ();
326 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
327 bus_send_display_changed (s);
329 update_mute_display ();
330 update_solo_display ();
332 if (!UIConfiguration::instance().get_blink_rec_arm()) {
333 blink_rec_display(true); // set initial rec-en button state
336 check_rec_enable_sensitivity ();
337 maybe_add_route_print_mgr ();
338 route_color_changed();
342 RouteUI::polarity_changed ()
348 set_invert_button_state ();
352 RouteUI::mute_press (GdkEventButton* ev)
354 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
358 //if this is a binding action, let the ArdourButton handle it
359 if ( BindingProxy::is_bind_action(ev) )
362 multiple_mute_change = false;
364 if (Keyboard::is_context_menu_event (ev)) {
370 mute_menu->popup(0,ev->time);
376 if (Keyboard::is_button2_event (ev)) {
377 // button2-click is "momentary"
379 _mute_release = new SoloMuteRelease (_route->muted ());
382 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
384 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
386 /* toggle mute on everything (but
387 * exclude the master and monitor)
389 * because we are going to erase
390 * elements of the list we need to work
394 boost::shared_ptr<RouteList> copy (new RouteList);
396 *copy = *_session->get_routes ();
398 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
399 if ((*i)->is_master() || (*i)->is_monitor()) {
407 _mute_release->routes = copy;
411 _session->set_mute (copy, !_route->muted());
413 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
415 /* Primary-button1 inverts the implication of
416 the group being active. If the group is
417 active (for mute), then this modifier means
418 "do not apply to mute". If the group is
419 inactive (for mute), then this modifier
420 means "apply to route". This is all
421 accomplished by passing just the actual
422 route, along with the InverseGroup group
425 NOTE: Primary-button2 is MIDI learn.
428 boost::shared_ptr<RouteList> rl;
430 if (ev->button == 1) {
432 rl.reset (new RouteList);
433 rl->push_back (_route);
436 _mute_release->routes = rl;
440 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
445 /* plain click applies change to this route */
447 boost::shared_ptr<RouteList> rl (new RouteList);
448 rl->push_back (_route);
451 _mute_release->routes = rl;
454 _session->set_mute (rl, !_route->muted());
464 RouteUI::mute_release (GdkEventButton* /*ev*/)
468 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
469 delete _mute_release;
477 RouteUI::edit_output_configuration ()
479 if (output_selector == 0) {
481 boost::shared_ptr<Send> send;
482 boost::shared_ptr<IO> output;
484 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
485 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
486 output = send->output();
488 output = _route->output ();
491 output = _route->output ();
494 output_selector = new IOSelectorWindow (_session, output);
497 if (output_selector->is_visible()) {
498 output_selector->get_toplevel()->get_window()->raise();
500 output_selector->present ();
503 //output_selector->set_keep_above (true);
507 RouteUI::edit_input_configuration ()
509 if (input_selector == 0) {
510 input_selector = new IOSelectorWindow (_session, _route->input());
513 if (input_selector->is_visible()) {
514 input_selector->get_toplevel()->get_window()->raise();
516 input_selector->present ();
519 //input_selector->set_keep_above (true);
523 RouteUI::solo_press(GdkEventButton* ev)
525 /* ignore double/triple clicks */
527 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
531 //if this is a binding action, let the ArdourButton handle it
532 if ( BindingProxy::is_bind_action(ev) )
535 multiple_solo_change = false;
537 if (Keyboard::is_context_menu_event (ev)) {
539 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
540 ! (solo_safe_led && solo_safe_led->is_visible())) {
542 if (solo_menu == 0) {
546 solo_menu->popup (1, ev->time);
551 if (Keyboard::is_button2_event (ev)) {
553 // button2-click is "momentary"
554 _solo_release = new SoloMuteRelease (_route->self_soloed());
557 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
559 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
561 /* Primary-Tertiary-click applies change to all routes */
564 _solo_release->routes = _session->get_routes ();
568 if (Config->get_solo_control_is_listen_control()) {
569 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::UseGroup);
571 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, Controllable::UseGroup);
574 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
576 // Primary-Secondary-click: exclusively solo this track
579 _solo_release->exclusive = true;
581 boost::shared_ptr<RouteList> routes = _session->get_routes();
583 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
584 if ((*i)->soloed ()) {
585 _solo_release->routes_on->push_back (*i);
587 _solo_release->routes_off->push_back (*i);
592 if (Config->get_solo_control_is_listen_control()) {
593 /* ??? we need a just_one_listen() method */
596 _session->set_just_one_solo (_route, true);
599 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
601 // shift-click: toggle solo isolated status
603 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
604 delete _solo_release;
607 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
609 /* Primary-button1: solo mix group.
610 NOTE: Primary-button2 is MIDI learn.
613 /* Primary-button1 applies change to the mix group even if it is not active
614 NOTE: Primary-button2 is MIDI learn.
617 boost::shared_ptr<RouteList> rl;
619 if (ev->button == 1) {
621 /* Primary-button1 inverts the implication of
622 the group being active. If the group is
623 active (for solo), then this modifier means
624 "do not apply to solo". If the group is
625 inactive (for mute), then this modifier
626 means "apply to route". This is all
627 accomplished by passing just the actual
628 route, along with the InverseGroup group
631 NOTE: Primary-button2 is MIDI learn.
634 rl.reset (new RouteList);
635 rl->push_back (_route);
638 _solo_release->routes = rl;
643 if (Config->get_solo_control_is_listen_control()) {
644 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
646 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
650 delete _solo_release;
655 /* click: solo this route */
657 boost::shared_ptr<RouteList> rl (new RouteList);
658 rl->push_back (route());
661 _solo_release->routes = rl;
665 if (Config->get_solo_control_is_listen_control()) {
666 _session->set_listen (rl, !_route->listening_via_monitor());
668 _session->set_solo (rl, !_route->self_soloed());
678 RouteUI::solo_release (GdkEventButton* /*ev*/)
682 if (_solo_release->exclusive) {
686 if (Config->get_solo_control_is_listen_control()) {
687 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
689 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
693 delete _solo_release;
701 RouteUI::rec_enable_press(GdkEventButton* ev)
703 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
707 //if this is a binding action, let the ArdourButton handle it
708 if ( BindingProxy::is_bind_action(ev) )
711 if (!_session->engine().connected()) {
712 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
717 if (is_midi_track()) {
719 /* rec-enable button exits from step editing */
721 if (midi_track()->step_editing()) {
722 midi_track()->set_step_editing (false);
727 if (is_track() && rec_enable_button) {
729 if (Keyboard::is_button2_event (ev)) {
731 //rec arm does not have a momentary mode
734 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
737 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
739 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
741 /* Primary-button1 applies change to the route group (even if it is not active)
742 NOTE: Primary-button2 is MIDI learn.
745 if (ev->button == 1) {
747 boost::shared_ptr<RouteList> rl;
749 rl.reset (new RouteList);
750 rl->push_back (_route);
753 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
756 } else if (Keyboard::is_context_menu_event (ev)) {
758 /* do this on release */
762 boost::shared_ptr<RouteList> rl (new RouteList);
763 rl->push_back (route());
765 _session->set_record_enabled (rl, !_route->record_enabled());
773 RouteUI::monitoring_changed ()
775 update_monitoring_display ();
779 RouteUI::update_monitoring_display ()
785 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
791 MonitorState ms = t->monitoring_state();
793 if (t->monitoring_choice() & MonitorInput) {
794 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
796 if (ms & MonitoringInput) {
797 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
799 monitor_input_button->unset_active_state ();
803 if (t->monitoring_choice() & MonitorDisk) {
804 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
806 if (ms & MonitoringDisk) {
807 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
809 monitor_disk_button->unset_active_state ();
815 RouteUI::monitor_input_press(GdkEventButton*)
821 RouteUI::monitor_input_release(GdkEventButton* ev)
823 return monitor_release (ev, MonitorInput);
827 RouteUI::monitor_disk_press (GdkEventButton*)
833 RouteUI::monitor_disk_release (GdkEventButton* ev)
835 return monitor_release (ev, MonitorDisk);
839 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
841 if (ev->button != 1) {
845 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
852 boost::shared_ptr<RouteList> rl;
854 /* XXX for now, monitoring choices are orthogonal. cue monitoring
855 will follow in 3.X but requires mixing the input and playback (disk)
856 signal together, which requires yet more buffers.
859 if (t->monitoring_choice() & monitor_choice) {
860 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
862 /* this line will change when the options are non-orthogonal */
863 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
867 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
868 rl = _session->get_routes ();
870 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
871 if (_route->route_group() && _route->route_group()->is_monitoring()) {
872 rl = _route->route_group()->route_list();
874 rl.reset (new RouteList);
875 rl->push_back (route());
878 rl.reset (new RouteList);
879 rl->push_back (route());
883 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
889 RouteUI::build_record_menu ()
892 record_menu = new Menu;
893 record_menu->set_name ("ArdourContextMenu");
894 using namespace Menu_Helpers;
895 MenuList& items = record_menu->items();
897 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
898 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
900 if (is_midi_track()) {
901 items.push_back (SeparatorElem());
902 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
903 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
907 if (step_edit_item) {
908 step_edit_item->set_sensitive (!_route->record_enabled());
909 step_edit_item->set_active (midi_track()->step_editing());
912 rec_safe_item->set_sensitive (!_route->record_enabled());
913 rec_safe_item->set_active (_route->record_safe());
918 RouteUI::toggle_step_edit ()
920 if (!is_midi_track() || _route->record_enabled()) {
924 midi_track()->set_step_editing (step_edit_item->get_active());
928 RouteUI::toggle_rec_safe ()
930 if (_route->record_enabled()) {
934 boost::shared_ptr<RouteList> rl (new RouteList);
935 rl->push_back (_route);
936 _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
940 RouteUI::step_edit_changed (bool yn)
943 if (rec_enable_button) {
944 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
947 start_step_editing ();
949 if (step_edit_item) {
950 step_edit_item->set_active (true);
955 if (rec_enable_button) {
956 rec_enable_button->unset_active_state ();
959 stop_step_editing ();
961 if (step_edit_item) {
962 step_edit_item->set_active (false);
968 RouteUI::rec_enable_release (GdkEventButton* ev)
970 if (Keyboard::is_context_menu_event (ev)) {
971 build_record_menu ();
973 record_menu->popup (1, ev->time);
982 RouteUI::build_sends_menu ()
984 using namespace Menu_Helpers;
986 sends_menu = new Menu;
987 sends_menu->set_name ("ArdourContextMenu");
988 MenuList& items = sends_menu->items();
991 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
995 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
999 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1003 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1007 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1011 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1014 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1018 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1021 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1022 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1023 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1028 RouteUI::create_sends (Placement p, bool include_buses)
1030 _session->globally_add_internal_sends (_route, p, include_buses);
1034 RouteUI::create_selected_sends (Placement p, bool include_buses)
1036 boost::shared_ptr<RouteList> rlist (new RouteList);
1037 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1039 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1040 RouteTimeAxisView* rtv;
1042 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1043 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1044 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1045 rlist->push_back (rui->route());
1051 _session->add_internal_sends (_route, p, rlist);
1055 RouteUI::set_sends_gain_from_track ()
1057 _session->globally_set_send_gains_from_track (_route);
1061 RouteUI::set_sends_gain_to_zero ()
1063 _session->globally_set_send_gains_to_zero (_route);
1067 RouteUI::set_sends_gain_to_unity ()
1069 _session->globally_set_send_gains_to_unity (_route);
1073 RouteUI::show_sends_press(GdkEventButton* ev)
1075 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1079 if (!is_track() && show_sends_button) {
1081 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1083 // do nothing on midi sigc::bind event
1086 } else if (Keyboard::is_context_menu_event (ev)) {
1088 if (sends_menu == 0) {
1089 build_sends_menu ();
1092 sends_menu->popup (0, ev->time);
1096 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1099 set_showing_sends_to (boost::shared_ptr<Route> ());
1101 set_showing_sends_to (_route);
1110 RouteUI::show_sends_release (GdkEventButton*)
1116 RouteUI::send_blink (bool onoff)
1118 if (!show_sends_button) {
1123 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1125 show_sends_button->unset_active_state ();
1129 Gtkmm2ext::ActiveState
1130 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1132 if (r->is_master() || r->is_monitor()) {
1133 return Gtkmm2ext::Off;
1136 if (Config->get_solo_control_is_listen_control()) {
1138 if (r->listening_via_monitor()) {
1139 return Gtkmm2ext::ExplicitActive;
1141 return Gtkmm2ext::Off;
1147 if (!r->self_soloed()) {
1148 return Gtkmm2ext::ImplicitActive;
1150 return Gtkmm2ext::ExplicitActive;
1153 return Gtkmm2ext::Off;
1157 Gtkmm2ext::ActiveState
1158 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1160 if (r->is_master() || r->is_monitor()) {
1161 return Gtkmm2ext::Off;
1164 if (r->solo_isolated()) {
1165 return Gtkmm2ext::ExplicitActive;
1167 return Gtkmm2ext::Off;
1171 Gtkmm2ext::ActiveState
1172 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1174 if (r->is_master() || r->is_monitor()) {
1175 return Gtkmm2ext::Off;
1178 if (r->solo_safe()) {
1179 return Gtkmm2ext::ExplicitActive;
1181 return Gtkmm2ext::Off;
1186 RouteUI::update_solo_display ()
1188 bool yn = _route->solo_safe ();
1190 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1191 solo_safe_check->set_active (yn);
1194 yn = _route->solo_isolated ();
1196 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1197 solo_isolated_check->set_active (yn);
1200 set_button_names ();
1202 if (solo_isolated_led) {
1203 if (_route->solo_isolated()) {
1204 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1206 solo_isolated_led->unset_active_state ();
1210 if (solo_safe_led) {
1211 if (_route->solo_safe()) {
1212 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1214 solo_safe_led->unset_active_state ();
1218 solo_button->set_active_state (solo_active_state (_route));
1220 /* some changes to solo status can affect mute display, so catch up
1223 update_mute_display ();
1227 RouteUI::solo_changed_so_update_mute ()
1229 update_mute_display ();
1233 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1235 if (r->is_monitor()) {
1236 return ActiveState(0);
1240 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1244 return Gtkmm2ext::ExplicitActive;
1245 } else if (r->muted_by_others()) {
1246 return Gtkmm2ext::ImplicitActive;
1248 /* no mute at all */
1249 return Gtkmm2ext::Off;
1256 return Gtkmm2ext::ExplicitActive;
1258 /* no mute at all */
1259 return Gtkmm2ext::Off;
1263 return ActiveState(0);
1267 RouteUI::update_mute_display ()
1273 mute_button->set_active_state (mute_active_state (_session, _route));
1277 RouteUI::route_rec_enable_changed ()
1279 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1280 update_monitoring_display ();
1284 RouteUI::session_rec_enable_changed ()
1286 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1287 update_monitoring_display ();
1291 RouteUI::blink_rec_display (bool blinkOn)
1293 if (!rec_enable_button || !_route) {
1296 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1300 if (_route->record_enabled()) {
1301 switch (_session->record_status ()) {
1302 case Session::Recording:
1303 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1306 case Session::Disabled:
1307 case Session::Enabled:
1308 if ( UIConfiguration::instance().get_blink_rec_arm() )
1309 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1311 rec_enable_button->set_active_state ( ImplicitActive );
1316 if (step_edit_item) {
1317 step_edit_item->set_sensitive (false);
1321 rec_enable_button->unset_active_state ();
1323 if (step_edit_item) {
1324 step_edit_item->set_sensitive (true);
1328 check_rec_enable_sensitivity ();
1332 RouteUI::build_solo_menu (void)
1334 using namespace Menu_Helpers;
1336 solo_menu = new Menu;
1337 solo_menu->set_name ("ArdourContextMenu");
1338 MenuList& items = solo_menu->items();
1339 Gtk::CheckMenuItem* check;
1341 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1342 check->set_active (_route->solo_isolated());
1343 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1344 items.push_back (CheckMenuElem(*check));
1345 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1348 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1349 check->set_active (_route->solo_safe());
1350 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1351 items.push_back (CheckMenuElem(*check));
1352 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1355 //items.push_back (SeparatorElem());
1356 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1361 RouteUI::build_mute_menu(void)
1363 using namespace Menu_Helpers;
1365 mute_menu = new Menu;
1366 mute_menu->set_name ("ArdourContextMenu");
1368 MenuList& items = mute_menu->items();
1370 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1371 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1372 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1373 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1374 pre_fader_mute_check->show_all();
1376 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1377 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1378 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1379 items.push_back (CheckMenuElem(*post_fader_mute_check));
1380 post_fader_mute_check->show_all();
1382 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1383 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1384 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1385 items.push_back (CheckMenuElem(*listen_mute_check));
1386 listen_mute_check->show_all();
1388 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1389 init_mute_menu(MuteMaster::Main, main_mute_check);
1390 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1391 items.push_back (CheckMenuElem(*main_mute_check));
1392 main_mute_check->show_all();
1394 //items.push_back (SeparatorElem());
1395 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1397 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1401 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1403 check->set_active (_route->mute_points() & mp);
1407 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1409 if (check->get_active()) {
1410 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1412 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1417 RouteUI::muting_change ()
1419 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1422 MuteMaster::MutePoint current = _route->mute_points ();
1424 yn = (current & MuteMaster::PreFader);
1426 if (pre_fader_mute_check->get_active() != yn) {
1427 pre_fader_mute_check->set_active (yn);
1430 yn = (current & MuteMaster::PostFader);
1432 if (post_fader_mute_check->get_active() != yn) {
1433 post_fader_mute_check->set_active (yn);
1436 yn = (current & MuteMaster::Listen);
1438 if (listen_mute_check->get_active() != yn) {
1439 listen_mute_check->set_active (yn);
1442 yn = (current & MuteMaster::Main);
1444 if (main_mute_check->get_active() != yn) {
1445 main_mute_check->set_active (yn);
1450 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1452 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1456 bool view = solo_isolated_led->active_state();
1457 bool model = _route->solo_isolated();
1459 /* called BEFORE the view has changed */
1461 if (ev->button == 1) {
1462 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1465 /* disable isolate for all routes */
1466 DisplaySuspender ds;
1467 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1469 /* enable isolate for all routes */
1470 DisplaySuspender ds;
1471 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1476 if (model == view) {
1478 /* flip just this route */
1480 boost::shared_ptr<RouteList> rl (new RouteList);
1481 rl->push_back (_route);
1482 DisplaySuspender ds;
1483 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1492 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1494 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1498 bool view = solo_safe_led->active_state();
1499 bool model = _route->solo_safe();
1501 if (ev->button == 1) {
1502 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1503 boost::shared_ptr<RouteList> rl (_session->get_routes());
1505 /* disable solo safe for all routes */
1506 DisplaySuspender ds;
1507 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1508 (*i)->set_solo_safe (false, Controllable::NoGroup);
1511 /* enable solo safe for all routes */
1512 DisplaySuspender ds;
1513 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1514 (*i)->set_solo_safe (true, Controllable::NoGroup);
1519 if (model == view) {
1520 /* flip just this route */
1521 _route->set_solo_safe (!view, Controllable::NoGroup);
1530 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1532 bool view = check->get_active();
1533 bool model = _route->solo_isolated();
1535 /* called AFTER the view has changed */
1537 if (model != view) {
1538 _route->set_solo_isolated (view, Controllable::UseGroup);
1543 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1545 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1548 /** Ask the user to choose a colour, and then apply that color to my route
1551 RouteUI::choose_color ()
1554 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1561 /** Set the route's own color. This may not be used for display if
1562 * the route is in a group which shares its color with its routes.
1565 RouteUI::set_color (const Gdk::Color & c)
1567 /* leave _color alone in the group case so that tracks can retain their
1568 * own pre-group colors.
1573 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1575 /* note: we use the route state ID here so that color is the same for both
1576 the time axis view and the mixer strip
1579 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1580 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1583 /** @return GUI state ID for things that are common to the route in all its representations */
1585 RouteUI::route_state_id () const
1587 return string_compose (X_("route %1"), _route->id().to_s());
1591 RouteUI::set_color_from_route ()
1593 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1601 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1604 _color.set_green (g);
1605 _color.set_blue (b);
1610 /** @return true if this name should be used for the route, otherwise false */
1612 RouteUI::verify_new_route_name (const std::string& name)
1614 if (name.find (':') == string::npos) {
1618 MessageDialog colon_msg (
1619 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1620 false, MESSAGE_QUESTION, BUTTONS_NONE
1623 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1624 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1626 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1630 RouteUI::route_rename ()
1632 ArdourPrompter name_prompter (true);
1637 name_prompter.set_title (_("Rename Track"));
1639 name_prompter.set_title (_("Rename Bus"));
1641 name_prompter.set_prompt (_("New name:"));
1642 name_prompter.set_initial_text (_route->name());
1643 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1644 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1645 name_prompter.show_all ();
1648 switch (name_prompter.run ()) {
1649 case Gtk::RESPONSE_ACCEPT:
1650 name_prompter.get_result (result);
1651 name_prompter.hide ();
1652 if (result.length()) {
1653 if (verify_new_route_name (result)) {
1654 _route->set_name (result);
1657 /* back to name prompter */
1661 /* nothing entered, just get out of here */
1676 RouteUI::property_changed (const PropertyChange& what_changed)
1678 if (what_changed.contains (ARDOUR::Properties::name)) {
1679 name_label.set_text (_route->name());
1684 RouteUI::toggle_comment_editor ()
1686 // if (ignore_toggle) {
1690 if (comment_window && comment_window->is_visible ()) {
1691 comment_window->hide ();
1693 open_comment_editor ();
1699 RouteUI::open_comment_editor ()
1701 if (comment_window == 0) {
1702 setup_comment_editor ();
1706 title = _route->name();
1707 title += _(": comment editor");
1709 comment_window->set_title (title);
1710 comment_window->present();
1714 RouteUI::setup_comment_editor ()
1716 comment_window = new ArdourWindow (""); // title will be reset to show route
1717 comment_window->set_skip_taskbar_hint (true);
1718 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1719 comment_window->set_default_size (400, 200);
1721 comment_area = manage (new TextView());
1722 comment_area->set_name ("MixerTrackCommentArea");
1723 comment_area->set_wrap_mode (WRAP_WORD);
1724 comment_area->set_editable (true);
1725 comment_area->get_buffer()->set_text (_route->comment());
1726 comment_area->show ();
1728 comment_window->add (*comment_area);
1732 RouteUI::comment_changed ()
1734 ignore_comment_edit = true;
1736 comment_area->get_buffer()->set_text (_route->comment());
1738 ignore_comment_edit = false;
1742 RouteUI::comment_editor_done_editing ()
1744 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1746 string const str = comment_area->get_buffer()->get_text();
1747 if (str == _route->comment ()) {
1751 _route->set_comment (str, this);
1755 RouteUI::set_route_active (bool a, bool apply_to_selection)
1757 if (apply_to_selection) {
1758 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1760 _route->set_active (a, this);
1765 RouteUI::duplicate_selected_routes ()
1767 ARDOUR_UI::instance()->start_duplicate_routes();
1771 RouteUI::toggle_denormal_protection ()
1773 if (denormal_menu_item) {
1777 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1779 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1780 _route->set_denormal_protection (x);
1786 RouteUI::denormal_protection_changed ()
1788 if (denormal_menu_item) {
1789 denormal_menu_item->set_active (_route->denormal_protection());
1794 RouteUI::disconnect_input ()
1796 _route->input()->disconnect (this);
1800 RouteUI::disconnect_output ()
1802 _route->output()->disconnect (this);
1806 RouteUI::is_track () const
1808 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1811 boost::shared_ptr<Track>
1812 RouteUI::track() const
1814 return boost::dynamic_pointer_cast<Track>(_route);
1818 RouteUI::is_audio_track () const
1820 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1823 boost::shared_ptr<AudioTrack>
1824 RouteUI::audio_track() const
1826 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1830 RouteUI::is_midi_track () const
1832 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1835 boost::shared_ptr<MidiTrack>
1836 RouteUI::midi_track() const
1838 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1842 RouteUI::has_audio_outputs () const
1844 return (_route->n_outputs().n_audio() > 0);
1848 RouteUI::name() const
1850 return _route->name();
1854 RouteUI::map_frozen ()
1856 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1858 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1861 check_rec_enable_sensitivity ();
1866 RouteUI::adjust_latency ()
1868 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1872 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1875 std::string safe_name;
1878 prompter.get_result (name, true);
1880 safe_name = legalize_for_path (name);
1881 safe_name += template_suffix;
1883 path = Glib::build_filename (dir, safe_name);
1885 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1886 bool overwrite = overwrite_file_dialog (prompter,
1887 _("Confirm Template Overwrite"),
1888 _("A template already exists with that name. Do you want to overwrite it?"));
1895 _route->save_as_template (path, name);
1901 RouteUI::save_as_template ()
1905 dir = ARDOUR::user_route_template_directory ();
1907 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1908 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1912 ArdourPrompter prompter (true); // modal
1914 prompter.set_title (_("Save As Template"));
1915 prompter.set_prompt (_("Template name:"));
1916 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1918 bool finished = false;
1920 switch (prompter.run()) {
1921 case RESPONSE_ACCEPT:
1922 finished = process_save_template_prompter (prompter, dir);
1932 RouteUI::check_rec_enable_sensitivity ()
1934 if (!rec_enable_button) {
1935 assert (0); // This should not happen
1938 if (!_session->writable()) {
1939 rec_enable_button->set_sensitive (false);
1943 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1944 rec_enable_button->set_sensitive (false);
1945 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1946 rec_enable_button->set_sensitive (false);
1948 rec_enable_button->set_sensitive (true);
1950 if (_route && _route->record_safe ()) {
1951 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1953 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1955 update_monitoring_display ();
1959 RouteUI::parameter_changed (string const & p)
1961 /* this handles RC and per-session parameter changes */
1963 if (p == "disable-disarm-during-roll") {
1964 check_rec_enable_sensitivity ();
1965 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1966 set_button_names ();
1967 } else if (p == "auto-input") {
1968 update_monitoring_display ();
1969 } else if (p == "blink-rec-arm") {
1970 if (UIConfiguration::instance().get_blink_rec_arm()) {
1971 rec_blink_connection.disconnect ();
1972 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1974 rec_blink_connection.disconnect ();
1975 RouteUI::blink_rec_display(false);
1981 RouteUI::step_gain_up ()
1983 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1987 RouteUI::page_gain_up ()
1989 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1993 RouteUI::step_gain_down ()
1995 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1999 RouteUI::page_gain_down ()
2001 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2005 RouteUI::open_remote_control_id_dialog ()
2007 ArdourDialog dialog (_("Remote Control ID"));
2008 SpinButton* spin = 0;
2010 dialog.get_vbox()->set_border_width (18);
2012 if (Config->get_remote_model() == UserOrdered) {
2013 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2015 HBox* hbox = manage (new HBox);
2016 hbox->set_spacing (6);
2017 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2018 spin = manage (new SpinButton);
2019 spin->set_digits (0);
2020 spin->set_increments (1, 10);
2021 spin->set_range (0, limit);
2022 spin->set_value (_route->remote_control_id());
2023 hbox->pack_start (*spin);
2024 dialog.get_vbox()->pack_start (*hbox);
2026 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2027 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2029 Label* l = manage (new Label());
2030 if (_route->is_master() || _route->is_monitor()) {
2031 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2032 "The remote control ID of %3 cannot be changed."),
2033 Gtkmm2ext::markup_escape_text (_route->name()),
2034 _route->remote_control_id(),
2035 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2037 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2038 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2039 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2040 (is_track() ? _("track") : _("bus")),
2041 _route->remote_control_id(),
2042 "<span size=\"small\" style=\"italic\">",
2044 Gtkmm2ext::markup_escape_text (_route->name()),
2047 dialog.get_vbox()->pack_start (*l);
2048 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2052 int const r = dialog.run ();
2054 if (r == RESPONSE_ACCEPT && spin) {
2055 _route->set_remote_control_id (spin->get_value_as_int ());
2060 RouteUI::setup_invert_buttons ()
2062 /* remove old invert buttons */
2063 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2064 _invert_button_box.remove (**i);
2067 _invert_buttons.clear ();
2069 if (!_route || !_route->input()) {
2073 uint32_t const N = _route->input()->n_ports().n_audio ();
2075 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2077 for (uint32_t i = 0; i < to_add; ++i) {
2078 ArdourButton* b = manage (new ArdourButton);
2079 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2080 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2082 b->set_name (X_("invert button"));
2085 b->set_text (string_compose (X_("Ø (%1)"), N));
2087 b->set_text (X_("Ø"));
2090 b->set_text (string_compose (X_("Ø%1"), i + 1));
2093 if (N <= _max_invert_buttons) {
2094 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));
2096 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2099 _invert_buttons.push_back (b);
2100 _invert_button_box.pack_start (*b);
2103 _invert_button_box.set_spacing (1);
2104 _invert_button_box.show_all ();
2108 RouteUI::set_invert_button_state ()
2110 uint32_t const N = _route->input()->n_ports().n_audio();
2111 if (N > _max_invert_buttons) {
2113 /* One button for many channels; explicit active if all channels are inverted,
2114 implicit active if some are, off if none are.
2117 ArdourButton* b = _invert_buttons.front ();
2119 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2120 b->set_active_state (Gtkmm2ext::ExplicitActive);
2121 } else if (_route->phase_invert().any()) {
2122 b->set_active_state (Gtkmm2ext::ImplicitActive);
2124 b->set_active_state (Gtkmm2ext::Off);
2129 /* One button per channel; just set active */
2132 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2133 (*i)->set_active (_route->phase_invert (j));
2140 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2142 if (ev->button == 1 && i < _invert_buttons.size()) {
2143 uint32_t const N = _route->input()->n_ports().n_audio ();
2144 if (N <= _max_invert_buttons) {
2145 /* left-click inverts phase so long as we have a button per channel */
2146 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2155 RouteUI::invert_press (GdkEventButton* ev)
2157 using namespace Menu_Helpers;
2159 uint32_t const N = _route->input()->n_ports().n_audio();
2160 if (N <= _max_invert_buttons && ev->button != 3) {
2161 /* If we have an invert button per channel, we only pop
2162 up a menu on right-click; left click is handled
2168 delete _invert_menu;
2169 _invert_menu = new Menu;
2170 _invert_menu->set_name ("ArdourContextMenu");
2171 MenuList& items = _invert_menu->items ();
2173 for (uint32_t i = 0; i < N; ++i) {
2174 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2175 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2176 ++_i_am_the_modifier;
2177 e->set_active (_route->phase_invert (i));
2178 --_i_am_the_modifier;
2181 _invert_menu->popup (0, ev->time);
2187 RouteUI::invert_menu_toggled (uint32_t c)
2189 if (_i_am_the_modifier) {
2193 _route->set_phase_invert (c, !_route->phase_invert (c));
2197 RouteUI::set_invert_sensitive (bool yn)
2199 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2200 (*b)->set_sensitive (yn);
2205 RouteUI::request_redraw ()
2208 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2212 /** The Route's gui_changed signal has been emitted */
2214 RouteUI::route_gui_changed (string what_changed)
2216 if (what_changed == "color") {
2217 if (set_color_from_route () == 0) {
2218 route_color_changed ();
2224 RouteUI::track_mode_changed (void)
2227 switch (track()->mode()) {
2228 case ARDOUR::NonLayered:
2229 case ARDOUR::Normal:
2230 rec_enable_button->set_icon (ArdourIcon::RecButton);
2232 case ARDOUR::Destructive:
2233 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2236 rec_enable_button->queue_draw();
2239 /** @return the color that this route should use; it maybe its own,
2240 or it maybe that of its route group.
2243 RouteUI::color () const
2245 RouteGroup* g = _route->route_group ();
2247 if (g && g->is_color()) {
2249 set_color_from_rgba (c, GroupTabs::group_color (g));
2257 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2259 _showing_sends_to = send_to;
2260 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2264 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2266 if (_route == send_to) {
2267 show_sends_button->set_active (true);
2268 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2270 show_sends_button->set_active (false);
2271 send_blink_connection.disconnect ();
2276 RouteUI::route_group() const
2278 return _route->route_group();
2282 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2283 : WM::ProxyBase (name, string())
2284 , _route (boost::weak_ptr<Route> (route))
2286 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2289 RoutePinWindowProxy::~RoutePinWindowProxy()
2294 ARDOUR::SessionHandlePtr*
2295 RoutePinWindowProxy::session_handle ()
2297 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2298 if (aw) { return aw; }
2303 RoutePinWindowProxy::get (bool create)
2305 boost::shared_ptr<Route> r = _route.lock ();
2314 _window = new PluginPinDialog (r);
2315 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2317 aw->set_session (_session);
2319 _window->show_all ();
2325 RoutePinWindowProxy::route_going_away ()
2329 WM::Manager::instance().remove (this);
2330 going_away_connection.disconnect();
2334 RouteUI::maybe_add_route_print_mgr ()
2336 if (_route->pinmgr_proxy ()) {
2339 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2340 string_compose ("RPM-%1", _route->id()), _route);
2341 wp->set_session (_session);
2343 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2345 wp->set_state (*ui_xml, 0);
2349 void* existing_ui = _route->pinmgr_proxy ();
2351 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2354 _route->set_pingmgr_proxy (wp);
2356 WM::Manager::instance().register_window (wp);
2360 RouteUI::manage_pins ()
2362 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();