2 Copyright (C) 2000-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.
23 #include <sigc++/bind.h>
25 #include "pbd/convert.h"
26 #include "pbd/enumwriter.h"
27 #include "pbd/replace_all.h"
28 #include "pbd/stacktrace.h"
30 #include <gtkmm2ext/gtk_ui.h>
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/choice.h>
33 #include <gtkmm2ext/doi.h>
34 #include <gtkmm2ext/slider_controller.h>
35 #include <gtkmm2ext/bindable_button.h>
37 #include "ardour/amp.h"
38 #include "ardour/audio_track.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/internal_send.h"
41 #include "ardour/io.h"
42 #include "ardour/meter.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/pannable.h"
45 #include "ardour/panner.h"
46 #include "ardour/panner_shell.h"
47 #include "ardour/panner_manager.h"
48 #include "ardour/port.h"
49 #include "ardour/profile.h"
50 #include "ardour/route.h"
51 #include "ardour/route_group.h"
52 #include "ardour/send.h"
53 #include "ardour/session.h"
54 #include "ardour/types.h"
55 #include "ardour/user_bundle.h"
56 #include "ardour/vca.h"
57 #include "ardour/vca_manager.h"
59 #include "ardour_window.h"
60 #include "mixer_strip.h"
63 #include "ardour_button.h"
64 #include "public_editor.h"
66 #include "io_selector.h"
68 #include "gui_thread.h"
69 #include "route_group_menu.h"
70 #include "meter_patterns.h"
72 #include "ui_config.h"
76 using namespace ARDOUR;
77 using namespace ARDOUR_UI_UTILS;
80 using namespace Gtkmm2ext;
82 using namespace ArdourMeter;
84 MixerStrip* MixerStrip::_entered_mixer_strip;
85 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
87 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
88 : SessionHandlePtr (sess)
91 , _mixer_owned (in_mixer)
92 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
95 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
96 , rec_mon_table (2, 2)
97 , solo_iso_table (1, 2)
98 , mute_solo_table (1, 2)
99 , bottom_button_table (1, 3)
100 , monitor_section_button (0)
101 , midi_input_enable_button (0)
102 , _plugin_insert_cnt (0)
103 , _comment_button (_("Comments"))
104 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
105 , _visibility (X_("mixer-element-visibility"))
106 , control_slave_ui (sess)
111 /* the editor mixer strip: don't destroy it every time
112 the underlying route goes away.
115 self_destruct = false;
119 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
120 : SessionHandlePtr (sess)
123 , _mixer_owned (in_mixer)
124 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
127 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
128 , rec_mon_table (2, 2)
129 , solo_iso_table (1, 2)
130 , mute_solo_table (1, 2)
131 , bottom_button_table (1, 3)
132 , monitor_section_button (0)
133 , midi_input_enable_button (0)
134 , _plugin_insert_cnt (0)
135 , _comment_button (_("Comments"))
136 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
137 , _visibility (X_("mixer-element-visibility"))
138 , control_slave_ui (sess)
147 _entered_mixer_strip= 0;
150 ignore_comment_edit = false;
151 ignore_toggle = false;
155 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
156 longest_label = "longest label";
158 string t = _("Click to toggle the width of this mixer strip.");
160 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
163 width_button.set_icon (ArdourIcon::StripWidth);
164 hide_button.set_tweaks (ArdourButton::Square);
165 set_tooltip (width_button, t);
167 hide_button.set_icon (ArdourIcon::CloseCross);
168 hide_button.set_tweaks (ArdourButton::Square);
169 set_tooltip (&hide_button, _("Hide this mixer strip"));
171 input_button_box.set_spacing(2);
173 input_button.set_text (_("Input"));
174 input_button.set_name ("mixer strip button");
175 input_button_box.pack_start (input_button, true, true);
177 output_button.set_text (_("Output"));
178 output_button.set_name ("mixer strip button");
180 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
182 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
184 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
185 solo_isolated_led->show ();
186 solo_isolated_led->set_no_show_all (true);
187 solo_isolated_led->set_name (X_("solo isolate"));
188 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
189 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
190 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
192 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
193 solo_safe_led->show ();
194 solo_safe_led->set_no_show_all (true);
195 solo_safe_led->set_name (X_("solo safe"));
196 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
197 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
198 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
200 solo_safe_led->set_text (S_("SoloLock|Lock"));
201 solo_isolated_led->set_text (_("Iso"));
203 solo_iso_table.set_homogeneous (true);
204 solo_iso_table.set_spacings (2);
205 if (!ARDOUR::Profile->get_trx()) {
206 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
207 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
209 solo_iso_table.show ();
211 rec_mon_table.set_homogeneous (true);
212 rec_mon_table.set_row_spacings (2);
213 rec_mon_table.set_col_spacings (2);
214 if (ARDOUR::Profile->get_mixbus()) {
215 rec_mon_table.resize (1, 3);
216 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
217 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
218 } else if (!ARDOUR::Profile->get_trx()) {
219 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
220 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
222 rec_mon_table.show ();
224 if (solo_isolated_led) {
225 button_size_group->add_widget (*solo_isolated_led);
228 button_size_group->add_widget (*solo_safe_led);
231 if (!ARDOUR::Profile->get_mixbus()) {
232 if (rec_enable_button) {
233 button_size_group->add_widget (*rec_enable_button);
235 if (monitor_disk_button) {
236 button_size_group->add_widget (*monitor_disk_button);
238 if (monitor_input_button) {
239 button_size_group->add_widget (*monitor_input_button);
243 mute_solo_table.set_homogeneous (true);
244 mute_solo_table.set_spacings (2);
246 bottom_button_table.set_spacings (2);
247 bottom_button_table.set_homogeneous (true);
248 bottom_button_table.attach (group_button, 1, 2, 0, 1);
249 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
251 name_button.set_name ("mixer strip button");
252 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
253 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
255 set_tooltip (&group_button, _("Mix group"));
256 group_button.set_name ("mixer strip button");
258 _comment_button.set_name (X_("mixer strip button"));
259 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
260 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
261 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
263 // TODO implement ArdourKnob::on_size_request properly
264 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
265 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
267 trim_control.set_tooltip_prefix (_("Trim: "));
268 trim_control.set_name ("trim knob");
269 trim_control.set_no_show_all (true);
270 input_button_box.pack_start (trim_control, false, false);
272 global_vpacker.set_border_width (1);
273 global_vpacker.set_spacing (0);
275 width_button.set_name ("mixer strip button");
276 hide_button.set_name ("mixer strip button");
278 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
279 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
281 width_hide_box.set_spacing (2);
282 width_hide_box.pack_start (width_button, false, true);
283 width_hide_box.pack_start (number_label, true, true);
284 width_hide_box.pack_end (hide_button, false, true);
286 number_label.set_text ("-");
287 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
288 number_label.set_no_show_all ();
289 number_label.set_name ("tracknumber label");
290 number_label.set_fixed_colors (0x80808080, 0x80808080);
291 number_label.set_alignment (.5, .5);
292 number_label.set_fallthrough_to_parent (true);
293 number_label.set_tweaks (ArdourButton::OccasionalText);
295 global_vpacker.set_spacing (2);
296 if (!ARDOUR::Profile->get_trx()) {
297 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
298 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
299 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
300 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
301 global_vpacker.pack_start (processor_box, true, true);
303 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
310 if (!ARDOUR::Profile->get_trx()) {
311 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
318 //add a spacer underneath the master bus;
319 //this fills the area that is taken up by the scrollbar on the tracks;
320 //and therefore keeps the faders "even" across the bottom
321 int scrollbar_height = 0;
323 Gtk::Window window (WINDOW_TOPLEVEL);
324 HScrollbar scrollbar;
325 window.add (scrollbar);
326 scrollbar.set_name ("MixerWindow");
327 scrollbar.ensure_style();
328 Gtk::Requisition requisition(scrollbar.size_request ());
329 scrollbar_height = requisition.height;
331 spacer.set_size_request (-1, scrollbar_height);
332 global_vpacker.pack_end (spacer, false, false);
335 global_frame.add (global_vpacker);
336 global_frame.set_shadow_type (Gtk::SHADOW_IN);
337 global_frame.set_name ("BaseFrame");
341 /* force setting of visible selected status */
344 set_selected (false);
349 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
350 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
352 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
353 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
354 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
356 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
357 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
359 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
360 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
361 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
363 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
365 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
367 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
371 /* start off as a passthru strip. we'll correct this, if necessary,
372 in update_diskstream_display().
375 /* start off as a passthru strip. we'll correct this, if necessary,
376 in update_diskstream_display().
379 if (is_midi_track()) {
380 set_name ("MidiTrackStripBase");
382 set_name ("AudioTrackStripBase");
385 add_events (Gdk::BUTTON_RELEASE_MASK|
386 Gdk::ENTER_NOTIFY_MASK|
387 Gdk::LEAVE_NOTIFY_MASK|
389 Gdk::KEY_RELEASE_MASK);
391 set_flags (get_flags() | Gtk::CAN_FOCUS);
393 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
394 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
397 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
398 must be the same as those used in RCOptionEditor so that the configuration changes
399 are recognised when they occur.
401 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
402 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
403 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
404 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
405 _visibility.add (&output_button, X_("Output"), _("Output"), false);
406 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
407 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
409 parameter_changed (X_("mixer-element-visibility"));
410 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
411 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
412 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
414 //watch for mouse enter/exit so we can do some stuff
415 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
416 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
418 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
421 MixerStrip::~MixerStrip ()
423 CatchDeletion (this);
425 if (this ==_entered_mixer_strip)
426 _entered_mixer_strip = NULL;
430 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
432 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
434 sl->assign(vca, false);
438 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
440 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
446 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
448 _entered_mixer_strip = this;
450 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
451 //because the mixerstrip control is a parent that encompasses the strip
452 deselect_all_processors();
458 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
460 //if we have moved outside our strip, but not into a child view, then deselect ourselves
461 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
462 _entered_mixer_strip= 0;
464 //clear keyboard focus in the gain display. this is cheesy but fixes a longstanding "bug" where the user starts typing in the gain entry, and leaves it active, thereby prohibiting other keybindings from working
465 gpm.gain_display.set_sensitive(false);
467 gpm.gain_display.set_sensitive(true);
469 //if we leave this mixer strip we need to clear out any selections
470 //processor_box.processor_display.select_none(); //but this doesn't work, because it gets triggered when (for example) you open the menu or start a drag
477 MixerStrip::name() const
480 return _route->name();
486 MixerStrip::update_trim_control ()
488 if (route()->trim() && route()->trim()->active() &&
489 route()->n_inputs().n_audio() > 0) {
490 trim_control.show ();
491 trim_control.set_controllable (route()->trim()->gain_control());
493 trim_control.hide ();
494 boost::shared_ptr<Controllable> none;
495 trim_control.set_controllable (none);
500 MixerStrip::set_route (boost::shared_ptr<Route> rt)
502 //the rec/monitor stuff only shows up for tracks.
503 //the show_sends only shows up for buses.
504 //remove them all here, and we may add them back later
505 if (show_sends_button->get_parent()) {
506 rec_mon_table.remove (*show_sends_button);
508 if (rec_enable_button->get_parent()) {
509 rec_mon_table.remove (*rec_enable_button);
511 if (monitor_input_button->get_parent()) {
512 rec_mon_table.remove (*monitor_input_button);
514 if (monitor_disk_button->get_parent()) {
515 rec_mon_table.remove (*monitor_disk_button);
517 if (group_button.get_parent()) {
518 bottom_button_table.remove (group_button);
521 RouteUI::set_route (rt);
523 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
525 /* ProcessorBox needs access to _route so that it can read
528 processor_box.set_route (rt);
530 revert_to_default_display ();
532 /* unpack these from the parent and stuff them into our own
536 if (gpm.peak_display.get_parent()) {
537 gpm.peak_display.get_parent()->remove (gpm.peak_display);
539 if (gpm.gain_display.get_parent()) {
540 gpm.gain_display.get_parent()->remove (gpm.gain_display);
543 gpm.set_type (rt->meter_type());
545 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
546 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
548 if (solo_button->get_parent()) {
549 mute_solo_table.remove (*solo_button);
552 if (mute_button->get_parent()) {
553 mute_solo_table.remove (*mute_button);
556 if (route()->is_master()) {
557 solo_button->hide ();
558 mute_button->show ();
559 rec_mon_table.hide ();
560 solo_iso_table.set_sensitive(false);
561 control_slave_ui.set_sensitive(false);
562 if (monitor_section_button == 0) {
563 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
564 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
566 monitor_section_button = manage (new ArdourButton);
568 monitor_section_button->set_related_action (act);
569 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
570 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
571 monitor_section_button->show();
572 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
574 parameter_changed ("use-monitor-bus");
576 bottom_button_table.attach (group_button, 1, 2, 0, 1);
577 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
578 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
579 mute_button->show ();
580 solo_button->show ();
581 rec_mon_table.show ();
582 solo_iso_table.set_sensitive(true);
583 control_slave_ui.set_sensitive(true);
586 if (_mixer_owned && route()->is_master() ) {
593 monitor_input_button->show ();
594 monitor_disk_button->show ();
596 monitor_input_button->hide();
597 monitor_disk_button->hide ();
600 update_trim_control();
602 if (is_midi_track()) {
603 if (midi_input_enable_button == 0) {
604 midi_input_enable_button = manage (new ArdourButton);
605 midi_input_enable_button->set_name ("midi input button");
606 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
607 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
608 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
609 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
610 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
612 input_button_box.remove (*midi_input_enable_button);
614 /* get current state */
615 midi_input_status_changed ();
616 input_button_box.pack_start (*midi_input_enable_button, false, false);
618 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
620 if (midi_input_enable_button) {
621 /* removal from the container will delete it */
622 input_button_box.remove (*midi_input_enable_button);
623 midi_input_enable_button = 0;
627 if (is_audio_track()) {
628 boost::shared_ptr<AudioTrack> at = audio_track();
629 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
634 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
635 rec_enable_button->show();
637 if (ARDOUR::Profile->get_mixbus()) {
638 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
639 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
640 } else if (ARDOUR::Profile->get_trx()) {
641 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
643 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
644 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
651 if (!_route->is_master()) {
652 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
653 show_sends_button->show();
657 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
659 delete route_ops_menu;
662 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
663 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
664 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
665 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
667 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
669 if (_route->panner_shell()) {
670 update_panner_choices();
671 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
674 if (is_audio_track()) {
675 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
678 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
680 set_stuff_from_route ();
682 /* now force an update of all the various elements */
684 update_mute_display ();
685 update_solo_display ();
688 route_group_changed ();
689 update_track_number_visibility ();
692 panners.setup_pan ();
694 if (has_audio_outputs ()) {
700 update_diskstream_display ();
701 update_input_display ();
702 update_output_display ();
704 add_events (Gdk::BUTTON_RELEASE_MASK);
706 processor_box.show ();
708 if (!route()->is_master() && !route()->is_monitor()) {
709 /* we don't allow master or control routes to be hidden */
714 gpm.reset_peak_display ();
715 gpm.gain_display.show ();
716 gpm.peak_display.show ();
719 width_hide_box.show();
721 global_vpacker.show();
722 mute_solo_table.show();
723 bottom_button_table.show();
725 gpm.meter_point_button.show();
726 input_button_box.show_all();
727 output_button.show();
729 _comment_button.show();
731 gpm.gain_automation_state_button.show();
733 parameter_changed ("mixer-element-visibility");
740 MixerStrip::set_stuff_from_route ()
742 /* if width is not set, it will be set by the MixerUI or editor */
744 string str = gui_property ("strip-width");
746 set_width_enum (Width (string_2_enum (str, _width)), this);
751 MixerStrip::set_width_enum (Width w, void* owner)
753 /* always set the gpm width again, things may be hidden */
756 panners.set_width (w);
758 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
760 _width_owner = owner;
764 if (_width_owner == this) {
765 set_gui_property ("strip-width", enum_2_string (_width));
770 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
775 if (show_sends_button) {
776 show_sends_button->set_text (_("Aux"));
779 gpm.gain_automation_style_button.set_text (
780 gpm.astyle_string(gain_automation->automation_style()));
781 gpm.gain_automation_state_button.set_text (
782 gpm.astate_string(gain_automation->automation_state()));
784 if (_route->panner()) {
785 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
786 panners.astyle_string(_route->panner()->automation_style()));
787 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
788 panners.astate_string(_route->panner()->automation_state()));
792 // panners expect an even number of horiz. pixels
793 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
795 set_size_request (width, -1);
801 if (show_sends_button) {
802 show_sends_button->set_text (_("Snd"));
805 gpm.gain_automation_style_button.set_text (
806 gpm.short_astyle_string(gain_automation->automation_style()));
807 gpm.gain_automation_state_button.set_text (
808 gpm.short_astate_string(gain_automation->automation_state()));
809 gain_meter().setup_meters (); // recalc meter width
811 if (_route->panner()) {
812 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
813 panners.short_astyle_string(_route->panner()->automation_style()));
814 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
815 panners.short_astate_string(_route->panner()->automation_state()));
819 // panners expect an even number of horiz. pixels
820 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
822 set_size_request (width, -1);
827 processor_box.set_width (w);
829 update_input_display ();
830 update_output_display ();
831 setup_comment_button ();
832 route_group_changed ();
838 MixerStrip::set_packed (bool yn)
843 set_gui_property ("visible", true);
845 set_gui_property ("visible", false);
850 struct RouteCompareByName {
851 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
852 return a->name().compare (b->name()) < 0;
857 MixerStrip::output_release (GdkEventButton *ev)
859 switch (ev->button) {
861 edit_output_configuration ();
869 MixerStrip::output_press (GdkEventButton *ev)
871 using namespace Menu_Helpers;
872 if (!_session->engine().connected()) {
873 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
878 MenuList& citems = output_menu.items();
879 switch (ev->button) {
882 return false; //wait for the mouse-up to pop the dialog
886 output_menu.set_name ("ArdourContextMenu");
888 output_menu_bundles.clear ();
890 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
892 citems.push_back (SeparatorElem());
893 uint32_t const n_with_separator = citems.size ();
895 ARDOUR::BundleList current = _route->output()->bundles_connected ();
897 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
899 /* give user bundles first chance at being in the menu */
901 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
902 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
903 maybe_add_bundle_to_output_menu (*i, current);
907 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
908 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
909 maybe_add_bundle_to_output_menu (*i, current);
913 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
914 RouteList copy = *routes;
915 copy.sort (RouteCompareByName ());
916 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
917 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
920 if (citems.size() == n_with_separator) {
921 /* no routes added; remove the separator */
925 if (!ARDOUR::Profile->get_mixbus()) {
926 citems.push_back (SeparatorElem());
928 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
931 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
932 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
938 citems.push_back (SeparatorElem());
939 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
941 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
954 MixerStrip::input_release (GdkEventButton *ev)
956 switch (ev->button) {
959 edit_input_configuration ();
971 MixerStrip::input_press (GdkEventButton *ev)
973 using namespace Menu_Helpers;
975 MenuList& citems = input_menu.items();
976 input_menu.set_name ("ArdourContextMenu");
979 if (!_session->engine().connected()) {
980 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
985 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
988 switch (ev->button) {
991 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
995 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
997 citems.push_back (SeparatorElem());
998 uint32_t const n_with_separator = citems.size ();
1000 input_menu_bundles.clear ();
1002 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1004 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1006 /* give user bundles first chance at being in the menu */
1008 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1009 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1010 maybe_add_bundle_to_input_menu (*i, current);
1014 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1015 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1016 maybe_add_bundle_to_input_menu (*i, current);
1020 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1021 RouteList copy = *routes;
1022 copy.sort (RouteCompareByName ());
1023 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1024 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1027 if (citems.size() == n_with_separator) {
1028 /* no routes added; remove the separator */
1032 citems.push_back (SeparatorElem());
1033 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1036 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1037 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1042 citems.push_back (SeparatorElem());
1043 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1045 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1057 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1059 if (ignore_toggle) {
1063 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1065 if (std::find (current.begin(), current.end(), c) == current.end()) {
1066 _route->input()->connect_ports_to_bundle (c, true, this);
1068 _route->input()->disconnect_ports_from_bundle (c, this);
1073 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1075 if (ignore_toggle) {
1079 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1081 if (std::find (current.begin(), current.end(), c) == current.end()) {
1082 _route->output()->connect_ports_to_bundle (c, true, this);
1084 _route->output()->disconnect_ports_from_bundle (c, this);
1089 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1091 using namespace Menu_Helpers;
1093 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1097 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1098 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1102 if (i != input_menu_bundles.end()) {
1106 input_menu_bundles.push_back (b);
1108 MenuList& citems = input_menu.items();
1110 std::string n = b->name ();
1111 replace_all (n, "_", " ");
1113 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1117 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1119 using namespace Menu_Helpers;
1121 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1125 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1126 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1130 if (i != output_menu_bundles.end()) {
1134 output_menu_bundles.push_back (b);
1136 MenuList& citems = output_menu.items();
1138 std::string n = b->name ();
1139 replace_all (n, "_", " ");
1141 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1145 MixerStrip::update_diskstream_display ()
1147 if (is_track() && input_selector) {
1148 input_selector->hide_all ();
1151 route_color_changed ();
1155 MixerStrip::connect_to_pan ()
1157 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1159 panstate_connection.disconnect ();
1160 panstyle_connection.disconnect ();
1162 if (!_route->panner()) {
1166 boost::shared_ptr<Pannable> p = _route->pannable ();
1168 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1169 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1171 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1172 * However, that only works a panner was previously set.
1174 * PannerUI must remain subscribed to _panshell->Changed() in case
1175 * we switch the panner eg. AUX-Send and back
1176 * _route->panner_shell()->Changed() vs _panshell->Changed
1178 if (panners._panner == 0) {
1179 panners.panshell_changed ();
1181 update_panner_choices();
1185 MixerStrip::update_panner_choices ()
1187 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1188 if (!_route->panner_shell()) { return; }
1190 uint32_t in = _route->output()->n_ports().n_audio();
1192 if (_route->panner()) {
1193 in = _route->panner()->in().n_audio();
1196 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1200 * Output port labelling
1201 * =====================
1203 * Case 1: Each output has one connection, all connections are to system:playback_%i
1204 * out 1 -> system:playback_1
1205 * out 2 -> system:playback_2
1206 * out 3 -> system:playback_3
1209 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1210 * out 1 -> ardour:track_x/in 1
1211 * out 2 -> ardour:track_x/in 2
1212 * Display as: track_x
1214 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1215 * out 1 -> program x:foo
1216 * out 2 -> program x:foo
1217 * Display as: program x
1219 * Case 4: No connections (Disconnected)
1222 * Default case (unusual routing):
1223 * Display as: *number of connections*
1227 * .-----------------------------------------------.
1229 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1230 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1231 * '-----------------------------------------------'
1232 * .-----------------------------------------------.
1235 * '-----------------------------------------------'
1239 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1243 boost::shared_ptr<IO> io;
1244 boost::shared_ptr<Port> port;
1245 vector<string> port_connections;
1247 uint32_t total_connection_count = 0;
1248 uint32_t io_connection_count = 0;
1249 uint32_t ardour_connection_count = 0;
1250 uint32_t system_connection_count = 0;
1251 uint32_t other_connection_count = 0;
1252 uint32_t typed_connection_count = 0;
1254 ostringstream label;
1256 bool have_label = false;
1257 bool each_io_has_one_connection = true;
1259 string connection_name;
1260 string ardour_track_name;
1261 string other_connection_type;
1262 string system_ports;
1265 ostringstream tooltip;
1266 char * tooltip_cstr;
1268 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1270 * First of all, if the user made only connections to a given type, we should use that one since
1271 * it is very probably what the user expects. If there are several connections types, then show
1272 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1273 * synthesisers. This first heuristic can be expressed with these two rules:
1274 * A) If there are connected audio ports, consider audio as primary type.
1275 * B) Else, if there are connected midi ports, consider midi as primary type.
1277 * If there are no connected ports, then we choose the primary type based on the type of existing
1278 * but unconnected ports. Again:
1279 * C) If there are audio ports, consider audio as primary type.
1280 * D) Else, if there are midi ports, consider midi as primary type. */
1282 DataType dt = DataType::AUDIO;
1286 io = route->input();
1288 io = route->output();
1291 io_count = io->n_ports().n_total();
1292 for (io_index = 0; io_index < io_count; ++io_index) {
1293 port = io->nth (io_index);
1294 if (port->connected()) {
1296 if (port->type() == DataType::AUDIO) {
1297 /* Rule A) applies no matter the remaining ports */
1298 dt = DataType::AUDIO;
1301 if (port->type() == DataType::MIDI) {
1302 /* Rule B) is a good candidate... */
1303 dt = DataType::MIDI;
1304 /* ...but continue the loop to check remaining ports for rule A) */
1310 /* Neither rule A) nor rule B) matched */
1311 if ( io->n_ports().n_audio() > 0 ) {
1313 dt = DataType::AUDIO;
1314 } else if ( io->n_ports().n_midi() > 0 ) {
1316 dt = DataType::MIDI;
1320 if ( dt == DataType::MIDI ) {
1321 tooltip << _("MIDI ");
1325 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1327 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1330 for (io_index = 0; io_index < io_count; ++io_index) {
1331 port = io->nth (io_index);
1333 port_connections.clear ();
1334 port->get_connections(port_connections);
1336 //ignore any port connections that don't match our DataType
1337 if (port->type() != dt) {
1338 if (!port_connections.empty()) {
1339 ++typed_connection_count;
1344 io_connection_count = 0;
1346 if (!port_connections.empty()) {
1347 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1349 string& connection_name (*i);
1351 if (connection_name.find("system:") == 0) {
1352 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1355 if (io_connection_count == 0) {
1356 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1358 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1361 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1364 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1365 if (ardour_track_name.empty()) {
1366 // "ardour:Master/in 1" -> "ardour:Master/"
1367 string::size_type slash = connection_name.find("/");
1368 if (slash != string::npos) {
1369 ardour_track_name = connection_name.substr(0, slash + 1);
1373 if (connection_name.find(ardour_track_name) == 0) {
1374 ++ardour_connection_count;
1376 } else if (!pn.empty()) {
1377 if (system_ports.empty()) {
1380 system_ports += "/" + pn;
1382 if (connection_name.find("system:") == 0) {
1383 ++system_connection_count;
1385 } else if (connection_name.find("system:midi_") == 0) {
1387 // "system:midi_capture_123" -> "123"
1388 system_port = "M " + connection_name.substr(20);
1390 // "system:midi_playback_123" -> "123"
1391 system_port = "M " + connection_name.substr(21);
1394 if (system_ports.empty()) {
1395 system_ports += system_port;
1397 system_ports += "/" + system_port;
1400 ++system_connection_count;
1402 } else if (connection_name.find("system:") == 0) {
1404 // "system:capture_123" -> "123"
1405 system_port = connection_name.substr(15);
1407 // "system:playback_123" -> "123"
1408 system_port = connection_name.substr(16);
1411 if (system_ports.empty()) {
1412 system_ports += system_port;
1414 system_ports += "/" + system_port;
1417 ++system_connection_count;
1419 if (other_connection_type.empty()) {
1420 // "jamin:in 1" -> "jamin:"
1421 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1424 if (connection_name.find(other_connection_type) == 0) {
1425 ++other_connection_count;
1429 ++total_connection_count;
1430 ++io_connection_count;
1434 if (io_connection_count != 1) {
1435 each_io_has_one_connection = false;
1439 if (total_connection_count == 0) {
1440 tooltip << endl << _("Disconnected");
1443 tooltip_cstr = new char[tooltip.str().size() + 1];
1444 strcpy(tooltip_cstr, tooltip.str().c_str());
1447 set_tooltip (&input_button, tooltip_cstr);
1449 set_tooltip (&output_button, tooltip_cstr);
1452 delete [] tooltip_cstr;
1454 if (each_io_has_one_connection) {
1455 if (total_connection_count == ardour_connection_count) {
1456 // all connections are to the same track in ardour
1457 // "ardour:Master/" -> "Master"
1458 string::size_type slash = ardour_track_name.find("/");
1459 if (slash != string::npos) {
1460 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1461 label << ardour_track_name.substr (ppps, slash - ppps);
1465 else if (total_connection_count == system_connection_count) {
1466 // all connections are to system ports
1467 label << system_ports;
1470 else if (total_connection_count == other_connection_count) {
1471 // all connections are to the same external program eg jamin
1472 // "jamin:" -> "jamin"
1473 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1479 if (total_connection_count == 0) {
1483 // Odd configuration
1484 label << "*" << total_connection_count << "*";
1486 if (typed_connection_count > 0) {
1487 label << "\u2295"; // circled plus
1492 input_button.set_text (label.str());
1494 output_button.set_text (label.str());
1499 MixerStrip::update_input_display ()
1501 update_io_button (_route, _width, true);
1502 panners.setup_pan ();
1504 if (has_audio_outputs ()) {
1505 panners.show_all ();
1507 panners.hide_all ();
1513 MixerStrip::update_output_display ()
1515 update_io_button (_route, _width, false);
1516 gpm.setup_meters ();
1517 panners.setup_pan ();
1519 if (has_audio_outputs ()) {
1520 panners.show_all ();
1522 panners.hide_all ();
1527 MixerStrip::fast_update ()
1529 gpm.update_meters ();
1533 MixerStrip::diskstream_changed ()
1535 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1539 MixerStrip::io_changed_proxy ()
1541 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1542 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1546 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1548 boost::shared_ptr<Port> a = wa.lock ();
1549 boost::shared_ptr<Port> b = wb.lock ();
1551 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1552 update_input_display ();
1553 set_width_enum (_width, this);
1556 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1557 update_output_display ();
1558 set_width_enum (_width, this);
1563 MixerStrip::setup_comment_button ()
1565 std::string comment = _route->comment();
1567 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1569 if (comment.empty ()) {
1570 _comment_button.set_name ("generic button");
1571 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1575 _comment_button.set_name ("comment button");
1577 string::size_type pos = comment.find_first_of (" \t\n");
1578 if (pos != string::npos) {
1579 comment = comment.substr (0, pos);
1581 if (comment.empty()) {
1582 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1584 _comment_button.set_text (comment);
1589 MixerStrip::select_route_group (GdkEventButton *ev)
1591 using namespace Menu_Helpers;
1593 if (ev->button == 1) {
1595 if (group_menu == 0) {
1597 PropertyList* plist = new PropertyList();
1599 plist->add (Properties::group_gain, true);
1600 plist->add (Properties::group_mute, true);
1601 plist->add (Properties::group_solo, true);
1603 group_menu = new RouteGroupMenu (_session, plist);
1607 r.push_back (route ());
1608 group_menu->build (r);
1610 RouteGroup *rg = _route->route_group();
1612 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1613 rg ? rg->name() : _("No Group"),
1621 MixerStrip::route_group_changed ()
1623 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1625 RouteGroup *rg = _route->route_group();
1628 group_button.set_text (PBD::short_version (rg->name(), 5));
1632 group_button.set_text (_("Grp"));
1635 group_button.set_text (_("~G"));
1642 MixerStrip::route_color_changed ()
1644 name_button.modify_bg (STATE_NORMAL, color());
1645 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1646 reset_strip_style ();
1650 MixerStrip::show_passthru_color ()
1652 reset_strip_style ();
1657 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1659 boost::shared_ptr<Processor> processor (p.lock ());
1660 if (!processor || !processor->display_to_user()) {
1663 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1665 if (pi && pi->is_channelstrip ()) {
1670 ++_plugin_insert_cnt;
1674 MixerStrip::build_route_ops_menu ()
1676 using namespace Menu_Helpers;
1677 route_ops_menu = new Menu;
1678 route_ops_menu->set_name ("ArdourContextMenu");
1680 MenuList& items = route_ops_menu->items();
1682 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1684 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1686 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1688 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1690 if (!Profile->get_mixbus()) {
1691 items.push_back (SeparatorElem());
1694 if (!_route->is_master()
1696 && !_route->mixbus()
1699 if (Profile->get_mixbus()) {
1700 items.push_back (SeparatorElem());
1702 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1705 if (!Profile->get_mixbus()) {
1706 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1707 /* do not allow rename if the track is record-enabled */
1708 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1711 items.push_back (SeparatorElem());
1712 items.push_back (CheckMenuElem (_("Active")));
1713 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1714 i->set_active (_route->active());
1715 i->set_sensitive(! _session->transport_rolling());
1716 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1718 if (!Profile->get_mixbus ()) {
1719 items.push_back (SeparatorElem());
1720 items.push_back (CheckMenuElem (_("Strict I/O")));
1721 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1722 i->set_active (_route->strict_io());
1723 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1726 _plugin_insert_cnt = 0;
1727 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1728 if (_plugin_insert_cnt > 0) {
1729 items.push_back (SeparatorElem());
1730 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1733 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1734 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1735 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1736 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1739 items.push_back (SeparatorElem());
1740 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1742 items.push_back (SeparatorElem());
1743 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1744 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1745 denormal_menu_item->set_active (_route->denormal_protection());
1748 /* note that this relies on selection being shared across editor and
1749 mixer (or global to the backend, in the future), which is the only
1750 sane thing for users anyway.
1753 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1755 Selection& selection (PublicEditor::instance().get_selection());
1756 if (!selection.selected (rtav)) {
1757 selection.set (rtav);
1760 if (!_route->is_master()) {
1761 items.push_back (SeparatorElem());
1762 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1765 items.push_back (SeparatorElem());
1766 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1772 MixerStrip::name_button_button_press (GdkEventButton* ev)
1774 if (ev->button == 1 || ev->button == 3) {
1775 list_route_operations ();
1777 if (ev->button == 1) {
1778 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1781 route_ops_menu->popup (3, ev->time);
1791 MixerStrip::number_button_button_press (GdkEventButton* ev)
1793 if ( ev->button == 3 ) {
1794 list_route_operations ();
1796 route_ops_menu->popup (1, ev->time);
1805 MixerStrip::list_route_operations ()
1807 delete route_ops_menu;
1808 build_route_ops_menu ();
1812 MixerStrip::set_selected (bool yn)
1814 AxisView::set_selected (yn);
1817 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1818 global_frame.set_name ("MixerStripSelectedFrame");
1820 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1821 global_frame.set_name ("MixerStripFrame");
1824 global_frame.queue_draw ();
1827 // processor_box.deselect_all_processors();
1831 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1833 if (what_changed.contains (ARDOUR::Properties::name)) {
1839 MixerStrip::name_changed ()
1843 name_button.set_text (_route->name());
1846 name_button.set_text (PBD::short_version (_route->name(), 5));
1850 set_tooltip (name_button, _route->name());
1852 if (_session->config.get_track_name_number()) {
1853 const int64_t track_number = _route->track_number ();
1854 if (track_number == 0) {
1855 number_label.set_text ("-");
1857 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1860 number_label.set_text ("");
1865 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1867 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1871 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1873 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1877 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1879 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1883 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1885 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1889 MixerStrip::width_button_pressed (GdkEventButton* ev)
1891 if (ev->button != 1) {
1895 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1898 _mixer.set_strip_width (Narrow, true);
1902 _mixer.set_strip_width (Wide, true);
1908 set_width_enum (Narrow, this);
1911 set_width_enum (Wide, this);
1920 MixerStrip::hide_clicked ()
1922 // LAME fix to reset the button status for when it is redisplayed (part 1)
1923 hide_button.set_sensitive(false);
1926 Hiding(); /* EMIT_SIGNAL */
1928 _mixer.hide_strip (this);
1932 hide_button.set_sensitive(true);
1936 MixerStrip::set_embedded (bool yn)
1942 MixerStrip::map_frozen ()
1944 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1946 boost::shared_ptr<AudioTrack> at = audio_track();
1949 switch (at->freeze_state()) {
1950 case AudioTrack::Frozen:
1951 processor_box.set_sensitive (false);
1952 hide_redirect_editors ();
1955 processor_box.set_sensitive (true);
1956 // XXX need some way, maybe, to retoggle redirect editors
1960 processor_box.set_sensitive (true);
1962 RouteUI::map_frozen ();
1966 MixerStrip::hide_redirect_editors ()
1968 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1972 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1974 boost::shared_ptr<Processor> processor (p.lock ());
1979 Gtk::Window* w = processor_box.get_processor_ui (processor);
1987 MixerStrip::reset_strip_style ()
1989 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1991 gpm.set_fader_name ("SendStripBase");
1995 if (is_midi_track()) {
1996 if (_route->active()) {
1997 set_name ("MidiTrackStripBase");
1999 set_name ("MidiTrackStripBaseInactive");
2001 gpm.set_fader_name ("MidiTrackFader");
2002 } else if (is_audio_track()) {
2003 if (_route->active()) {
2004 set_name ("AudioTrackStripBase");
2006 set_name ("AudioTrackStripBaseInactive");
2008 gpm.set_fader_name ("AudioTrackFader");
2010 if (_route->active()) {
2011 set_name ("AudioBusStripBase");
2013 set_name ("AudioBusStripBaseInactive");
2015 gpm.set_fader_name ("AudioBusFader");
2017 /* (no MIDI busses yet) */
2024 MixerStrip::engine_stopped ()
2029 MixerStrip::engine_running ()
2034 MixerStrip::meter_point_string (MeterPoint mp)
2047 case MeterPostFader:
2064 return S_("Meter|In");
2068 return S_("Meter|Pr");
2071 case MeterPostFader:
2072 return S_("Meter|Po");
2076 return S_("Meter|O");
2081 return S_("Meter|C");
2090 /** Called when the monitor-section state */
2092 MixerStrip::monitor_changed ()
2094 assert (monitor_section_button);
2095 if (_session->monitor_active()) {
2096 monitor_section_button->set_name ("master monitor section button active");
2098 monitor_section_button->set_name ("master monitor section button normal");
2102 /** Called when the metering point has changed */
2104 MixerStrip::meter_changed ()
2106 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2107 gpm.setup_meters ();
2108 // reset peak when meter point changes
2109 gpm.reset_peak_display();
2112 /** The bus that we are displaying sends to has changed, or been turned off.
2113 * @param send_to New bus that we are displaying sends to, or 0.
2116 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2118 RouteUI::bus_send_display_changed (send_to);
2121 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2126 revert_to_default_display ();
2129 revert_to_default_display ();
2134 MixerStrip::drop_send ()
2136 boost::shared_ptr<Send> current_send;
2138 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2139 current_send->set_metering (false);
2142 send_gone_connection.disconnect ();
2143 input_button.set_sensitive (true);
2144 output_button.set_sensitive (true);
2145 group_button.set_sensitive (true);
2146 set_invert_sensitive (true);
2147 gpm.meter_point_button.set_sensitive (true);
2148 mute_button->set_sensitive (true);
2149 solo_button->set_sensitive (true);
2150 solo_isolated_led->set_sensitive (true);
2151 solo_safe_led->set_sensitive (true);
2152 monitor_input_button->set_sensitive (true);
2153 monitor_disk_button->set_sensitive (true);
2154 _comment_button.set_sensitive (true);
2155 RouteUI::check_rec_enable_sensitivity ();
2156 set_button_names (); // update solo button visual state
2160 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2162 _current_delivery = d;
2163 DeliveryChanged (_current_delivery);
2167 MixerStrip::show_send (boost::shared_ptr<Send> send)
2173 set_current_delivery (send);
2175 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2176 send->set_metering (true);
2177 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2179 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2180 gain_meter().setup_meters ();
2182 uint32_t const in = _current_delivery->pans_required();
2183 uint32_t const out = _current_delivery->pan_outs();
2185 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2186 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2187 panner_ui().setup_pan ();
2188 panner_ui().set_send_drawing_mode (true);
2189 panner_ui().show_all ();
2191 input_button.set_sensitive (false);
2192 group_button.set_sensitive (false);
2193 set_invert_sensitive (false);
2194 gpm.meter_point_button.set_sensitive (false);
2195 mute_button->set_sensitive (false);
2196 solo_button->set_sensitive (false);
2197 rec_enable_button->set_sensitive (false);
2198 solo_isolated_led->set_sensitive (false);
2199 solo_safe_led->set_sensitive (false);
2200 monitor_input_button->set_sensitive (false);
2201 monitor_disk_button->set_sensitive (false);
2202 _comment_button.set_sensitive (false);
2204 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2205 output_button.set_sensitive (false);
2208 reset_strip_style ();
2212 MixerStrip::revert_to_default_display ()
2216 set_current_delivery (_route->main_outs ());
2218 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2219 gain_meter().setup_meters ();
2221 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2222 update_panner_choices();
2223 panner_ui().setup_pan ();
2224 panner_ui().set_send_drawing_mode (false);
2226 if (has_audio_outputs ()) {
2227 panners.show_all ();
2229 panners.hide_all ();
2232 reset_strip_style ();
2236 MixerStrip::set_button_names ()
2240 mute_button->set_text (_("Mute"));
2241 monitor_input_button->set_text (_("In"));
2242 monitor_disk_button->set_text (_("Disk"));
2243 if (monitor_section_button) {
2244 monitor_section_button->set_text (_("Mon"));
2247 if (_route && _route->solo_safe_control()->solo_safe()) {
2248 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2250 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2252 if (!Config->get_solo_control_is_listen_control()) {
2253 solo_button->set_text (_("Solo"));
2255 switch (Config->get_listen_position()) {
2256 case AfterFaderListen:
2257 solo_button->set_text (_("AFL"));
2259 case PreFaderListen:
2260 solo_button->set_text (_("PFL"));
2264 solo_isolated_led->set_text (_("Iso"));
2265 solo_safe_led->set_text (S_("SoloLock|Lock"));
2269 mute_button->set_text (S_("Mute|M"));
2270 monitor_input_button->set_text (S_("MonitorInput|I"));
2271 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2272 if (monitor_section_button) {
2273 monitor_section_button->set_text (S_("Mon|O"));
2276 if (_route && _route->solo_safe_control()->solo_safe()) {
2277 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2279 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2281 if (!Config->get_solo_control_is_listen_control()) {
2282 solo_button->set_text (S_("Solo|S"));
2284 switch (Config->get_listen_position()) {
2285 case AfterFaderListen:
2286 solo_button->set_text (S_("AfterFader|A"));
2288 case PreFaderListen:
2289 solo_button->set_text (S_("Prefader|P"));
2294 solo_isolated_led->set_text (S_("SoloIso|I"));
2295 solo_safe_led->set_text (S_("SoloLock|L"));
2300 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2302 gpm.meter_point_button.set_text ("");
2307 MixerStrip::plugin_selector()
2309 return _mixer.plugin_selector();
2313 MixerStrip::hide_things ()
2315 processor_box.hide_things ();
2319 MixerStrip::input_active_button_press (GdkEventButton*)
2321 /* nothing happens on press */
2326 MixerStrip::input_active_button_release (GdkEventButton* ev)
2328 boost::shared_ptr<MidiTrack> mt = midi_track ();
2334 boost::shared_ptr<RouteList> rl (new RouteList);
2336 rl->push_back (route());
2338 _session->set_exclusive_input_active (rl, !mt->input_active(),
2339 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2345 MixerStrip::midi_input_status_changed ()
2347 if (midi_input_enable_button) {
2348 boost::shared_ptr<MidiTrack> mt = midi_track ();
2350 midi_input_enable_button->set_active (mt->input_active ());
2355 MixerStrip::state_id () const
2357 return string_compose ("strip %1", _route->id().to_s());
2361 MixerStrip::parameter_changed (string p)
2363 if (p == _visibility.get_state_name()) {
2364 /* The user has made changes to the mixer strip visibility, so get
2365 our VisibilityGroup to reflect these changes in our widgets.
2367 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2368 } else if (p == "track-name-number") {
2370 } else if (p == "use-monitor-bus") {
2371 if (monitor_section_button) {
2372 if (mute_button->get_parent()) {
2373 mute_button->get_parent()->remove(*mute_button);
2375 if (monitor_section_button->get_parent()) {
2376 monitor_section_button->get_parent()->remove(*monitor_section_button);
2378 if (Config->get_use_monitor_bus ()) {
2379 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2380 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2381 mute_button->show();
2382 monitor_section_button->show();
2384 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2385 mute_button->show();
2388 } else if (p == "track-name-number") {
2389 update_track_number_visibility();
2393 /** Called to decide whether the solo isolate / solo lock button visibility should
2394 * be overridden from that configured by the user. We do this for the master bus.
2396 * @return optional value that is present if visibility state should be overridden.
2398 boost::optional<bool>
2399 MixerStrip::override_solo_visibility () const
2401 if (_route && _route->is_master ()) {
2402 return boost::optional<bool> (false);
2405 return boost::optional<bool> ();
2409 MixerStrip::add_input_port (DataType t)
2411 _route->input()->add_port ("", this, t);
2415 MixerStrip::add_output_port (DataType t)
2417 _route->output()->add_port ("", this, t);
2421 MixerStrip::route_active_changed ()
2423 reset_strip_style ();
2427 MixerStrip::copy_processors ()
2429 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2433 MixerStrip::cut_processors ()
2435 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2439 MixerStrip::paste_processors ()
2441 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2445 MixerStrip::select_all_processors ()
2447 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2451 MixerStrip::deselect_all_processors ()
2453 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2457 MixerStrip::delete_processors ()
2459 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2463 MixerStrip::toggle_processors ()
2465 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2469 MixerStrip::ab_plugins ()
2471 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2475 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2477 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2480 if (ev->button == 3) {
2481 popup_level_meter_menu (ev);
2489 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2491 using namespace Gtk::Menu_Helpers;
2493 Gtk::Menu* m = manage (new Menu);
2494 MenuList& items = m->items ();
2496 RadioMenuItem::Group group;
2498 _suspend_menu_callbacks = true;
2499 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2500 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2501 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2502 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2503 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2505 if (gpm.meter_channels().n_audio() == 0) {
2506 m->popup (ev->button, ev->time);
2507 _suspend_menu_callbacks = false;
2511 RadioMenuItem::Group tgroup;
2512 items.push_back (SeparatorElem());
2514 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2515 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2516 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2517 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2518 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2519 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2520 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2521 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2522 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2523 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2524 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2527 if (_route->is_master()) {
2530 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2531 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2532 /* non-master bus */
2535 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2542 MeterType cmt = _route->meter_type();
2543 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2545 items.push_back (SeparatorElem());
2546 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2547 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2548 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2549 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2550 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2551 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2553 m->popup (ev->button, ev->time);
2554 _suspend_menu_callbacks = false;
2558 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2559 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2561 using namespace Menu_Helpers;
2563 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2564 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2565 i->set_active (_route->meter_point() == point);
2569 MixerStrip::set_meter_point (MeterPoint p)
2571 if (_suspend_menu_callbacks) return;
2572 _route->set_meter_point (p);
2576 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2577 RadioMenuItem::Group& group, string const & name, MeterType type)
2579 using namespace Menu_Helpers;
2581 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2582 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2583 i->set_active (_route->meter_type() == type);
2587 MixerStrip::set_meter_type (MeterType t)
2589 if (_suspend_menu_callbacks) return;
2594 MixerStrip::update_track_number_visibility ()
2596 DisplaySuspender ds;
2597 bool show_label = _session->config.get_track_name_number();
2599 if (_route && _route->is_master()) {
2604 number_label.show ();
2605 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2606 // except the width of the number label is subtracted from the name-hbox, so we
2607 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2608 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2610 number_label.set_size_request(tnw, -1);
2611 number_label.show ();
2613 number_label.hide ();
2618 MixerStrip::color () const
2620 return route_color ();
2624 MixerStrip::marked_for_display () const
2626 return !_route->presentation_info().hidden();
2630 MixerStrip::set_marked_for_display (bool yn)
2632 return RouteUI::mark_hidden (!yn);