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;
151 setup_invert_buttons ();
153 mute_button = manage (new ArdourButton);
154 mute_button->set_name ("mute button");
155 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
157 solo_button = manage (new ArdourButton);
158 solo_button->set_name ("solo button");
159 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
160 solo_button->set_no_show_all (true);
162 rec_enable_button = manage (new ArdourButton);
163 rec_enable_button->set_name ("record enable button");
164 rec_enable_button->set_icon (ArdourIcon::RecButton);
165 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
167 if (UIConfiguration::instance().get_blink_rec_arm()) {
168 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
171 show_sends_button = manage (new ArdourButton);
172 show_sends_button->set_name ("send alert button");
173 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
175 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
176 monitor_input_button->set_name ("monitor button");
177 monitor_input_button->set_text (_("In"));
178 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
179 monitor_input_button->set_no_show_all (true);
181 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
182 monitor_disk_button->set_name ("monitor button");
183 monitor_disk_button->set_text (_("Disk"));
184 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
185 monitor_disk_button->set_no_show_all (true);
187 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
188 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
189 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
191 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
192 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
194 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
195 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
197 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
198 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
200 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
201 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
202 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
203 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
205 monitor_input_button->set_distinct_led_click (false);
206 monitor_disk_button->set_distinct_led_click (false);
208 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
209 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
211 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
212 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
214 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
220 route_connections.drop_connections ();
228 denormal_menu_item = 0;
232 RouteUI::self_delete ()
238 RouteUI::set_route (boost::shared_ptr<Route> rp)
244 if (set_color_from_route()) {
245 set_color (unique_random_color());
249 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
252 delete input_selector;
255 delete output_selector;
258 mute_button->set_controllable (_route->mute_control());
259 solo_button->set_controllable (_route->solo_control());
261 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
262 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
264 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
266 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
267 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
268 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
269 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
271 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
272 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
273 track_mode_changed();
276 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
277 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
279 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
280 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
282 if (_session->writable() && is_track()) {
283 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
285 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
286 t->RecordSafeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
288 rec_enable_button->show();
289 rec_enable_button->set_controllable (t->rec_enable_control());
291 if (is_midi_track()) {
292 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
293 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
298 /* this will work for busses and tracks, and needs to be called to
299 set up the name entry/name label display.
303 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
304 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
306 update_monitoring_display ();
309 mute_button->unset_flags (Gtk::CAN_FOCUS);
310 solo_button->unset_flags (Gtk::CAN_FOCUS);
314 if (_route->is_monitor() || _route->is_master()) {
315 solo_button->hide ();
322 setup_invert_buttons ();
323 set_invert_button_state ();
325 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
326 bus_send_display_changed (s);
328 update_mute_display ();
329 update_solo_display ();
331 if (!UIConfiguration::instance().get_blink_rec_arm()) {
332 blink_rec_display(true); // set initial rec-en button state
335 check_rec_enable_sensitivity ();
336 maybe_add_route_print_mgr ();
337 route_color_changed();
341 RouteUI::polarity_changed ()
347 set_invert_button_state ();
351 RouteUI::mute_press (GdkEventButton* ev)
353 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
357 //if this is a binding action, let the ArdourButton handle it
358 if ( BindingProxy::is_bind_action(ev) )
361 multiple_mute_change = false;
363 if (Keyboard::is_context_menu_event (ev)) {
369 mute_menu->popup(0,ev->time);
375 if (Keyboard::is_button2_event (ev)) {
376 // button2-click is "momentary"
378 _mute_release = new SoloMuteRelease (_route->muted ());
381 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
383 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
385 /* toggle mute on everything (but
386 * exclude the master and monitor)
388 * because we are going to erase
389 * elements of the list we need to work
393 boost::shared_ptr<RouteList> copy (new RouteList);
395 *copy = *_session->get_routes ();
397 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
398 if ((*i)->is_master() || (*i)->is_monitor()) {
406 _mute_release->routes = copy;
410 _session->set_mute (copy, !_route->muted());
412 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
414 /* Primary-button1 inverts the implication of
415 the group being active. If the group is
416 active (for mute), then this modifier means
417 "do not apply to mute". If the group is
418 inactive (for mute), then this modifier
419 means "apply to route". This is all
420 accomplished by passing just the actual
421 route, along with the InverseGroup group
424 NOTE: Primary-button2 is MIDI learn.
427 boost::shared_ptr<RouteList> rl;
429 if (ev->button == 1) {
431 rl.reset (new RouteList);
432 rl->push_back (_route);
435 _mute_release->routes = rl;
439 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
444 /* plain click applies change to this route */
446 boost::shared_ptr<RouteList> rl (new RouteList);
447 rl->push_back (_route);
450 _mute_release->routes = rl;
453 _session->set_mute (rl, !_route->muted());
463 RouteUI::mute_release (GdkEventButton* /*ev*/)
467 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
468 delete _mute_release;
476 RouteUI::edit_output_configuration ()
478 if (output_selector == 0) {
480 boost::shared_ptr<Send> send;
481 boost::shared_ptr<IO> output;
483 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
484 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
485 output = send->output();
487 output = _route->output ();
490 output = _route->output ();
493 output_selector = new IOSelectorWindow (_session, output);
496 if (output_selector->is_visible()) {
497 output_selector->get_toplevel()->get_window()->raise();
499 output_selector->present ();
502 //output_selector->set_keep_above (true);
506 RouteUI::edit_input_configuration ()
508 if (input_selector == 0) {
509 input_selector = new IOSelectorWindow (_session, _route->input());
512 if (input_selector->is_visible()) {
513 input_selector->get_toplevel()->get_window()->raise();
515 input_selector->present ();
518 //input_selector->set_keep_above (true);
522 RouteUI::solo_press(GdkEventButton* ev)
524 /* ignore double/triple clicks */
526 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
530 //if this is a binding action, let the ArdourButton handle it
531 if ( BindingProxy::is_bind_action(ev) )
534 multiple_solo_change = false;
536 if (Keyboard::is_context_menu_event (ev)) {
538 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
539 ! (solo_safe_led && solo_safe_led->is_visible())) {
541 if (solo_menu == 0) {
545 solo_menu->popup (1, ev->time);
550 if (Keyboard::is_button2_event (ev)) {
552 // button2-click is "momentary"
553 _solo_release = new SoloMuteRelease (_route->self_soloed());
556 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
558 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
560 /* Primary-Tertiary-click applies change to all routes */
563 _solo_release->routes = _session->get_routes ();
567 if (Config->get_solo_control_is_listen_control()) {
568 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::UseGroup);
570 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, Controllable::UseGroup);
573 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
575 // Primary-Secondary-click: exclusively solo this track
578 _solo_release->exclusive = true;
580 boost::shared_ptr<RouteList> routes = _session->get_routes();
582 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
583 if ((*i)->soloed ()) {
584 _solo_release->routes_on->push_back (*i);
586 _solo_release->routes_off->push_back (*i);
591 if (Config->get_solo_control_is_listen_control()) {
592 /* ??? we need a just_one_listen() method */
595 _session->set_just_one_solo (_route, true);
598 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
600 // shift-click: toggle solo isolated status
602 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
603 delete _solo_release;
606 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
608 /* Primary-button1: solo mix group.
609 NOTE: Primary-button2 is MIDI learn.
612 /* Primary-button1 applies change to the mix group even if it is not active
613 NOTE: Primary-button2 is MIDI learn.
616 boost::shared_ptr<RouteList> rl;
618 if (ev->button == 1) {
620 /* Primary-button1 inverts the implication of
621 the group being active. If the group is
622 active (for solo), then this modifier means
623 "do not apply to solo". If the group is
624 inactive (for mute), then this modifier
625 means "apply to route". This is all
626 accomplished by passing just the actual
627 route, along with the InverseGroup group
630 NOTE: Primary-button2 is MIDI learn.
633 rl.reset (new RouteList);
634 rl->push_back (_route);
637 _solo_release->routes = rl;
642 if (Config->get_solo_control_is_listen_control()) {
643 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
645 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
649 delete _solo_release;
654 /* click: solo this route */
656 boost::shared_ptr<RouteList> rl (new RouteList);
657 rl->push_back (route());
660 _solo_release->routes = rl;
664 if (Config->get_solo_control_is_listen_control()) {
665 _session->set_listen (rl, !_route->listening_via_monitor());
667 _session->set_solo (rl, !_route->self_soloed());
677 RouteUI::solo_release (GdkEventButton* /*ev*/)
681 if (_solo_release->exclusive) {
685 if (Config->get_solo_control_is_listen_control()) {
686 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
688 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
692 delete _solo_release;
700 RouteUI::rec_enable_press(GdkEventButton* ev)
702 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
706 //if this is a binding action, let the ArdourButton handle it
707 if ( BindingProxy::is_bind_action(ev) )
710 if (!_session->engine().connected()) {
711 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
716 if (is_midi_track()) {
718 /* rec-enable button exits from step editing */
720 if (midi_track()->step_editing()) {
721 midi_track()->set_step_editing (false);
726 if (is_track() && rec_enable_button) {
728 if (Keyboard::is_button2_event (ev)) {
730 //rec arm does not have a momentary mode
733 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
736 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
738 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
740 /* Primary-button1 applies change to the route group (even if it is not active)
741 NOTE: Primary-button2 is MIDI learn.
744 if (ev->button == 1) {
746 boost::shared_ptr<RouteList> rl;
748 rl.reset (new RouteList);
749 rl->push_back (_route);
752 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
755 } else if (Keyboard::is_context_menu_event (ev)) {
757 /* do this on release */
761 boost::shared_ptr<RouteList> rl (new RouteList);
762 rl->push_back (route());
764 _session->set_record_enabled (rl, !_route->record_enabled());
772 RouteUI::monitoring_changed ()
774 update_monitoring_display ();
778 RouteUI::update_monitoring_display ()
784 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
790 MonitorState ms = t->monitoring_state();
792 if (t->monitoring_choice() & MonitorInput) {
793 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
795 if (ms & MonitoringInput) {
796 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
798 monitor_input_button->unset_active_state ();
802 if (t->monitoring_choice() & MonitorDisk) {
803 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
805 if (ms & MonitoringDisk) {
806 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
808 monitor_disk_button->unset_active_state ();
814 RouteUI::monitor_input_press(GdkEventButton*)
820 RouteUI::monitor_input_release(GdkEventButton* ev)
822 return monitor_release (ev, MonitorInput);
826 RouteUI::monitor_disk_press (GdkEventButton*)
832 RouteUI::monitor_disk_release (GdkEventButton* ev)
834 return monitor_release (ev, MonitorDisk);
838 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
840 if (ev->button != 1) {
844 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
851 boost::shared_ptr<RouteList> rl;
853 /* XXX for now, monitoring choices are orthogonal. cue monitoring
854 will follow in 3.X but requires mixing the input and playback (disk)
855 signal together, which requires yet more buffers.
858 if (t->monitoring_choice() & monitor_choice) {
859 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
861 /* this line will change when the options are non-orthogonal */
862 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
866 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
867 rl = _session->get_routes ();
869 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
870 if (_route->route_group() && _route->route_group()->is_monitoring()) {
871 rl = _route->route_group()->route_list();
873 rl.reset (new RouteList);
874 rl->push_back (route());
877 rl.reset (new RouteList);
878 rl->push_back (route());
882 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
888 RouteUI::build_record_menu ()
891 record_menu = new Menu;
892 record_menu->set_name ("ArdourContextMenu");
893 using namespace Menu_Helpers;
894 MenuList& items = record_menu->items();
896 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
897 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
899 if (is_midi_track()) {
900 items.push_back (SeparatorElem());
901 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
902 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
906 if (step_edit_item) {
907 step_edit_item->set_sensitive (!_route->record_enabled());
908 step_edit_item->set_active (midi_track()->step_editing());
911 rec_safe_item->set_sensitive (!_route->record_enabled());
912 rec_safe_item->set_active (_route->record_safe());
917 RouteUI::toggle_step_edit ()
919 if (!is_midi_track() || _route->record_enabled()) {
923 midi_track()->set_step_editing (step_edit_item->get_active());
927 RouteUI::toggle_rec_safe ()
929 if (_route->record_enabled()) {
933 boost::shared_ptr<RouteList> rl (new RouteList);
934 rl->push_back (_route);
935 _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
939 RouteUI::step_edit_changed (bool yn)
942 if (rec_enable_button) {
943 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
946 start_step_editing ();
948 if (step_edit_item) {
949 step_edit_item->set_active (true);
954 if (rec_enable_button) {
955 rec_enable_button->unset_active_state ();
958 stop_step_editing ();
960 if (step_edit_item) {
961 step_edit_item->set_active (false);
967 RouteUI::rec_enable_release (GdkEventButton* ev)
969 if (Keyboard::is_context_menu_event (ev)) {
970 build_record_menu ();
972 record_menu->popup (1, ev->time);
981 RouteUI::build_sends_menu ()
983 using namespace Menu_Helpers;
985 sends_menu = new Menu;
986 sends_menu->set_name ("ArdourContextMenu");
987 MenuList& items = sends_menu->items();
990 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
994 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
998 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1002 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1006 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1010 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1013 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1017 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1020 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1021 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1022 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1027 RouteUI::create_sends (Placement p, bool include_buses)
1029 _session->globally_add_internal_sends (_route, p, include_buses);
1033 RouteUI::create_selected_sends (Placement p, bool include_buses)
1035 boost::shared_ptr<RouteList> rlist (new RouteList);
1036 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1038 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1039 RouteTimeAxisView* rtv;
1041 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1042 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1043 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1044 rlist->push_back (rui->route());
1050 _session->add_internal_sends (_route, p, rlist);
1054 RouteUI::set_sends_gain_from_track ()
1056 _session->globally_set_send_gains_from_track (_route);
1060 RouteUI::set_sends_gain_to_zero ()
1062 _session->globally_set_send_gains_to_zero (_route);
1066 RouteUI::set_sends_gain_to_unity ()
1068 _session->globally_set_send_gains_to_unity (_route);
1072 RouteUI::show_sends_press(GdkEventButton* ev)
1074 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1078 if (!is_track() && show_sends_button) {
1080 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1082 // do nothing on midi sigc::bind event
1085 } else if (Keyboard::is_context_menu_event (ev)) {
1087 if (sends_menu == 0) {
1088 build_sends_menu ();
1091 sends_menu->popup (0, ev->time);
1095 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1098 set_showing_sends_to (boost::shared_ptr<Route> ());
1100 set_showing_sends_to (_route);
1109 RouteUI::show_sends_release (GdkEventButton*)
1115 RouteUI::send_blink (bool onoff)
1117 if (!show_sends_button) {
1122 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1124 show_sends_button->unset_active_state ();
1128 Gtkmm2ext::ActiveState
1129 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1131 if (r->is_master() || r->is_monitor()) {
1132 return Gtkmm2ext::Off;
1135 if (Config->get_solo_control_is_listen_control()) {
1137 if (r->listening_via_monitor()) {
1138 return Gtkmm2ext::ExplicitActive;
1140 return Gtkmm2ext::Off;
1146 if (!r->self_soloed()) {
1147 return Gtkmm2ext::ImplicitActive;
1149 return Gtkmm2ext::ExplicitActive;
1152 return Gtkmm2ext::Off;
1156 Gtkmm2ext::ActiveState
1157 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1159 if (r->is_master() || r->is_monitor()) {
1160 return Gtkmm2ext::Off;
1163 if (r->solo_isolated()) {
1164 return Gtkmm2ext::ExplicitActive;
1166 return Gtkmm2ext::Off;
1170 Gtkmm2ext::ActiveState
1171 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1173 if (r->is_master() || r->is_monitor()) {
1174 return Gtkmm2ext::Off;
1177 if (r->solo_safe()) {
1178 return Gtkmm2ext::ExplicitActive;
1180 return Gtkmm2ext::Off;
1185 RouteUI::update_solo_display ()
1187 bool yn = _route->solo_safe ();
1189 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1190 solo_safe_check->set_active (yn);
1193 yn = _route->solo_isolated ();
1195 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1196 solo_isolated_check->set_active (yn);
1199 set_button_names ();
1201 if (solo_isolated_led) {
1202 if (_route->solo_isolated()) {
1203 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1205 solo_isolated_led->unset_active_state ();
1209 if (solo_safe_led) {
1210 if (_route->solo_safe()) {
1211 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1213 solo_safe_led->unset_active_state ();
1217 solo_button->set_active_state (solo_active_state (_route));
1219 /* some changes to solo status can affect mute display, so catch up
1222 update_mute_display ();
1226 RouteUI::solo_changed_so_update_mute ()
1228 update_mute_display ();
1232 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1234 if (r->is_monitor()) {
1235 return ActiveState(0);
1239 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1243 return Gtkmm2ext::ExplicitActive;
1244 } else if (r->muted_by_others()) {
1245 return Gtkmm2ext::ImplicitActive;
1247 /* no mute at all */
1248 return Gtkmm2ext::Off;
1255 return Gtkmm2ext::ExplicitActive;
1257 /* no mute at all */
1258 return Gtkmm2ext::Off;
1262 return ActiveState(0);
1266 RouteUI::update_mute_display ()
1272 mute_button->set_active_state (mute_active_state (_session, _route));
1276 RouteUI::route_rec_enable_changed ()
1278 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1279 update_monitoring_display ();
1283 RouteUI::session_rec_enable_changed ()
1285 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1286 update_monitoring_display ();
1290 RouteUI::blink_rec_display (bool blinkOn)
1292 if (!rec_enable_button || !_route) {
1295 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1299 if (_route->record_enabled()) {
1300 switch (_session->record_status ()) {
1301 case Session::Recording:
1302 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1305 case Session::Disabled:
1306 case Session::Enabled:
1307 if ( UIConfiguration::instance().get_blink_rec_arm() )
1308 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1310 rec_enable_button->set_active_state ( ImplicitActive );
1315 if (step_edit_item) {
1316 step_edit_item->set_sensitive (false);
1320 rec_enable_button->unset_active_state ();
1322 if (step_edit_item) {
1323 step_edit_item->set_sensitive (true);
1327 check_rec_enable_sensitivity ();
1331 RouteUI::build_solo_menu (void)
1333 using namespace Menu_Helpers;
1335 solo_menu = new Menu;
1336 solo_menu->set_name ("ArdourContextMenu");
1337 MenuList& items = solo_menu->items();
1338 Gtk::CheckMenuItem* check;
1340 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1341 check->set_active (_route->solo_isolated());
1342 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1343 items.push_back (CheckMenuElem(*check));
1344 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1347 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1348 check->set_active (_route->solo_safe());
1349 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1350 items.push_back (CheckMenuElem(*check));
1351 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1354 //items.push_back (SeparatorElem());
1355 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1360 RouteUI::build_mute_menu(void)
1362 using namespace Menu_Helpers;
1364 mute_menu = new Menu;
1365 mute_menu->set_name ("ArdourContextMenu");
1367 MenuList& items = mute_menu->items();
1369 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1370 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1371 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1372 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1373 pre_fader_mute_check->show_all();
1375 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1376 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1377 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1378 items.push_back (CheckMenuElem(*post_fader_mute_check));
1379 post_fader_mute_check->show_all();
1381 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1382 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1383 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1384 items.push_back (CheckMenuElem(*listen_mute_check));
1385 listen_mute_check->show_all();
1387 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1388 init_mute_menu(MuteMaster::Main, main_mute_check);
1389 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1390 items.push_back (CheckMenuElem(*main_mute_check));
1391 main_mute_check->show_all();
1393 //items.push_back (SeparatorElem());
1394 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1396 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1400 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1402 check->set_active (_route->mute_points() & mp);
1406 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1408 if (check->get_active()) {
1409 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1411 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1416 RouteUI::muting_change ()
1418 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1421 MuteMaster::MutePoint current = _route->mute_points ();
1423 yn = (current & MuteMaster::PreFader);
1425 if (pre_fader_mute_check->get_active() != yn) {
1426 pre_fader_mute_check->set_active (yn);
1429 yn = (current & MuteMaster::PostFader);
1431 if (post_fader_mute_check->get_active() != yn) {
1432 post_fader_mute_check->set_active (yn);
1435 yn = (current & MuteMaster::Listen);
1437 if (listen_mute_check->get_active() != yn) {
1438 listen_mute_check->set_active (yn);
1441 yn = (current & MuteMaster::Main);
1443 if (main_mute_check->get_active() != yn) {
1444 main_mute_check->set_active (yn);
1449 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1451 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1455 bool view = solo_isolated_led->active_state();
1456 bool model = _route->solo_isolated();
1458 /* called BEFORE the view has changed */
1460 if (ev->button == 1) {
1461 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1464 /* disable isolate for all routes */
1465 DisplaySuspender ds;
1466 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1468 /* enable isolate for all routes */
1469 DisplaySuspender ds;
1470 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1475 if (model == view) {
1477 /* flip just this route */
1479 boost::shared_ptr<RouteList> rl (new RouteList);
1480 rl->push_back (_route);
1481 DisplaySuspender ds;
1482 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1491 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1493 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1497 bool view = solo_safe_led->active_state();
1498 bool model = _route->solo_safe();
1500 if (ev->button == 1) {
1501 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1502 boost::shared_ptr<RouteList> rl (_session->get_routes());
1504 /* disable solo safe for all routes */
1505 DisplaySuspender ds;
1506 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1507 (*i)->set_solo_safe (false, Controllable::NoGroup);
1510 /* enable solo safe for all routes */
1511 DisplaySuspender ds;
1512 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1513 (*i)->set_solo_safe (true, Controllable::NoGroup);
1518 if (model == view) {
1519 /* flip just this route */
1520 _route->set_solo_safe (!view, Controllable::NoGroup);
1529 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1531 bool view = check->get_active();
1532 bool model = _route->solo_isolated();
1534 /* called AFTER the view has changed */
1536 if (model != view) {
1537 _route->set_solo_isolated (view, Controllable::UseGroup);
1542 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1544 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1547 /** Ask the user to choose a colour, and then apply that color to my route
1550 RouteUI::choose_color ()
1553 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1560 /** Set the route's own color. This may not be used for display if
1561 * the route is in a group which shares its color with its routes.
1564 RouteUI::set_color (const Gdk::Color & c)
1566 /* leave _color alone in the group case so that tracks can retain their
1567 * own pre-group colors.
1572 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1574 /* note: we use the route state ID here so that color is the same for both
1575 the time axis view and the mixer strip
1578 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1579 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1582 /** @return GUI state ID for things that are common to the route in all its representations */
1584 RouteUI::route_state_id () const
1586 return string_compose (X_("route %1"), _route->id().to_s());
1590 RouteUI::set_color_from_route ()
1592 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1600 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1603 _color.set_green (g);
1604 _color.set_blue (b);
1609 /** @return true if this name should be used for the route, otherwise false */
1611 RouteUI::verify_new_route_name (const std::string& name)
1613 if (name.find (':') == string::npos) {
1617 MessageDialog colon_msg (
1618 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1619 false, MESSAGE_QUESTION, BUTTONS_NONE
1622 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1623 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1625 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1629 RouteUI::route_rename ()
1631 ArdourPrompter name_prompter (true);
1636 name_prompter.set_title (_("Rename Track"));
1638 name_prompter.set_title (_("Rename Bus"));
1640 name_prompter.set_prompt (_("New name:"));
1641 name_prompter.set_initial_text (_route->name());
1642 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1643 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1644 name_prompter.show_all ();
1647 switch (name_prompter.run ()) {
1648 case Gtk::RESPONSE_ACCEPT:
1649 name_prompter.get_result (result);
1650 name_prompter.hide ();
1651 if (result.length()) {
1652 if (verify_new_route_name (result)) {
1653 _route->set_name (result);
1656 /* back to name prompter */
1660 /* nothing entered, just get out of here */
1675 RouteUI::property_changed (const PropertyChange& what_changed)
1677 if (what_changed.contains (ARDOUR::Properties::name)) {
1678 name_label.set_text (_route->name());
1683 RouteUI::toggle_comment_editor ()
1685 // if (ignore_toggle) {
1689 if (comment_window && comment_window->is_visible ()) {
1690 comment_window->hide ();
1692 open_comment_editor ();
1698 RouteUI::open_comment_editor ()
1700 if (comment_window == 0) {
1701 setup_comment_editor ();
1705 title = _route->name();
1706 title += _(": comment editor");
1708 comment_window->set_title (title);
1709 comment_window->present();
1713 RouteUI::setup_comment_editor ()
1715 comment_window = new ArdourWindow (""); // title will be reset to show route
1716 comment_window->set_skip_taskbar_hint (true);
1717 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1718 comment_window->set_default_size (400, 200);
1720 comment_area = manage (new TextView());
1721 comment_area->set_name ("MixerTrackCommentArea");
1722 comment_area->set_wrap_mode (WRAP_WORD);
1723 comment_area->set_editable (true);
1724 comment_area->get_buffer()->set_text (_route->comment());
1725 comment_area->show ();
1727 comment_window->add (*comment_area);
1731 RouteUI::comment_changed ()
1733 ignore_comment_edit = true;
1735 comment_area->get_buffer()->set_text (_route->comment());
1737 ignore_comment_edit = false;
1741 RouteUI::comment_editor_done_editing ()
1743 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1745 string const str = comment_area->get_buffer()->get_text();
1746 if (str == _route->comment ()) {
1750 _route->set_comment (str, this);
1754 RouteUI::set_route_active (bool a, bool apply_to_selection)
1756 if (apply_to_selection) {
1757 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1759 _route->set_active (a, this);
1764 RouteUI::duplicate_selected_routes ()
1766 ARDOUR_UI::instance()->start_duplicate_routes();
1770 RouteUI::toggle_denormal_protection ()
1772 if (denormal_menu_item) {
1776 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1778 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1779 _route->set_denormal_protection (x);
1785 RouteUI::denormal_protection_changed ()
1787 if (denormal_menu_item) {
1788 denormal_menu_item->set_active (_route->denormal_protection());
1793 RouteUI::disconnect_input ()
1795 _route->input()->disconnect (this);
1799 RouteUI::disconnect_output ()
1801 _route->output()->disconnect (this);
1805 RouteUI::is_track () const
1807 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1810 boost::shared_ptr<Track>
1811 RouteUI::track() const
1813 return boost::dynamic_pointer_cast<Track>(_route);
1817 RouteUI::is_audio_track () const
1819 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1822 boost::shared_ptr<AudioTrack>
1823 RouteUI::audio_track() const
1825 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1829 RouteUI::is_midi_track () const
1831 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1834 boost::shared_ptr<MidiTrack>
1835 RouteUI::midi_track() const
1837 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1841 RouteUI::has_audio_outputs () const
1843 return (_route->n_outputs().n_audio() > 0);
1847 RouteUI::name() const
1849 return _route->name();
1853 RouteUI::map_frozen ()
1855 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1857 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1860 check_rec_enable_sensitivity ();
1865 RouteUI::adjust_latency ()
1867 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1871 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1874 std::string safe_name;
1877 prompter.get_result (name, true);
1879 safe_name = legalize_for_path (name);
1880 safe_name += template_suffix;
1882 path = Glib::build_filename (dir, safe_name);
1884 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1885 bool overwrite = overwrite_file_dialog (prompter,
1886 _("Confirm Template Overwrite"),
1887 _("A template already exists with that name. Do you want to overwrite it?"));
1894 _route->save_as_template (path, name);
1900 RouteUI::save_as_template ()
1904 dir = ARDOUR::user_route_template_directory ();
1906 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1907 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1911 ArdourPrompter prompter (true); // modal
1913 prompter.set_title (_("Save As Template"));
1914 prompter.set_prompt (_("Template name:"));
1915 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1917 bool finished = false;
1919 switch (prompter.run()) {
1920 case RESPONSE_ACCEPT:
1921 finished = process_save_template_prompter (prompter, dir);
1931 RouteUI::check_rec_enable_sensitivity ()
1933 if (!rec_enable_button) {
1934 assert (0); // This should not happen
1937 if (!_session->writable()) {
1938 rec_enable_button->set_sensitive (false);
1942 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1943 rec_enable_button->set_sensitive (false);
1944 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1945 rec_enable_button->set_sensitive (false);
1947 rec_enable_button->set_sensitive (true);
1949 if (_route && _route->record_safe ()) {
1950 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1952 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1954 update_monitoring_display ();
1958 RouteUI::parameter_changed (string const & p)
1960 /* this handles RC and per-session parameter changes */
1962 if (p == "disable-disarm-during-roll") {
1963 check_rec_enable_sensitivity ();
1964 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1965 set_button_names ();
1966 } else if (p == "auto-input") {
1967 update_monitoring_display ();
1968 } else if (p == "blink-rec-arm") {
1969 if (UIConfiguration::instance().get_blink_rec_arm()) {
1970 rec_blink_connection.disconnect ();
1971 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1973 rec_blink_connection.disconnect ();
1974 RouteUI::blink_rec_display(false);
1980 RouteUI::step_gain_up ()
1982 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1986 RouteUI::page_gain_up ()
1988 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1992 RouteUI::step_gain_down ()
1994 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1998 RouteUI::page_gain_down ()
2000 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2004 RouteUI::open_remote_control_id_dialog ()
2006 ArdourDialog dialog (_("Remote Control ID"));
2007 SpinButton* spin = 0;
2009 dialog.get_vbox()->set_border_width (18);
2011 if (Config->get_remote_model() == UserOrdered) {
2012 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2014 HBox* hbox = manage (new HBox);
2015 hbox->set_spacing (6);
2016 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2017 spin = manage (new SpinButton);
2018 spin->set_digits (0);
2019 spin->set_increments (1, 10);
2020 spin->set_range (0, limit);
2021 spin->set_value (_route->remote_control_id());
2022 hbox->pack_start (*spin);
2023 dialog.get_vbox()->pack_start (*hbox);
2025 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2026 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2028 Label* l = manage (new Label());
2029 if (_route->is_master() || _route->is_monitor()) {
2030 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2031 "The remote control ID of %3 cannot be changed."),
2032 Gtkmm2ext::markup_escape_text (_route->name()),
2033 _route->remote_control_id(),
2034 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2036 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2037 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2038 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2039 (is_track() ? _("track") : _("bus")),
2040 _route->remote_control_id(),
2041 "<span size=\"small\" style=\"italic\">",
2043 Gtkmm2ext::markup_escape_text (_route->name()),
2046 dialog.get_vbox()->pack_start (*l);
2047 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2051 int const r = dialog.run ();
2053 if (r == RESPONSE_ACCEPT && spin) {
2054 _route->set_remote_control_id (spin->get_value_as_int ());
2059 RouteUI::setup_invert_buttons ()
2061 /* remove old invert buttons */
2062 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2063 _invert_button_box.remove (**i);
2066 _invert_buttons.clear ();
2068 if (!_route || !_route->input()) {
2072 uint32_t const N = _route->input()->n_ports().n_audio ();
2074 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2076 for (uint32_t i = 0; i < to_add; ++i) {
2077 ArdourButton* b = manage (new ArdourButton);
2078 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2079 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2081 b->set_name (X_("invert button"));
2084 b->set_text (string_compose (X_("Ø (%1)"), N));
2086 b->set_text (X_("Ø"));
2089 b->set_text (string_compose (X_("Ø%1"), i + 1));
2092 if (N <= _max_invert_buttons) {
2093 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));
2095 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2098 _invert_buttons.push_back (b);
2099 _invert_button_box.pack_start (*b);
2102 _invert_button_box.set_spacing (1);
2103 _invert_button_box.show_all ();
2107 RouteUI::set_invert_button_state ()
2109 uint32_t const N = _route->input()->n_ports().n_audio();
2110 if (N > _max_invert_buttons) {
2112 /* One button for many channels; explicit active if all channels are inverted,
2113 implicit active if some are, off if none are.
2116 ArdourButton* b = _invert_buttons.front ();
2118 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2119 b->set_active_state (Gtkmm2ext::ExplicitActive);
2120 } else if (_route->phase_invert().any()) {
2121 b->set_active_state (Gtkmm2ext::ImplicitActive);
2123 b->set_active_state (Gtkmm2ext::Off);
2128 /* One button per channel; just set active */
2131 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2132 (*i)->set_active (_route->phase_invert (j));
2139 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2141 if (ev->button == 1 && i < _invert_buttons.size()) {
2142 uint32_t const N = _route->input()->n_ports().n_audio ();
2143 if (N <= _max_invert_buttons) {
2144 /* left-click inverts phase so long as we have a button per channel */
2145 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2154 RouteUI::invert_press (GdkEventButton* ev)
2156 using namespace Menu_Helpers;
2158 uint32_t const N = _route->input()->n_ports().n_audio();
2159 if (N <= _max_invert_buttons && ev->button != 3) {
2160 /* If we have an invert button per channel, we only pop
2161 up a menu on right-click; left click is handled
2167 delete _invert_menu;
2168 _invert_menu = new Menu;
2169 _invert_menu->set_name ("ArdourContextMenu");
2170 MenuList& items = _invert_menu->items ();
2172 for (uint32_t i = 0; i < N; ++i) {
2173 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2174 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2175 ++_i_am_the_modifier;
2176 e->set_active (_route->phase_invert (i));
2177 --_i_am_the_modifier;
2180 _invert_menu->popup (0, ev->time);
2186 RouteUI::invert_menu_toggled (uint32_t c)
2188 if (_i_am_the_modifier) {
2192 _route->set_phase_invert (c, !_route->phase_invert (c));
2196 RouteUI::set_invert_sensitive (bool yn)
2198 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2199 (*b)->set_sensitive (yn);
2204 RouteUI::request_redraw ()
2207 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2211 /** The Route's gui_changed signal has been emitted */
2213 RouteUI::route_gui_changed (string what_changed)
2215 if (what_changed == "color") {
2216 if (set_color_from_route () == 0) {
2217 route_color_changed ();
2223 RouteUI::track_mode_changed (void)
2226 switch (track()->mode()) {
2227 case ARDOUR::NonLayered:
2228 case ARDOUR::Normal:
2229 rec_enable_button->set_icon (ArdourIcon::RecButton);
2231 case ARDOUR::Destructive:
2232 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2235 rec_enable_button->queue_draw();
2238 /** @return the color that this route should use; it maybe its own,
2239 or it maybe that of its route group.
2242 RouteUI::color () const
2244 RouteGroup* g = _route->route_group ();
2246 if (g && g->is_color()) {
2248 set_color_from_rgba (c, GroupTabs::group_color (g));
2256 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2258 _showing_sends_to = send_to;
2259 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2263 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2265 if (_route == send_to) {
2266 show_sends_button->set_active (true);
2267 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2269 show_sends_button->set_active (false);
2270 send_blink_connection.disconnect ();
2275 RouteUI::route_group() const
2277 return _route->route_group();
2281 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2282 : WM::ProxyBase (name, string())
2283 , _route (boost::weak_ptr<Route> (route))
2285 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2288 RoutePinWindowProxy::~RoutePinWindowProxy()
2293 ARDOUR::SessionHandlePtr*
2294 RoutePinWindowProxy::session_handle ()
2296 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2297 if (aw) { return aw; }
2302 RoutePinWindowProxy::get (bool create)
2304 boost::shared_ptr<Route> r = _route.lock ();
2313 _window = new PluginPinDialog (r);
2314 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2316 aw->set_session (_session);
2318 _window->show_all ();
2324 RoutePinWindowProxy::route_going_away ()
2328 WM::Manager::instance().remove (this);
2329 going_away_connection.disconnect();
2333 RouteUI::maybe_add_route_print_mgr ()
2335 if (_route->pinmgr_proxy ()) {
2338 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2339 string_compose ("RPM-%1", _route->id()), _route);
2340 wp->set_session (_session);
2342 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2344 wp->set_state (*ui_xml, 0);
2348 void* existing_ui = _route->pinmgr_proxy ();
2350 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2353 _route->set_pingmgr_proxy (wp);
2355 WM::Manager::instance().register_window (wp);
2359 RouteUI::manage_pins ()
2361 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();