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;
143 multiple_mute_change = false;
144 multiple_solo_change = false;
145 _i_am_the_modifier = 0;
150 setup_invert_buttons ();
152 mute_button = manage (new ArdourButton);
153 mute_button->set_name ("mute button");
154 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
156 solo_button = manage (new ArdourButton);
157 solo_button->set_name ("solo button");
158 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
159 solo_button->set_no_show_all (true);
161 rec_enable_button = manage (new ArdourButton);
162 rec_enable_button->set_name ("record enable button");
163 rec_enable_button->set_icon (ArdourIcon::RecButton);
164 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
166 if (UIConfiguration::instance().get_blink_rec_arm()) {
167 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
170 show_sends_button = manage (new ArdourButton);
171 show_sends_button->set_name ("send alert button");
172 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
174 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
175 monitor_input_button->set_name ("monitor button");
176 monitor_input_button->set_text (_("In"));
177 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
178 monitor_input_button->set_no_show_all (true);
180 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
181 monitor_disk_button->set_name ("monitor button");
182 monitor_disk_button->set_text (_("Disk"));
183 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
184 monitor_disk_button->set_no_show_all (true);
186 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
187 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
188 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
190 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
191 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
193 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
194 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
196 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
197 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
199 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
200 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
201 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
202 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
204 monitor_input_button->set_distinct_led_click (false);
205 monitor_disk_button->set_distinct_led_click (false);
207 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
208 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
210 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
211 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
213 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
219 route_connections.drop_connections ();
227 denormal_menu_item = 0;
231 RouteUI::self_delete ()
237 RouteUI::set_route (boost::shared_ptr<Route> rp)
243 if (set_color_from_route()) {
244 set_color (unique_random_color());
248 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
251 delete input_selector;
254 delete output_selector;
257 mute_button->set_controllable (_route->mute_control());
258 solo_button->set_controllable (_route->solo_control());
260 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
261 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
263 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
265 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
266 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
267 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
268 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
270 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
271 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
272 track_mode_changed();
275 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
276 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
278 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
279 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
281 if (_session->writable() && is_track()) {
282 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
284 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
285 t->RecordSafeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
287 rec_enable_button->show();
288 rec_enable_button->set_controllable (t->rec_enable_control());
290 if (is_midi_track()) {
291 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
292 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
297 /* this will work for busses and tracks, and needs to be called to
298 set up the name entry/name label display.
302 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
303 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
305 update_monitoring_display ();
308 mute_button->unset_flags (Gtk::CAN_FOCUS);
309 solo_button->unset_flags (Gtk::CAN_FOCUS);
313 if (_route->is_monitor() || _route->is_master()) {
314 solo_button->hide ();
321 setup_invert_buttons ();
322 set_invert_button_state ();
324 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
325 bus_send_display_changed (s);
327 update_mute_display ();
328 update_solo_display ();
330 if (!UIConfiguration::instance().get_blink_rec_arm()) {
331 blink_rec_display(true); // set initial rec-en button state
334 check_rec_enable_sensitivity ();
335 maybe_add_route_print_mgr ();
336 route_color_changed();
340 RouteUI::polarity_changed ()
346 set_invert_button_state ();
350 RouteUI::mute_press (GdkEventButton* ev)
352 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
356 //if this is a binding action, let the ArdourButton handle it
357 if ( BindingProxy::is_bind_action(ev) )
360 multiple_mute_change = false;
362 if (Keyboard::is_context_menu_event (ev)) {
368 mute_menu->popup(0,ev->time);
374 if (Keyboard::is_button2_event (ev)) {
375 // button2-click is "momentary"
377 _mute_release = new SoloMuteRelease (_route->muted ());
380 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
382 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
384 /* toggle mute on everything (but
385 * exclude the master and monitor)
387 * because we are going to erase
388 * elements of the list we need to work
392 boost::shared_ptr<RouteList> copy (new RouteList);
394 *copy = *_session->get_routes ();
396 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
397 if ((*i)->is_master() || (*i)->is_monitor()) {
405 _mute_release->routes = copy;
409 _session->set_mute (copy, !_route->muted());
411 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
413 /* Primary-button1 inverts the implication of
414 the group being active. If the group is
415 active (for mute), then this modifier means
416 "do not apply to mute". If the group is
417 inactive (for mute), then this modifier
418 means "apply to route". This is all
419 accomplished by passing just the actual
420 route, along with the InverseGroup group
423 NOTE: Primary-button2 is MIDI learn.
426 boost::shared_ptr<RouteList> rl;
428 if (ev->button == 1) {
430 rl.reset (new RouteList);
431 rl->push_back (_route);
434 _mute_release->routes = rl;
438 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
443 /* plain click applies change to this route */
445 boost::shared_ptr<RouteList> rl (new RouteList);
446 rl->push_back (_route);
449 _mute_release->routes = rl;
452 _session->set_mute (rl, !_route->muted());
462 RouteUI::mute_release (GdkEventButton* /*ev*/)
466 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
467 delete _mute_release;
475 RouteUI::edit_output_configuration ()
477 if (output_selector == 0) {
479 boost::shared_ptr<Send> send;
480 boost::shared_ptr<IO> output;
482 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
483 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
484 output = send->output();
486 output = _route->output ();
489 output = _route->output ();
492 output_selector = new IOSelectorWindow (_session, output);
495 if (output_selector->is_visible()) {
496 output_selector->get_toplevel()->get_window()->raise();
498 output_selector->present ();
501 //output_selector->set_keep_above (true);
505 RouteUI::edit_input_configuration ()
507 if (input_selector == 0) {
508 input_selector = new IOSelectorWindow (_session, _route->input());
511 if (input_selector->is_visible()) {
512 input_selector->get_toplevel()->get_window()->raise();
514 input_selector->present ();
517 //input_selector->set_keep_above (true);
521 RouteUI::solo_press(GdkEventButton* ev)
523 /* ignore double/triple clicks */
525 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
529 //if this is a binding action, let the ArdourButton handle it
530 if ( BindingProxy::is_bind_action(ev) )
533 multiple_solo_change = false;
535 if (Keyboard::is_context_menu_event (ev)) {
537 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
538 ! (solo_safe_led && solo_safe_led->is_visible())) {
540 if (solo_menu == 0) {
544 solo_menu->popup (1, ev->time);
549 if (Keyboard::is_button2_event (ev)) {
551 // button2-click is "momentary"
552 _solo_release = new SoloMuteRelease (_route->self_soloed());
555 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
557 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
559 /* Primary-Tertiary-click applies change to all routes */
562 _solo_release->routes = _session->get_routes ();
566 if (Config->get_solo_control_is_listen_control()) {
567 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::UseGroup);
569 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, Controllable::UseGroup);
572 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
574 // Primary-Secondary-click: exclusively solo this track
577 _solo_release->exclusive = true;
579 boost::shared_ptr<RouteList> routes = _session->get_routes();
581 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
582 if ((*i)->soloed ()) {
583 _solo_release->routes_on->push_back (*i);
585 _solo_release->routes_off->push_back (*i);
590 if (Config->get_solo_control_is_listen_control()) {
591 /* ??? we need a just_one_listen() method */
594 _session->set_just_one_solo (_route, true);
597 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
599 // shift-click: toggle solo isolated status
601 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
602 delete _solo_release;
605 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
607 /* Primary-button1: solo mix group.
608 NOTE: Primary-button2 is MIDI learn.
611 /* Primary-button1 applies change to the mix group even if it is not active
612 NOTE: Primary-button2 is MIDI learn.
615 boost::shared_ptr<RouteList> rl;
617 if (ev->button == 1) {
619 /* Primary-button1 inverts the implication of
620 the group being active. If the group is
621 active (for solo), then this modifier means
622 "do not apply to solo". If the group is
623 inactive (for mute), then this modifier
624 means "apply to route". This is all
625 accomplished by passing just the actual
626 route, along with the InverseGroup group
629 NOTE: Primary-button2 is MIDI learn.
632 rl.reset (new RouteList);
633 rl->push_back (_route);
636 _solo_release->routes = rl;
641 if (Config->get_solo_control_is_listen_control()) {
642 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
644 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
648 delete _solo_release;
653 /* click: solo this route */
655 boost::shared_ptr<RouteList> rl (new RouteList);
656 rl->push_back (route());
659 _solo_release->routes = rl;
663 if (Config->get_solo_control_is_listen_control()) {
664 _session->set_listen (rl, !_route->listening_via_monitor());
666 _session->set_solo (rl, !_route->self_soloed());
676 RouteUI::solo_release (GdkEventButton* /*ev*/)
680 if (_solo_release->exclusive) {
684 if (Config->get_solo_control_is_listen_control()) {
685 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
687 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
691 delete _solo_release;
699 RouteUI::rec_enable_press(GdkEventButton* ev)
701 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
705 //if this is a binding action, let the ArdourButton handle it
706 if ( BindingProxy::is_bind_action(ev) )
709 if (!_session->engine().connected()) {
710 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
715 if (is_midi_track()) {
717 /* rec-enable button exits from step editing */
719 if (midi_track()->step_editing()) {
720 midi_track()->set_step_editing (false);
725 if (is_track() && rec_enable_button) {
727 if (Keyboard::is_button2_event (ev)) {
729 //rec arm does not have a momentary mode
732 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
735 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
737 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
739 /* Primary-button1 applies change to the route group (even if it is not active)
740 NOTE: Primary-button2 is MIDI learn.
743 if (ev->button == 1) {
745 boost::shared_ptr<RouteList> rl;
747 rl.reset (new RouteList);
748 rl->push_back (_route);
751 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
754 } else if (Keyboard::is_context_menu_event (ev)) {
756 /* do this on release */
760 boost::shared_ptr<RouteList> rl (new RouteList);
761 rl->push_back (route());
763 _session->set_record_enabled (rl, !_route->record_enabled());
771 RouteUI::monitoring_changed ()
773 update_monitoring_display ();
777 RouteUI::update_monitoring_display ()
783 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
789 MonitorState ms = t->monitoring_state();
791 if (t->monitoring_choice() & MonitorInput) {
792 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
794 if (ms & MonitoringInput) {
795 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
797 monitor_input_button->unset_active_state ();
801 if (t->monitoring_choice() & MonitorDisk) {
802 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
804 if (ms & MonitoringDisk) {
805 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
807 monitor_disk_button->unset_active_state ();
813 RouteUI::monitor_input_press(GdkEventButton*)
819 RouteUI::monitor_input_release(GdkEventButton* ev)
821 return monitor_release (ev, MonitorInput);
825 RouteUI::monitor_disk_press (GdkEventButton*)
831 RouteUI::monitor_disk_release (GdkEventButton* ev)
833 return monitor_release (ev, MonitorDisk);
837 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
839 if (ev->button != 1) {
843 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
850 boost::shared_ptr<RouteList> rl;
852 /* XXX for now, monitoring choices are orthogonal. cue monitoring
853 will follow in 3.X but requires mixing the input and playback (disk)
854 signal together, which requires yet more buffers.
857 if (t->monitoring_choice() & monitor_choice) {
858 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
860 /* this line will change when the options are non-orthogonal */
861 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
865 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
866 rl = _session->get_routes ();
868 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
869 if (_route->route_group() && _route->route_group()->is_monitoring()) {
870 rl = _route->route_group()->route_list();
872 rl.reset (new RouteList);
873 rl->push_back (route());
876 rl.reset (new RouteList);
877 rl->push_back (route());
881 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
887 RouteUI::build_record_menu ()
893 /* no rec-button context menu for non-MIDI tracks
896 if (is_midi_track()) {
897 record_menu = new Menu;
898 record_menu->set_name ("ArdourContextMenu");
900 using namespace Menu_Helpers;
901 MenuList& items = record_menu->items();
903 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
904 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
906 if (_route->record_enabled()) {
907 step_edit_item->set_sensitive (false);
910 step_edit_item->set_active (midi_track()->step_editing());
915 RouteUI::toggle_step_edit ()
917 if (!is_midi_track() || _route->record_enabled()) {
921 midi_track()->set_step_editing (step_edit_item->get_active());
925 RouteUI::step_edit_changed (bool yn)
928 if (rec_enable_button) {
929 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
932 start_step_editing ();
934 if (step_edit_item) {
935 step_edit_item->set_active (true);
940 if (rec_enable_button) {
941 rec_enable_button->unset_active_state ();
944 stop_step_editing ();
946 if (step_edit_item) {
947 step_edit_item->set_active (false);
953 RouteUI::rec_enable_release (GdkEventButton* ev)
955 if (Keyboard::is_context_menu_event (ev)) {
956 build_record_menu ();
958 record_menu->popup (1, ev->time);
967 RouteUI::build_sends_menu ()
969 using namespace Menu_Helpers;
971 sends_menu = new Menu;
972 sends_menu->set_name ("ArdourContextMenu");
973 MenuList& items = sends_menu->items();
976 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
980 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
984 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
988 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
992 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
996 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
999 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1003 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1006 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1007 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1008 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1013 RouteUI::create_sends (Placement p, bool include_buses)
1015 _session->globally_add_internal_sends (_route, p, include_buses);
1019 RouteUI::create_selected_sends (Placement p, bool include_buses)
1021 boost::shared_ptr<RouteList> rlist (new RouteList);
1022 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1024 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1025 RouteTimeAxisView* rtv;
1027 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1028 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1029 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1030 rlist->push_back (rui->route());
1036 _session->add_internal_sends (_route, p, rlist);
1040 RouteUI::set_sends_gain_from_track ()
1042 _session->globally_set_send_gains_from_track (_route);
1046 RouteUI::set_sends_gain_to_zero ()
1048 _session->globally_set_send_gains_to_zero (_route);
1052 RouteUI::set_sends_gain_to_unity ()
1054 _session->globally_set_send_gains_to_unity (_route);
1058 RouteUI::show_sends_press(GdkEventButton* ev)
1060 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1064 if (!is_track() && show_sends_button) {
1066 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1068 // do nothing on midi sigc::bind event
1071 } else if (Keyboard::is_context_menu_event (ev)) {
1073 if (sends_menu == 0) {
1074 build_sends_menu ();
1077 sends_menu->popup (0, ev->time);
1081 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1084 set_showing_sends_to (boost::shared_ptr<Route> ());
1086 set_showing_sends_to (_route);
1095 RouteUI::show_sends_release (GdkEventButton*)
1101 RouteUI::send_blink (bool onoff)
1103 if (!show_sends_button) {
1108 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1110 show_sends_button->unset_active_state ();
1114 Gtkmm2ext::ActiveState
1115 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1117 if (r->is_master() || r->is_monitor()) {
1118 return Gtkmm2ext::Off;
1121 if (Config->get_solo_control_is_listen_control()) {
1123 if (r->listening_via_monitor()) {
1124 return Gtkmm2ext::ExplicitActive;
1126 return Gtkmm2ext::Off;
1132 if (!r->self_soloed()) {
1133 return Gtkmm2ext::ImplicitActive;
1135 return Gtkmm2ext::ExplicitActive;
1138 return Gtkmm2ext::Off;
1142 Gtkmm2ext::ActiveState
1143 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1145 if (r->is_master() || r->is_monitor()) {
1146 return Gtkmm2ext::Off;
1149 if (r->solo_isolated()) {
1150 return Gtkmm2ext::ExplicitActive;
1152 return Gtkmm2ext::Off;
1156 Gtkmm2ext::ActiveState
1157 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1159 if (r->is_master() || r->is_monitor()) {
1160 return Gtkmm2ext::Off;
1163 if (r->solo_safe()) {
1164 return Gtkmm2ext::ExplicitActive;
1166 return Gtkmm2ext::Off;
1171 RouteUI::update_solo_display ()
1173 bool yn = _route->solo_safe ();
1175 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1176 solo_safe_check->set_active (yn);
1179 yn = _route->solo_isolated ();
1181 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1182 solo_isolated_check->set_active (yn);
1185 set_button_names ();
1187 if (solo_isolated_led) {
1188 if (_route->solo_isolated()) {
1189 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1191 solo_isolated_led->unset_active_state ();
1195 if (solo_safe_led) {
1196 if (_route->solo_safe()) {
1197 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1199 solo_safe_led->unset_active_state ();
1203 solo_button->set_active_state (solo_active_state (_route));
1205 /* some changes to solo status can affect mute display, so catch up
1208 update_mute_display ();
1212 RouteUI::solo_changed_so_update_mute ()
1214 update_mute_display ();
1218 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1220 if (r->is_monitor()) {
1221 return ActiveState(0);
1225 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1229 return Gtkmm2ext::ExplicitActive;
1230 } else if (r->muted_by_others()) {
1231 return Gtkmm2ext::ImplicitActive;
1233 /* no mute at all */
1234 return Gtkmm2ext::Off;
1241 return Gtkmm2ext::ExplicitActive;
1243 /* no mute at all */
1244 return Gtkmm2ext::Off;
1248 return ActiveState(0);
1252 RouteUI::update_mute_display ()
1258 mute_button->set_active_state (mute_active_state (_session, _route));
1262 RouteUI::route_rec_enable_changed ()
1264 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1265 update_monitoring_display ();
1269 RouteUI::session_rec_enable_changed ()
1271 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1272 update_monitoring_display ();
1276 RouteUI::blink_rec_display (bool blinkOn)
1278 if (!rec_enable_button || !_route) {
1281 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1285 if (_route->record_enabled()) {
1286 switch (_session->record_status ()) {
1287 case Session::Recording:
1288 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1291 case Session::Disabled:
1292 case Session::Enabled:
1293 if ( UIConfiguration::instance().get_blink_rec_arm() )
1294 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1296 rec_enable_button->set_active_state ( ImplicitActive );
1301 if (step_edit_item) {
1302 step_edit_item->set_sensitive (false);
1306 rec_enable_button->unset_active_state ();
1308 if (step_edit_item) {
1309 step_edit_item->set_sensitive (true);
1313 check_rec_enable_sensitivity ();
1317 RouteUI::build_solo_menu (void)
1319 using namespace Menu_Helpers;
1321 solo_menu = new Menu;
1322 solo_menu->set_name ("ArdourContextMenu");
1323 MenuList& items = solo_menu->items();
1324 Gtk::CheckMenuItem* check;
1326 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1327 check->set_active (_route->solo_isolated());
1328 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1329 items.push_back (CheckMenuElem(*check));
1330 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1333 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1334 check->set_active (_route->solo_safe());
1335 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1336 items.push_back (CheckMenuElem(*check));
1337 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1340 //items.push_back (SeparatorElem());
1341 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1346 RouteUI::build_mute_menu(void)
1348 using namespace Menu_Helpers;
1350 mute_menu = new Menu;
1351 mute_menu->set_name ("ArdourContextMenu");
1353 MenuList& items = mute_menu->items();
1355 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1356 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1357 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1358 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1359 pre_fader_mute_check->show_all();
1361 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1362 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1363 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1364 items.push_back (CheckMenuElem(*post_fader_mute_check));
1365 post_fader_mute_check->show_all();
1367 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1368 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1369 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1370 items.push_back (CheckMenuElem(*listen_mute_check));
1371 listen_mute_check->show_all();
1373 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1374 init_mute_menu(MuteMaster::Main, main_mute_check);
1375 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1376 items.push_back (CheckMenuElem(*main_mute_check));
1377 main_mute_check->show_all();
1379 //items.push_back (SeparatorElem());
1380 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1382 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1386 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1388 check->set_active (_route->mute_points() & mp);
1392 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1394 if (check->get_active()) {
1395 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1397 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1402 RouteUI::muting_change ()
1404 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1407 MuteMaster::MutePoint current = _route->mute_points ();
1409 yn = (current & MuteMaster::PreFader);
1411 if (pre_fader_mute_check->get_active() != yn) {
1412 pre_fader_mute_check->set_active (yn);
1415 yn = (current & MuteMaster::PostFader);
1417 if (post_fader_mute_check->get_active() != yn) {
1418 post_fader_mute_check->set_active (yn);
1421 yn = (current & MuteMaster::Listen);
1423 if (listen_mute_check->get_active() != yn) {
1424 listen_mute_check->set_active (yn);
1427 yn = (current & MuteMaster::Main);
1429 if (main_mute_check->get_active() != yn) {
1430 main_mute_check->set_active (yn);
1435 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1437 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1441 bool view = solo_isolated_led->active_state();
1442 bool model = _route->solo_isolated();
1444 /* called BEFORE the view has changed */
1446 if (ev->button == 1) {
1447 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1450 /* disable isolate for all routes */
1451 DisplaySuspender ds;
1452 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1454 /* enable isolate for all routes */
1455 DisplaySuspender ds;
1456 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1461 if (model == view) {
1463 /* flip just this route */
1465 boost::shared_ptr<RouteList> rl (new RouteList);
1466 rl->push_back (_route);
1467 DisplaySuspender ds;
1468 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1477 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1479 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1483 bool view = solo_safe_led->active_state();
1484 bool model = _route->solo_safe();
1486 if (ev->button == 1) {
1487 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1488 boost::shared_ptr<RouteList> rl (_session->get_routes());
1490 /* disable solo safe for all routes */
1491 DisplaySuspender ds;
1492 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1493 (*i)->set_solo_safe (false, Controllable::NoGroup);
1496 /* enable solo safe for all routes */
1497 DisplaySuspender ds;
1498 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1499 (*i)->set_solo_safe (true, Controllable::NoGroup);
1504 if (model == view) {
1505 /* flip just this route */
1506 _route->set_solo_safe (!view, Controllable::NoGroup);
1515 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1517 bool view = check->get_active();
1518 bool model = _route->solo_isolated();
1520 /* called AFTER the view has changed */
1522 if (model != view) {
1523 _route->set_solo_isolated (view, Controllable::UseGroup);
1528 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1530 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1533 /** Ask the user to choose a colour, and then apply that color to my route
1536 RouteUI::choose_color ()
1539 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1546 /** Set the route's own color. This may not be used for display if
1547 * the route is in a group which shares its color with its routes.
1550 RouteUI::set_color (const Gdk::Color & c)
1552 /* leave _color alone in the group case so that tracks can retain their
1553 * own pre-group colors.
1558 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1560 /* note: we use the route state ID here so that color is the same for both
1561 the time axis view and the mixer strip
1564 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1565 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1568 /** @return GUI state ID for things that are common to the route in all its representations */
1570 RouteUI::route_state_id () const
1572 return string_compose (X_("route %1"), _route->id().to_s());
1576 RouteUI::set_color_from_route ()
1578 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1586 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1589 _color.set_green (g);
1590 _color.set_blue (b);
1595 /** @return true if this name should be used for the route, otherwise false */
1597 RouteUI::verify_new_route_name (const std::string& name)
1599 if (name.find (':') == string::npos) {
1603 MessageDialog colon_msg (
1604 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1605 false, MESSAGE_QUESTION, BUTTONS_NONE
1608 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1609 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1611 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1615 RouteUI::route_rename ()
1617 ArdourPrompter name_prompter (true);
1622 name_prompter.set_title (_("Rename Track"));
1624 name_prompter.set_title (_("Rename Bus"));
1626 name_prompter.set_prompt (_("New name:"));
1627 name_prompter.set_initial_text (_route->name());
1628 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1629 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1630 name_prompter.show_all ();
1633 switch (name_prompter.run ()) {
1634 case Gtk::RESPONSE_ACCEPT:
1635 name_prompter.get_result (result);
1636 name_prompter.hide ();
1637 if (result.length()) {
1638 if (verify_new_route_name (result)) {
1639 _route->set_name (result);
1642 /* back to name prompter */
1646 /* nothing entered, just get out of here */
1661 RouteUI::property_changed (const PropertyChange& what_changed)
1663 if (what_changed.contains (ARDOUR::Properties::name)) {
1664 name_label.set_text (_route->name());
1669 RouteUI::toggle_comment_editor ()
1671 // if (ignore_toggle) {
1675 if (comment_window && comment_window->is_visible ()) {
1676 comment_window->hide ();
1678 open_comment_editor ();
1684 RouteUI::open_comment_editor ()
1686 if (comment_window == 0) {
1687 setup_comment_editor ();
1691 title = _route->name();
1692 title += _(": comment editor");
1694 comment_window->set_title (title);
1695 comment_window->present();
1699 RouteUI::setup_comment_editor ()
1701 comment_window = new ArdourWindow (""); // title will be reset to show route
1702 comment_window->set_skip_taskbar_hint (true);
1703 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1704 comment_window->set_default_size (400, 200);
1706 comment_area = manage (new TextView());
1707 comment_area->set_name ("MixerTrackCommentArea");
1708 comment_area->set_wrap_mode (WRAP_WORD);
1709 comment_area->set_editable (true);
1710 comment_area->get_buffer()->set_text (_route->comment());
1711 comment_area->show ();
1713 comment_window->add (*comment_area);
1717 RouteUI::comment_changed ()
1719 ignore_comment_edit = true;
1721 comment_area->get_buffer()->set_text (_route->comment());
1723 ignore_comment_edit = false;
1727 RouteUI::comment_editor_done_editing ()
1729 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1731 string const str = comment_area->get_buffer()->get_text();
1732 if (str == _route->comment ()) {
1736 _route->set_comment (str, this);
1740 RouteUI::set_route_active (bool a, bool apply_to_selection)
1742 if (apply_to_selection) {
1743 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1745 _route->set_active (a, this);
1750 RouteUI::duplicate_selected_routes ()
1752 ARDOUR_UI::instance()->start_duplicate_routes();
1756 RouteUI::toggle_denormal_protection ()
1758 if (denormal_menu_item) {
1762 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1764 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1765 _route->set_denormal_protection (x);
1771 RouteUI::denormal_protection_changed ()
1773 if (denormal_menu_item) {
1774 denormal_menu_item->set_active (_route->denormal_protection());
1779 RouteUI::disconnect_input ()
1781 _route->input()->disconnect (this);
1785 RouteUI::disconnect_output ()
1787 _route->output()->disconnect (this);
1791 RouteUI::is_track () const
1793 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1796 boost::shared_ptr<Track>
1797 RouteUI::track() const
1799 return boost::dynamic_pointer_cast<Track>(_route);
1803 RouteUI::is_audio_track () const
1805 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1808 boost::shared_ptr<AudioTrack>
1809 RouteUI::audio_track() const
1811 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1815 RouteUI::is_midi_track () const
1817 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1820 boost::shared_ptr<MidiTrack>
1821 RouteUI::midi_track() const
1823 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1827 RouteUI::has_audio_outputs () const
1829 return (_route->n_outputs().n_audio() > 0);
1833 RouteUI::name() const
1835 return _route->name();
1839 RouteUI::map_frozen ()
1841 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1843 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1846 check_rec_enable_sensitivity ();
1851 RouteUI::adjust_latency ()
1853 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1857 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1860 std::string safe_name;
1863 prompter.get_result (name, true);
1865 safe_name = legalize_for_path (name);
1866 safe_name += template_suffix;
1868 path = Glib::build_filename (dir, safe_name);
1870 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1871 bool overwrite = overwrite_file_dialog (prompter,
1872 _("Confirm Template Overwrite"),
1873 _("A template already exists with that name. Do you want to overwrite it?"));
1880 _route->save_as_template (path, name);
1886 RouteUI::save_as_template ()
1890 dir = ARDOUR::user_route_template_directory ();
1892 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1893 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1897 ArdourPrompter prompter (true); // modal
1899 prompter.set_title (_("Save As Template"));
1900 prompter.set_prompt (_("Template name:"));
1901 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1903 bool finished = false;
1905 switch (prompter.run()) {
1906 case RESPONSE_ACCEPT:
1907 finished = process_save_template_prompter (prompter, dir);
1917 RouteUI::check_rec_enable_sensitivity ()
1919 if (!rec_enable_button) {
1920 assert (0); // This should not happen
1923 if (!_session->writable()) {
1924 rec_enable_button->set_sensitive (false);
1928 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1929 rec_enable_button->set_sensitive (false);
1930 } else if (_route && _route->record_safe ()) {
1931 rec_enable_button->set_sensitive (false);
1933 boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(_route);
1935 switch (at->freeze_state()) {
1936 case AudioTrack::Frozen:
1937 rec_enable_button->set_sensitive (false);
1940 rec_enable_button->set_sensitive (true);
1944 rec_enable_button->set_sensitive (true);
1948 update_monitoring_display ();
1952 RouteUI::parameter_changed (string const & p)
1954 /* this handles RC and per-session parameter changes */
1956 if (p == "disable-disarm-during-roll") {
1957 check_rec_enable_sensitivity ();
1958 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1959 set_button_names ();
1960 } else if (p == "auto-input") {
1961 update_monitoring_display ();
1962 } else if (p == "blink-rec-arm") {
1963 if (UIConfiguration::instance().get_blink_rec_arm()) {
1964 rec_blink_connection.disconnect ();
1965 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1967 rec_blink_connection.disconnect ();
1968 RouteUI::blink_rec_display(false);
1974 RouteUI::step_gain_up ()
1976 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1980 RouteUI::page_gain_up ()
1982 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1986 RouteUI::step_gain_down ()
1988 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1992 RouteUI::page_gain_down ()
1994 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1998 RouteUI::open_remote_control_id_dialog ()
2000 ArdourDialog dialog (_("Remote Control ID"));
2001 SpinButton* spin = 0;
2003 dialog.get_vbox()->set_border_width (18);
2005 if (Config->get_remote_model() == UserOrdered) {
2006 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2008 HBox* hbox = manage (new HBox);
2009 hbox->set_spacing (6);
2010 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2011 spin = manage (new SpinButton);
2012 spin->set_digits (0);
2013 spin->set_increments (1, 10);
2014 spin->set_range (0, limit);
2015 spin->set_value (_route->remote_control_id());
2016 hbox->pack_start (*spin);
2017 dialog.get_vbox()->pack_start (*hbox);
2019 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2020 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2022 Label* l = manage (new Label());
2023 if (_route->is_master() || _route->is_monitor()) {
2024 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2025 "The remote control ID of %3 cannot be changed."),
2026 Gtkmm2ext::markup_escape_text (_route->name()),
2027 _route->remote_control_id(),
2028 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2030 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2031 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2032 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2033 (is_track() ? _("track") : _("bus")),
2034 _route->remote_control_id(),
2035 "<span size=\"small\" style=\"italic\">",
2037 Gtkmm2ext::markup_escape_text (_route->name()),
2040 dialog.get_vbox()->pack_start (*l);
2041 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2045 int const r = dialog.run ();
2047 if (r == RESPONSE_ACCEPT && spin) {
2048 _route->set_remote_control_id (spin->get_value_as_int ());
2053 RouteUI::setup_invert_buttons ()
2055 /* remove old invert buttons */
2056 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2057 _invert_button_box.remove (**i);
2060 _invert_buttons.clear ();
2062 if (!_route || !_route->input()) {
2066 uint32_t const N = _route->input()->n_ports().n_audio ();
2068 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2070 for (uint32_t i = 0; i < to_add; ++i) {
2071 ArdourButton* b = manage (new ArdourButton);
2072 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2073 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2075 b->set_name (X_("invert button"));
2078 b->set_text (string_compose (X_("Ø (%1)"), N));
2080 b->set_text (X_("Ø"));
2083 b->set_text (string_compose (X_("Ø%1"), i + 1));
2086 if (N <= _max_invert_buttons) {
2087 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));
2089 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2092 _invert_buttons.push_back (b);
2093 _invert_button_box.pack_start (*b);
2096 _invert_button_box.set_spacing (1);
2097 _invert_button_box.show_all ();
2101 RouteUI::set_invert_button_state ()
2103 uint32_t const N = _route->input()->n_ports().n_audio();
2104 if (N > _max_invert_buttons) {
2106 /* One button for many channels; explicit active if all channels are inverted,
2107 implicit active if some are, off if none are.
2110 ArdourButton* b = _invert_buttons.front ();
2112 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2113 b->set_active_state (Gtkmm2ext::ExplicitActive);
2114 } else if (_route->phase_invert().any()) {
2115 b->set_active_state (Gtkmm2ext::ImplicitActive);
2117 b->set_active_state (Gtkmm2ext::Off);
2122 /* One button per channel; just set active */
2125 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2126 (*i)->set_active (_route->phase_invert (j));
2133 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2135 if (ev->button == 1 && i < _invert_buttons.size()) {
2136 uint32_t const N = _route->input()->n_ports().n_audio ();
2137 if (N <= _max_invert_buttons) {
2138 /* left-click inverts phase so long as we have a button per channel */
2139 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2148 RouteUI::invert_press (GdkEventButton* ev)
2150 using namespace Menu_Helpers;
2152 uint32_t const N = _route->input()->n_ports().n_audio();
2153 if (N <= _max_invert_buttons && ev->button != 3) {
2154 /* If we have an invert button per channel, we only pop
2155 up a menu on right-click; left click is handled
2161 delete _invert_menu;
2162 _invert_menu = new Menu;
2163 _invert_menu->set_name ("ArdourContextMenu");
2164 MenuList& items = _invert_menu->items ();
2166 for (uint32_t i = 0; i < N; ++i) {
2167 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2168 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2169 ++_i_am_the_modifier;
2170 e->set_active (_route->phase_invert (i));
2171 --_i_am_the_modifier;
2174 _invert_menu->popup (0, ev->time);
2180 RouteUI::invert_menu_toggled (uint32_t c)
2182 if (_i_am_the_modifier) {
2186 _route->set_phase_invert (c, !_route->phase_invert (c));
2190 RouteUI::set_invert_sensitive (bool yn)
2192 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2193 (*b)->set_sensitive (yn);
2198 RouteUI::request_redraw ()
2201 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2205 /** The Route's gui_changed signal has been emitted */
2207 RouteUI::route_gui_changed (string what_changed)
2209 if (what_changed == "color") {
2210 if (set_color_from_route () == 0) {
2211 route_color_changed ();
2217 RouteUI::track_mode_changed (void)
2220 switch (track()->mode()) {
2221 case ARDOUR::NonLayered:
2222 case ARDOUR::Normal:
2223 rec_enable_button->set_icon (ArdourIcon::RecButton);
2225 case ARDOUR::Destructive:
2226 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2229 rec_enable_button->queue_draw();
2232 /** @return the color that this route should use; it maybe its own,
2233 or it maybe that of its route group.
2236 RouteUI::color () const
2238 RouteGroup* g = _route->route_group ();
2240 if (g && g->is_color()) {
2242 set_color_from_rgba (c, GroupTabs::group_color (g));
2250 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2252 _showing_sends_to = send_to;
2253 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2257 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2259 if (_route == send_to) {
2260 show_sends_button->set_active (true);
2261 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2263 show_sends_button->set_active (false);
2264 send_blink_connection.disconnect ();
2269 RouteUI::route_group() const
2271 return _route->route_group();
2275 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2276 : WM::ProxyBase (name, string())
2277 , _route (boost::weak_ptr<Route> (route))
2279 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2282 RoutePinWindowProxy::~RoutePinWindowProxy()
2287 ARDOUR::SessionHandlePtr*
2288 RoutePinWindowProxy::session_handle ()
2290 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2291 if (aw) { return aw; }
2296 RoutePinWindowProxy::get (bool create)
2298 boost::shared_ptr<Route> r = _route.lock ();
2307 _window = new PluginPinDialog (r);
2308 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2310 aw->set_session (_session);
2312 _window->show_all ();
2318 RoutePinWindowProxy::route_going_away ()
2322 WM::Manager::instance().remove (this);
2323 going_away_connection.disconnect();
2327 RouteUI::maybe_add_route_print_mgr ()
2329 if (_route->pinmgr_proxy ()) {
2332 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2333 string_compose ("RPM-%1", _route->id()), _route);
2334 wp->set_session (_session);
2336 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2338 wp->set_state (*ui_xml, 0);
2342 void* existing_ui = _route->pinmgr_proxy ();
2344 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2347 _route->set_pingmgr_proxy (wp);
2349 WM::Manager::instance().register_window (wp);
2353 RouteUI::manage_pins ()
2355 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();