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 <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/choice.h>
22 #include <gtkmm2ext/doi.h>
23 #include <gtkmm2ext/bindable_button.h>
24 #include <gtkmm2ext/barcontroller.h>
25 #include <gtkmm2ext/gtk_ui.h>
26 #include <gtkmm2ext/utils.h>
28 #include "ardour/route_group.h"
29 #include "ardour/dB.h"
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
35 #include "ardour_ui.h"
38 #include "ardour_button.h"
42 #include "gui_thread.h"
43 #include "ardour_dialog.h"
44 #include "latency_gui.h"
45 #include "mixer_strip.h"
46 #include "automation_time_axis.h"
47 #include "route_time_axis.h"
48 #include "group_tabs.h"
50 #include "ardour/audio_track.h"
51 #include "ardour/audioengine.h"
52 #include "ardour/filename_extensions.h"
53 #include "ardour/midi_track.h"
54 #include "ardour/internal_send.h"
55 #include "ardour/send.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/template_utils.h"
62 using namespace Gtkmm2ext;
63 using namespace ARDOUR;
64 using namespace ARDOUR_UI_UTILS;
67 uint32_t RouteUI::_max_invert_buttons = 3;
68 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
69 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
71 static const int _button_vpad = 2;
73 RouteUI::RouteUI (ARDOUR::Session* sess)
90 _route.reset (); /* drop reference to route, so that it can be cleaned up */
91 route_connections.drop_connections ();
97 delete comment_window;
98 delete input_selector;
99 delete output_selector;
102 send_blink_connection.disconnect ();
103 rec_blink_connection.disconnect ();
109 self_destruct = true;
115 pre_fader_mute_check = 0;
116 post_fader_mute_check = 0;
117 listen_mute_check = 0;
120 solo_isolated_check = 0;
121 solo_isolated_led = 0;
125 denormal_menu_item = 0;
127 multiple_mute_change = false;
128 multiple_solo_change = false;
129 _i_am_the_modifier = 0;
134 setup_invert_buttons ();
136 mute_button = manage (new ArdourButton);
137 mute_button->set_name ("mute button");
138 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
140 solo_button = manage (new ArdourButton);
141 solo_button->set_name ("solo button");
142 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
143 solo_button->set_no_show_all (true);
145 rec_enable_button = manage (new ArdourButton);
146 rec_enable_button->set_name ("record enable button");
147 rec_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::RecButton));
148 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
150 rec_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
152 show_sends_button = manage (new ArdourButton);
153 show_sends_button->set_name ("send alert button");
154 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
156 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
157 monitor_input_button->set_name ("monitor button");
158 monitor_input_button->set_text (_("In"));
159 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
160 monitor_input_button->set_no_show_all (true);
162 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
163 monitor_disk_button->set_name ("monitor button");
164 monitor_disk_button->set_text (_("Disk"));
165 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
166 monitor_disk_button->set_no_show_all (true);
168 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
169 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
170 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
172 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
173 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
175 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
176 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
178 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
179 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
181 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
182 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
183 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
184 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
186 monitor_input_button->set_distinct_led_click (false);
187 monitor_disk_button->set_distinct_led_click (false);
189 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
190 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
192 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
193 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
195 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
201 route_connections.drop_connections ();
209 denormal_menu_item = 0;
213 RouteUI::self_delete ()
219 RouteUI::set_route (boost::shared_ptr<Route> rp)
225 if (set_color_from_route()) {
226 set_color (unique_random_color());
230 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
233 delete input_selector;
236 delete output_selector;
239 mute_button->set_controllable (_route->mute_control());
240 solo_button->set_controllable (_route->solo_control());
242 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
243 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::mute_changed, this, _1), gui_context());
245 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this, _1), gui_context());
247 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
248 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
249 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
250 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
252 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
253 track_mode_changed();
256 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
257 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
259 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
260 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
262 if (_session->writable() && is_track()) {
263 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
265 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
267 rec_enable_button->show();
268 rec_enable_button->set_controllable (t->rec_enable_control());
270 if (is_midi_track()) {
271 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
272 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
277 /* this will work for busses and tracks, and needs to be called to
278 set up the name entry/name label display.
282 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
283 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
285 update_monitoring_display ();
288 mute_button->unset_flags (Gtk::CAN_FOCUS);
289 solo_button->unset_flags (Gtk::CAN_FOCUS);
293 if (_route->is_monitor() || _route->is_master()) {
294 solo_button->hide ();
301 setup_invert_buttons ();
302 set_invert_button_state ();
304 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
305 bus_send_display_changed (s);
307 update_mute_display ();
308 update_solo_display ();
310 route_color_changed();
314 RouteUI::polarity_changed ()
320 set_invert_button_state ();
324 RouteUI::mute_press (GdkEventButton* ev)
326 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
330 //if this is a binding action, let the ArdourButton handle it
331 if ( BindingProxy::is_bind_action(ev) )
334 multiple_mute_change = false;
336 if (Keyboard::is_context_menu_event (ev)) {
342 mute_menu->popup(0,ev->time);
348 if (Keyboard::is_button2_event (ev)) {
349 // button2-click is "momentary"
351 _mute_release = new SoloMuteRelease (_route->muted ());
354 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
356 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
358 /* toggle mute on everything (but
359 * exclude the master and monitor)
361 * because we are going to erase
362 * elements of the list we need to work
366 boost::shared_ptr<RouteList> copy (new RouteList);
368 *copy = *_session->get_routes ();
370 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
371 if ((*i)->is_master() || (*i)->is_monitor()) {
379 _mute_release->routes = copy;
383 _session->set_mute (copy, !_route->muted());
385 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
387 /* Primary-button1 applies change to the mix group even if it is not active
388 NOTE: Primary-button2 is MIDI learn.
391 boost::shared_ptr<RouteList> rl;
393 if (ev->button == 1) {
395 if (_route->route_group()) {
397 rl = _route->route_group()->route_list();
400 _mute_release->routes = rl;
403 rl.reset (new RouteList);
404 rl->push_back (_route);
408 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, true);
413 /* plain click applies change to this route */
415 boost::shared_ptr<RouteList> rl (new RouteList);
416 rl->push_back (_route);
419 _mute_release->routes = rl;
422 _session->set_mute (rl, !_route->muted());
432 RouteUI::mute_release (GdkEventButton* /*ev*/)
436 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
437 delete _mute_release;
445 RouteUI::edit_output_configuration ()
447 if (output_selector == 0) {
449 boost::shared_ptr<Send> send;
450 boost::shared_ptr<IO> output;
452 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
453 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
454 output = send->output();
456 output = _route->output ();
459 output = _route->output ();
462 output_selector = new IOSelectorWindow (_session, output);
465 if (output_selector->is_visible()) {
466 output_selector->get_toplevel()->get_window()->raise();
468 output_selector->present ();
471 output_selector->set_keep_above (true);
475 RouteUI::edit_input_configuration ()
477 if (input_selector == 0) {
478 input_selector = new IOSelectorWindow (_session, _route->input());
481 if (input_selector->is_visible()) {
482 input_selector->get_toplevel()->get_window()->raise();
484 input_selector->present ();
487 input_selector->set_keep_above (true);
491 RouteUI::solo_press(GdkEventButton* ev)
493 /* ignore double/triple clicks */
495 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
499 //if this is a binding action, let the ArdourButton handle it
500 if ( BindingProxy::is_bind_action(ev) )
503 multiple_solo_change = false;
505 if (Keyboard::is_context_menu_event (ev)) {
507 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
508 ! (solo_safe_led && solo_safe_led->is_visible())) {
510 if (solo_menu == 0) {
514 solo_menu->popup (1, ev->time);
519 if (Keyboard::is_button2_event (ev)) {
521 // button2-click is "momentary"
522 _solo_release = new SoloMuteRelease (_route->self_soloed());
525 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
527 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
529 /* Primary-Tertiary-click applies change to all routes */
532 _solo_release->routes = _session->get_routes ();
536 if (Config->get_solo_control_is_listen_control()) {
537 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
539 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
542 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
544 // Primary-Secondary-click: exclusively solo this track
547 _solo_release->exclusive = true;
549 boost::shared_ptr<RouteList> routes = _session->get_routes();
551 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
552 if ((*i)->soloed ()) {
553 _solo_release->routes_on->push_back (*i);
555 _solo_release->routes_off->push_back (*i);
560 if (Config->get_solo_control_is_listen_control()) {
561 /* ??? we need a just_one_listen() method */
564 _session->set_just_one_solo (_route, true);
567 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
569 // shift-click: toggle solo isolated status
571 _route->set_solo_isolated (!_route->solo_isolated(), this);
572 delete _solo_release;
575 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
577 /* Primary-button1: solo mix group.
578 NOTE: Primary-button2 is MIDI learn.
581 /* Primary-button1 applies change to the mix group even if it is not active
582 NOTE: Primary-button2 is MIDI learn.
585 boost::shared_ptr<RouteList> rl;
587 if (ev->button == 1) {
589 if (_route->route_group()) {
591 rl = _route->route_group()->route_list();
594 _solo_release->routes = rl;
597 rl.reset (new RouteList);
598 rl->push_back (_route);
602 if (Config->get_solo_control_is_listen_control()) {
603 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, true);
605 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, true);
611 /* click: solo this route */
613 boost::shared_ptr<RouteList> rl (new RouteList);
614 rl->push_back (route());
617 _solo_release->routes = rl;
621 if (Config->get_solo_control_is_listen_control()) {
622 _session->set_listen (rl, !_route->listening_via_monitor());
624 _session->set_solo (rl, !_route->self_soloed());
634 RouteUI::solo_release (GdkEventButton* /*ev*/)
638 if (_solo_release->exclusive) {
642 if (Config->get_solo_control_is_listen_control()) {
643 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
645 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
649 delete _solo_release;
657 RouteUI::rec_enable_press(GdkEventButton* ev)
659 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
663 //if this is a binding action, let the ArdourButton handle it
664 if ( BindingProxy::is_bind_action(ev) )
667 if (!_session->engine().connected()) {
668 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
673 if (is_midi_track()) {
675 /* rec-enable button exits from step editing */
677 if (midi_track()->step_editing()) {
678 midi_track()->set_step_editing (false);
683 if (is_track() && rec_enable_button) {
685 if (Keyboard::is_button2_event (ev)) {
687 //rec arm does not have a momentary mode
690 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
693 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
695 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
697 /* Primary-button1 applies change to the route group (even if it is not active)
698 NOTE: Primary-button2 is MIDI learn.
701 if (ev->button == 1) {
703 boost::shared_ptr<RouteList> rl;
705 if (_route->route_group()) {
707 rl = _route->route_group()->route_list();
710 rl.reset (new RouteList);
711 rl->push_back (_route);
715 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, true);
718 } else if (Keyboard::is_context_menu_event (ev)) {
720 /* do this on release */
724 boost::shared_ptr<RouteList> rl (new RouteList);
725 rl->push_back (route());
727 _session->set_record_enabled (rl, !_route->record_enabled());
735 RouteUI::monitoring_changed ()
737 update_monitoring_display ();
741 RouteUI::update_monitoring_display ()
747 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
753 MonitorState ms = t->monitoring_state();
755 if (t->monitoring_choice() & MonitorInput) {
756 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
758 if (ms & MonitoringInput) {
759 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
761 monitor_input_button->unset_active_state ();
765 if (t->monitoring_choice() & MonitorDisk) {
766 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
768 if (ms & MonitoringDisk) {
769 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
771 monitor_disk_button->unset_active_state ();
777 RouteUI::monitor_input_press(GdkEventButton*)
783 RouteUI::monitor_input_release(GdkEventButton* ev)
785 return monitor_release (ev, MonitorInput);
789 RouteUI::monitor_disk_press (GdkEventButton*)
795 RouteUI::monitor_disk_release (GdkEventButton* ev)
797 return monitor_release (ev, MonitorDisk);
801 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
803 if (ev->button != 1) {
807 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
814 boost::shared_ptr<RouteList> rl;
816 /* XXX for now, monitoring choices are orthogonal. cue monitoring
817 will follow in 3.X but requires mixing the input and playback (disk)
818 signal together, which requires yet more buffers.
821 if (t->monitoring_choice() & monitor_choice) {
822 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
824 /* this line will change when the options are non-orthogonal */
825 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
829 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
830 rl = _session->get_routes ();
832 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
833 if (_route->route_group() && _route->route_group()->is_monitoring()) {
834 rl = _route->route_group()->route_list();
836 rl.reset (new RouteList);
837 rl->push_back (route());
840 rl.reset (new RouteList);
841 rl->push_back (route());
845 _session->set_monitoring (rl, mc, Session::rt_cleanup, true);
851 RouteUI::build_record_menu ()
857 /* no rec-button context menu for non-MIDI tracks
860 if (is_midi_track()) {
861 record_menu = new Menu;
862 record_menu->set_name ("ArdourContextMenu");
864 using namespace Menu_Helpers;
865 MenuList& items = record_menu->items();
867 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
868 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
870 if (_route->record_enabled()) {
871 step_edit_item->set_sensitive (false);
874 step_edit_item->set_active (midi_track()->step_editing());
879 RouteUI::toggle_step_edit ()
881 if (!is_midi_track() || _route->record_enabled()) {
885 midi_track()->set_step_editing (step_edit_item->get_active());
889 RouteUI::step_edit_changed (bool yn)
892 if (rec_enable_button) {
893 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
896 start_step_editing ();
898 if (step_edit_item) {
899 step_edit_item->set_active (true);
904 if (rec_enable_button) {
905 rec_enable_button->unset_active_state ();
908 stop_step_editing ();
910 if (step_edit_item) {
911 step_edit_item->set_active (false);
917 RouteUI::rec_enable_release (GdkEventButton* ev)
919 if (Keyboard::is_context_menu_event (ev)) {
920 build_record_menu ();
922 record_menu->popup (1, ev->time);
931 RouteUI::build_sends_menu ()
933 using namespace Menu_Helpers;
935 sends_menu = new Menu;
936 sends_menu->set_name ("ArdourContextMenu");
937 MenuList& items = sends_menu->items();
940 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
944 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
948 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
952 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
956 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
960 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
963 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
967 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
970 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
971 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
972 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
977 RouteUI::create_sends (Placement p, bool include_buses)
979 _session->globally_add_internal_sends (_route, p, include_buses);
983 RouteUI::create_selected_sends (Placement p, bool include_buses)
985 boost::shared_ptr<RouteList> rlist (new RouteList);
986 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
988 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
989 RouteTimeAxisView* rtv;
991 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
992 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
993 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
994 rlist->push_back (rui->route());
1000 _session->add_internal_sends (_route, p, rlist);
1004 RouteUI::set_sends_gain_from_track ()
1006 _session->globally_set_send_gains_from_track (_route);
1010 RouteUI::set_sends_gain_to_zero ()
1012 _session->globally_set_send_gains_to_zero (_route);
1016 RouteUI::set_sends_gain_to_unity ()
1018 _session->globally_set_send_gains_to_unity (_route);
1022 RouteUI::show_sends_press(GdkEventButton* ev)
1024 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1028 if (!is_track() && show_sends_button) {
1030 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1032 // do nothing on midi sigc::bind event
1035 } else if (Keyboard::is_context_menu_event (ev)) {
1037 if (sends_menu == 0) {
1038 build_sends_menu ();
1041 sends_menu->popup (0, ev->time);
1045 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1048 set_showing_sends_to (boost::shared_ptr<Route> ());
1050 set_showing_sends_to (_route);
1059 RouteUI::show_sends_release (GdkEventButton*)
1065 RouteUI::send_blink (bool onoff)
1067 if (!show_sends_button) {
1072 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1074 show_sends_button->unset_active_state ();
1078 Gtkmm2ext::ActiveState
1079 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1081 if (r->is_master() || r->is_monitor()) {
1082 return Gtkmm2ext::Off;
1085 if (Config->get_solo_control_is_listen_control()) {
1087 if (r->listening_via_monitor()) {
1088 return Gtkmm2ext::ExplicitActive;
1090 return Gtkmm2ext::Off;
1096 if (!r->self_soloed()) {
1097 return Gtkmm2ext::ImplicitActive;
1099 return Gtkmm2ext::ExplicitActive;
1102 return Gtkmm2ext::Off;
1106 Gtkmm2ext::ActiveState
1107 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1109 if (r->is_master() || r->is_monitor()) {
1110 return Gtkmm2ext::Off;
1113 if (r->solo_isolated()) {
1114 return Gtkmm2ext::ExplicitActive;
1116 return Gtkmm2ext::Off;
1120 Gtkmm2ext::ActiveState
1121 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1123 if (r->is_master() || r->is_monitor()) {
1124 return Gtkmm2ext::Off;
1127 if (r->solo_safe()) {
1128 return Gtkmm2ext::ExplicitActive;
1130 return Gtkmm2ext::Off;
1135 RouteUI::update_solo_display ()
1137 bool yn = _route->solo_safe ();
1139 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1140 solo_safe_check->set_active (yn);
1143 yn = _route->solo_isolated ();
1145 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1146 solo_isolated_check->set_active (yn);
1149 set_button_names ();
1151 if (solo_isolated_led) {
1152 if (_route->solo_isolated()) {
1153 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1155 solo_isolated_led->unset_active_state ();
1159 if (solo_safe_led) {
1160 if (_route->solo_safe()) {
1161 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1163 solo_safe_led->unset_active_state ();
1167 solo_button->set_active_state (solo_active_state (_route));
1169 /* some changes to solo status can affect mute display, so catch up
1172 update_mute_display ();
1176 RouteUI::solo_changed_so_update_mute ()
1178 update_mute_display ();
1182 RouteUI::mute_changed(void* /*src*/)
1184 update_mute_display ();
1188 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1190 if (r->is_monitor()) {
1191 return ActiveState(0);
1195 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1199 return Gtkmm2ext::ExplicitActive;
1200 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1201 /* master is NEVER muted by others */
1202 return Gtkmm2ext::ImplicitActive;
1204 /* no mute at all */
1205 return Gtkmm2ext::Off;
1212 return Gtkmm2ext::ExplicitActive;
1214 /* no mute at all */
1215 return Gtkmm2ext::Off;
1219 return ActiveState(0);
1223 RouteUI::update_mute_display ()
1229 mute_button->set_active_state (mute_active_state (_session, _route));
1233 RouteUI::route_rec_enable_changed ()
1235 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1236 update_monitoring_display ();
1240 RouteUI::session_rec_enable_changed ()
1242 update_monitoring_display ();
1246 RouteUI::blink_rec_display (bool blinkOn)
1248 if (!rec_enable_button || !_route) {
1252 if (_route->record_enabled()) {
1253 switch (_session->record_status ()) {
1254 case Session::Recording:
1255 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1258 case Session::Disabled:
1259 case Session::Enabled:
1260 if ( ARDOUR_UI::config()->get_blink_rec_arm() )
1261 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1263 rec_enable_button->set_active_state ( ImplicitActive );
1268 if (step_edit_item) {
1269 step_edit_item->set_sensitive (false);
1273 rec_enable_button->unset_active_state ();
1275 if (step_edit_item) {
1276 step_edit_item->set_sensitive (true);
1281 check_rec_enable_sensitivity ();
1285 RouteUI::build_solo_menu (void)
1287 using namespace Menu_Helpers;
1289 solo_menu = new Menu;
1290 solo_menu->set_name ("ArdourContextMenu");
1291 MenuList& items = solo_menu->items();
1292 Gtk::CheckMenuItem* check;
1294 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1295 check->set_active (_route->solo_isolated());
1296 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1297 items.push_back (CheckMenuElem(*check));
1298 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1301 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1302 check->set_active (_route->solo_safe());
1303 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1304 items.push_back (CheckMenuElem(*check));
1305 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1308 //items.push_back (SeparatorElem());
1309 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1314 RouteUI::build_mute_menu(void)
1316 using namespace Menu_Helpers;
1318 mute_menu = new Menu;
1319 mute_menu->set_name ("ArdourContextMenu");
1321 MenuList& items = mute_menu->items();
1323 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1324 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1325 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1326 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1327 pre_fader_mute_check->show_all();
1329 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1330 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1331 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1332 items.push_back (CheckMenuElem(*post_fader_mute_check));
1333 post_fader_mute_check->show_all();
1335 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1336 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1337 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1338 items.push_back (CheckMenuElem(*listen_mute_check));
1339 listen_mute_check->show_all();
1341 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1342 init_mute_menu(MuteMaster::Main, main_mute_check);
1343 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1344 items.push_back (CheckMenuElem(*main_mute_check));
1345 main_mute_check->show_all();
1347 //items.push_back (SeparatorElem());
1348 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1350 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1354 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1356 check->set_active (_route->mute_points() & mp);
1360 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1362 if (check->get_active()) {
1363 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1365 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1370 RouteUI::muting_change ()
1372 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1375 MuteMaster::MutePoint current = _route->mute_points ();
1377 yn = (current & MuteMaster::PreFader);
1379 if (pre_fader_mute_check->get_active() != yn) {
1380 pre_fader_mute_check->set_active (yn);
1383 yn = (current & MuteMaster::PostFader);
1385 if (post_fader_mute_check->get_active() != yn) {
1386 post_fader_mute_check->set_active (yn);
1389 yn = (current & MuteMaster::Listen);
1391 if (listen_mute_check->get_active() != yn) {
1392 listen_mute_check->set_active (yn);
1395 yn = (current & MuteMaster::Main);
1397 if (main_mute_check->get_active() != yn) {
1398 main_mute_check->set_active (yn);
1403 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1405 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1409 bool view = solo_isolated_led->active_state();
1410 bool model = _route->solo_isolated();
1412 /* called BEFORE the view has changed */
1414 if (ev->button == 1) {
1415 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1418 /* disable isolate for all routes */
1419 DisplaySuspender ds;
1420 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1424 if (model == view) {
1426 /* flip just this route */
1428 boost::shared_ptr<RouteList> rl (new RouteList);
1429 rl->push_back (_route);
1430 DisplaySuspender ds;
1431 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1440 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1442 if (ev->button == 1) {
1443 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1449 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1451 bool view = check->get_active();
1452 bool model = _route->solo_isolated();
1454 /* called AFTER the view has changed */
1456 if (model != view) {
1457 _route->set_solo_isolated (view, this);
1462 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1464 _route->set_solo_safe (check->get_active(), this);
1467 /** Ask the user to choose a colour, and then apply that color to my route
1470 RouteUI::choose_color ()
1473 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1480 /** Set the route's own color. This may not be used for display if
1481 * the route is in a group which shares its color with its routes.
1484 RouteUI::set_color (const Gdk::Color & c)
1486 /* leave _color alone in the group case so that tracks can retain their
1487 * own pre-group colors.
1492 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1494 /* note: we use the route state ID here so that color is the same for both
1495 the time axis view and the mixer strip
1498 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1499 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1502 /** @return GUI state ID for things that are common to the route in all its representations */
1504 RouteUI::route_state_id () const
1506 return string_compose (X_("route %1"), _route->id().to_s());
1510 RouteUI::set_color_from_route ()
1512 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1520 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1523 _color.set_green (g);
1524 _color.set_blue (b);
1530 RouteUI::remove_this_route (bool apply_to_selection)
1532 if (apply_to_selection) {
1533 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1535 if ((route()->is_master() || route()->is_monitor()) &&
1536 !Config->get_allow_special_bus_removal()) {
1537 MessageDialog msg (_("That would be bad news ...."),
1541 msg.set_secondary_text (string_compose (_(
1542 "Removing the master or monitor bus is such a bad idea\n\
1543 that %1 is not going to allow it.\n\
1545 If you really want to do this sort of thing\n\
1546 edit your ardour.rc file to set the\n\
1547 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1554 vector<string> choices;
1558 prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1560 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1563 choices.push_back (_("No, do nothing."));
1564 choices.push_back (_("Yes, remove it."));
1568 title = _("Remove track");
1570 title = _("Remove bus");
1573 Choice prompter (title, prompt, choices);
1575 if (prompter.run () == 1) {
1576 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1582 RouteUI::idle_remove_this_route (RouteUI *rui)
1584 DisplaySuspender ds;
1585 rui->_session->remove_route (rui->route());
1589 /** @return true if this name should be used for the route, otherwise false */
1591 RouteUI::verify_new_route_name (const std::string& name)
1593 if (name.find (':') == string::npos) {
1597 MessageDialog colon_msg (
1598 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1599 false, MESSAGE_QUESTION, BUTTONS_NONE
1602 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1603 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1605 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1609 RouteUI::route_rename ()
1611 ArdourPrompter name_prompter (true);
1616 name_prompter.set_title (_("Rename Track"));
1618 name_prompter.set_title (_("Rename Bus"));
1620 name_prompter.set_prompt (_("New name:"));
1621 name_prompter.set_initial_text (_route->name());
1622 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1623 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1624 name_prompter.show_all ();
1627 switch (name_prompter.run ()) {
1628 case Gtk::RESPONSE_ACCEPT:
1629 name_prompter.get_result (result);
1630 name_prompter.hide ();
1631 if (result.length()) {
1632 if (verify_new_route_name (result)) {
1633 _route->set_name (result);
1636 /* back to name prompter */
1640 /* nothing entered, just get out of here */
1655 RouteUI::property_changed (const PropertyChange& what_changed)
1657 if (what_changed.contains (ARDOUR::Properties::name)) {
1658 name_label.set_text (_route->name());
1663 RouteUI::toggle_comment_editor ()
1665 // if (ignore_toggle) {
1669 if (comment_window && comment_window->is_visible ()) {
1670 comment_window->hide ();
1672 open_comment_editor ();
1678 RouteUI::open_comment_editor ()
1680 if (comment_window == 0) {
1681 setup_comment_editor ();
1685 title = _route->name();
1686 title += _(": comment editor");
1688 comment_window->set_title (title);
1689 comment_window->present();
1693 RouteUI::setup_comment_editor ()
1695 comment_window = new ArdourWindow (""); // title will be reset to show route
1696 comment_window->set_skip_taskbar_hint (true);
1697 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1698 comment_window->set_default_size (400, 200);
1700 comment_area = manage (new TextView());
1701 comment_area->set_name ("MixerTrackCommentArea");
1702 comment_area->set_wrap_mode (WRAP_WORD);
1703 comment_area->set_editable (true);
1704 comment_area->get_buffer()->set_text (_route->comment());
1705 comment_area->show ();
1707 comment_window->add (*comment_area);
1711 RouteUI::comment_changed (void *src)
1713 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_changed, src)
1716 ignore_comment_edit = true;
1718 comment_area->get_buffer()->set_text (_route->comment());
1720 ignore_comment_edit = false;
1725 RouteUI::comment_editor_done_editing ()
1727 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1729 string const str = comment_area->get_buffer()->get_text();
1730 if (str == _route->comment ()) {
1734 _route->set_comment (str, this);
1738 RouteUI::set_route_active (bool a, bool apply_to_selection)
1740 if (apply_to_selection) {
1741 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1743 _route->set_active (a, this);
1748 RouteUI::toggle_denormal_protection ()
1750 if (denormal_menu_item) {
1754 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1756 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1757 _route->set_denormal_protection (x);
1763 RouteUI::denormal_protection_changed ()
1765 if (denormal_menu_item) {
1766 denormal_menu_item->set_active (_route->denormal_protection());
1771 RouteUI::disconnect_input ()
1773 _route->input()->disconnect (this);
1777 RouteUI::disconnect_output ()
1779 _route->output()->disconnect (this);
1783 RouteUI::is_track () const
1785 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1788 boost::shared_ptr<Track>
1789 RouteUI::track() const
1791 return boost::dynamic_pointer_cast<Track>(_route);
1795 RouteUI::is_audio_track () const
1797 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1800 boost::shared_ptr<AudioTrack>
1801 RouteUI::audio_track() const
1803 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1807 RouteUI::is_midi_track () const
1809 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1812 boost::shared_ptr<MidiTrack>
1813 RouteUI::midi_track() const
1815 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1819 RouteUI::has_audio_outputs () const
1821 return (_route->n_outputs().n_audio() > 0);
1825 RouteUI::name() const
1827 return _route->name();
1831 RouteUI::map_frozen ()
1833 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1835 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1838 switch (at->freeze_state()) {
1839 case AudioTrack::Frozen:
1840 rec_enable_button->set_sensitive (false);
1843 rec_enable_button->set_sensitive (true);
1850 RouteUI::adjust_latency ()
1852 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1856 RouteUI::save_as_template ()
1859 std::string safe_name;
1862 path = ARDOUR::user_route_template_directory ();
1864 if (g_mkdir_with_parents (path.c_str(), 0755)) {
1865 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1869 Prompter p (true); // modal
1871 p.set_title (_("Save As Template"));
1872 p.set_prompt (_("Template name:"));
1873 p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1875 case RESPONSE_ACCEPT:
1882 p.get_result (name, true);
1884 safe_name = legalize_for_path (name);
1885 safe_name += template_suffix;
1887 path = Glib::build_filename (path, safe_name);
1889 _route->save_as_template (path, name);
1893 RouteUI::check_rec_enable_sensitivity ()
1895 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1896 rec_enable_button->set_sensitive (false);
1898 rec_enable_button->set_sensitive (true);
1901 update_monitoring_display ();
1905 RouteUI::parameter_changed (string const & p)
1907 /* this handles RC and per-session parameter changes */
1909 if (p == "disable-disarm-during-roll") {
1910 check_rec_enable_sensitivity ();
1911 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1912 set_button_names ();
1913 } else if (p == "auto-input") {
1914 update_monitoring_display ();
1919 RouteUI::step_gain_up ()
1921 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1925 RouteUI::page_gain_up ()
1927 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1931 RouteUI::step_gain_down ()
1933 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1937 RouteUI::page_gain_down ()
1939 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1943 RouteUI::open_remote_control_id_dialog ()
1945 ArdourDialog dialog (_("Remote Control ID"));
1946 SpinButton* spin = 0;
1948 dialog.get_vbox()->set_border_width (18);
1950 if (Config->get_remote_model() == UserOrdered) {
1951 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1953 HBox* hbox = manage (new HBox);
1954 hbox->set_spacing (6);
1955 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1956 spin = manage (new SpinButton);
1957 spin->set_digits (0);
1958 spin->set_increments (1, 10);
1959 spin->set_range (0, limit);
1960 spin->set_value (_route->remote_control_id());
1961 hbox->pack_start (*spin);
1962 dialog.get_vbox()->pack_start (*hbox);
1964 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1965 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1967 Label* l = manage (new Label());
1968 if (_route->is_master() || _route->is_monitor()) {
1969 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
1970 "The remote control ID of %3 cannot be changed."),
1971 Glib::Markup::escape_text (_route->name()),
1972 _route->remote_control_id(),
1973 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
1975 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
1976 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
1977 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
1978 (is_track() ? _("track") : _("bus")),
1979 _route->remote_control_id(),
1980 "<span size=\"small\" style=\"italic\">",
1982 Glib::Markup::escape_text (_route->name()),
1985 dialog.get_vbox()->pack_start (*l);
1986 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1990 int const r = dialog.run ();
1992 if (r == RESPONSE_ACCEPT && spin) {
1993 _route->set_remote_control_id (spin->get_value_as_int ());
1998 RouteUI::setup_invert_buttons ()
2000 /* remove old invert buttons */
2001 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2002 _invert_button_box.remove (**i);
2005 _invert_buttons.clear ();
2007 if (!_route || !_route->input()) {
2011 uint32_t const N = _route->input()->n_ports().n_audio ();
2013 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2015 for (uint32_t i = 0; i < to_add; ++i) {
2016 ArdourButton* b = manage (new ArdourButton);
2017 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2018 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2020 b->set_name (X_("invert button"));
2023 b->set_text (string_compose (X_("Ø (%1)"), N));
2025 b->set_text (X_("Ø"));
2028 b->set_text (string_compose (X_("Ø%1"), i + 1));
2031 if (N <= _max_invert_buttons) {
2032 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));
2034 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2037 _invert_buttons.push_back (b);
2038 _invert_button_box.pack_start (*b);
2041 _invert_button_box.set_spacing (1);
2042 _invert_button_box.show_all ();
2046 RouteUI::set_invert_button_state ()
2048 uint32_t const N = _route->input()->n_ports().n_audio();
2049 if (N > _max_invert_buttons) {
2051 /* One button for many channels; explicit active if all channels are inverted,
2052 implicit active if some are, off if none are.
2055 ArdourButton* b = _invert_buttons.front ();
2057 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2058 b->set_active_state (Gtkmm2ext::ExplicitActive);
2059 } else if (_route->phase_invert().any()) {
2060 b->set_active_state (Gtkmm2ext::ImplicitActive);
2062 b->set_active_state (Gtkmm2ext::Off);
2067 /* One button per channel; just set active */
2070 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2071 (*i)->set_active (_route->phase_invert (j));
2078 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2080 if (ev->button == 1 && i < _invert_buttons.size()) {
2081 uint32_t const N = _route->input()->n_ports().n_audio ();
2082 if (N <= _max_invert_buttons) {
2083 /* left-click inverts phase so long as we have a button per channel */
2084 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2093 RouteUI::invert_press (GdkEventButton* ev)
2095 using namespace Menu_Helpers;
2097 uint32_t const N = _route->input()->n_ports().n_audio();
2098 if (N <= _max_invert_buttons && ev->button != 3) {
2099 /* If we have an invert button per channel, we only pop
2100 up a menu on right-click; left click is handled
2106 delete _invert_menu;
2107 _invert_menu = new Menu;
2108 _invert_menu->set_name ("ArdourContextMenu");
2109 MenuList& items = _invert_menu->items ();
2111 for (uint32_t i = 0; i < N; ++i) {
2112 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2113 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2114 ++_i_am_the_modifier;
2115 e->set_active (_route->phase_invert (i));
2116 --_i_am_the_modifier;
2119 _invert_menu->popup (0, ev->time);
2125 RouteUI::invert_menu_toggled (uint32_t c)
2127 if (_i_am_the_modifier) {
2131 _route->set_phase_invert (c, !_route->phase_invert (c));
2135 RouteUI::set_invert_sensitive (bool yn)
2137 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2138 (*b)->set_sensitive (yn);
2143 RouteUI::request_redraw ()
2146 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2150 /** The Route's gui_changed signal has been emitted */
2152 RouteUI::route_gui_changed (string what_changed)
2154 if (what_changed == "color") {
2155 if (set_color_from_route () == 0) {
2156 route_color_changed ();
2162 RouteUI::track_mode_changed (void)
2165 switch (track()->mode()) {
2166 case ARDOUR::NonLayered:
2167 case ARDOUR::Normal:
2168 rec_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::RecButton));
2170 case ARDOUR::Destructive:
2171 rec_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::RecButton|ArdourButton::RecTapeMode));
2174 rec_enable_button->queue_draw();
2177 /** @return the color that this route should use; it maybe its own,
2178 or it maybe that of its route group.
2181 RouteUI::color () const
2183 RouteGroup* g = _route->route_group ();
2185 if (g && g->is_color()) {
2187 set_color_from_rgba (c, GroupTabs::group_color (g));
2195 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2197 _showing_sends_to = send_to;
2198 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2202 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2204 if (_route == send_to) {
2205 show_sends_button->set_active (true);
2206 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2208 show_sends_button->set_active (false);
2209 send_blink_connection.disconnect ();
2214 RouteUI::route_group() const
2216 return _route->route_group();