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 items.push_back (SeparatorElem());
1692 if (!_route->is_master()) {
1693 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1695 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1696 rename_menu_item = &items.back();
1698 items.push_back (SeparatorElem());
1699 items.push_back (CheckMenuElem (_("Active")));
1700 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1701 i->set_active (_route->active());
1702 i->set_sensitive(! _session->transport_rolling());
1703 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1705 if (!Profile->get_mixbus ()) {
1706 items.push_back (SeparatorElem());
1707 items.push_back (CheckMenuElem (_("Strict I/O")));
1708 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1709 i->set_active (_route->strict_io());
1710 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1713 _plugin_insert_cnt = 0;
1714 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1715 if (_plugin_insert_cnt > 0) {
1716 items.push_back (SeparatorElem());
1717 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1720 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1721 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1722 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1723 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1726 items.push_back (SeparatorElem());
1727 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1729 items.push_back (SeparatorElem());
1730 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1731 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1732 denormal_menu_item->set_active (_route->denormal_protection());
1735 /* note that this relies on selection being shared across editor and
1736 mixer (or global to the backend, in the future), which is the only
1737 sane thing for users anyway.
1740 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1742 Selection& selection (PublicEditor::instance().get_selection());
1743 if (!selection.selected (rtav)) {
1744 selection.set (rtav);
1747 if (!_route->is_master()) {
1748 items.push_back (SeparatorElem());
1749 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1752 items.push_back (SeparatorElem());
1753 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1759 MixerStrip::name_button_button_press (GdkEventButton* ev)
1761 if (ev->button == 1 || ev->button == 3) {
1762 list_route_operations ();
1764 /* do not allow rename if the track is record-enabled */
1765 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1766 if (ev->button == 1) {
1767 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1770 route_ops_menu->popup (3, ev->time);
1780 MixerStrip::number_button_button_press (GdkEventButton* ev)
1782 if ( ev->button == 3 ) {
1783 list_route_operations ();
1785 /* do not allow rename if the track is record-enabled */
1786 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1787 route_ops_menu->popup (1, ev->time);
1796 MixerStrip::list_route_operations ()
1798 delete route_ops_menu;
1799 build_route_ops_menu ();
1803 MixerStrip::set_selected (bool yn)
1805 AxisView::set_selected (yn);
1808 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1809 global_frame.set_name ("MixerStripSelectedFrame");
1811 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1812 global_frame.set_name ("MixerStripFrame");
1815 global_frame.queue_draw ();
1818 // processor_box.deselect_all_processors();
1822 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1824 if (what_changed.contains (ARDOUR::Properties::name)) {
1830 MixerStrip::name_changed ()
1834 name_button.set_text (_route->name());
1837 name_button.set_text (PBD::short_version (_route->name(), 5));
1841 set_tooltip (name_button, _route->name());
1843 if (_session->config.get_track_name_number()) {
1844 const int64_t track_number = _route->track_number ();
1845 if (track_number == 0) {
1846 number_label.set_text ("-");
1848 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1851 number_label.set_text ("");
1856 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1858 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1862 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1864 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1868 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1870 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1874 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1876 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1880 MixerStrip::width_button_pressed (GdkEventButton* ev)
1882 if (ev->button != 1) {
1886 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1889 _mixer.set_strip_width (Narrow, true);
1893 _mixer.set_strip_width (Wide, true);
1899 set_width_enum (Narrow, this);
1902 set_width_enum (Wide, this);
1911 MixerStrip::hide_clicked ()
1913 // LAME fix to reset the button status for when it is redisplayed (part 1)
1914 hide_button.set_sensitive(false);
1917 Hiding(); /* EMIT_SIGNAL */
1919 _mixer.hide_strip (this);
1923 hide_button.set_sensitive(true);
1927 MixerStrip::set_embedded (bool yn)
1933 MixerStrip::map_frozen ()
1935 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1937 boost::shared_ptr<AudioTrack> at = audio_track();
1940 switch (at->freeze_state()) {
1941 case AudioTrack::Frozen:
1942 processor_box.set_sensitive (false);
1943 hide_redirect_editors ();
1946 processor_box.set_sensitive (true);
1947 // XXX need some way, maybe, to retoggle redirect editors
1951 processor_box.set_sensitive (true);
1953 RouteUI::map_frozen ();
1957 MixerStrip::hide_redirect_editors ()
1959 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1963 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1965 boost::shared_ptr<Processor> processor (p.lock ());
1970 Gtk::Window* w = processor_box.get_processor_ui (processor);
1978 MixerStrip::reset_strip_style ()
1980 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1982 gpm.set_fader_name ("SendStripBase");
1986 if (is_midi_track()) {
1987 if (_route->active()) {
1988 set_name ("MidiTrackStripBase");
1990 set_name ("MidiTrackStripBaseInactive");
1992 gpm.set_fader_name ("MidiTrackFader");
1993 } else if (is_audio_track()) {
1994 if (_route->active()) {
1995 set_name ("AudioTrackStripBase");
1997 set_name ("AudioTrackStripBaseInactive");
1999 gpm.set_fader_name ("AudioTrackFader");
2001 if (_route->active()) {
2002 set_name ("AudioBusStripBase");
2004 set_name ("AudioBusStripBaseInactive");
2006 gpm.set_fader_name ("AudioBusFader");
2008 /* (no MIDI busses yet) */
2015 MixerStrip::engine_stopped ()
2020 MixerStrip::engine_running ()
2025 MixerStrip::meter_point_string (MeterPoint mp)
2038 case MeterPostFader:
2055 return S_("Meter|In");
2059 return S_("Meter|Pr");
2062 case MeterPostFader:
2063 return S_("Meter|Po");
2067 return S_("Meter|O");
2072 return S_("Meter|C");
2081 /** Called when the monitor-section state */
2083 MixerStrip::monitor_changed ()
2085 assert (monitor_section_button);
2086 if (_session->monitor_active()) {
2087 monitor_section_button->set_name ("master monitor section button active");
2089 monitor_section_button->set_name ("master monitor section button normal");
2093 /** Called when the metering point has changed */
2095 MixerStrip::meter_changed ()
2097 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2098 gpm.setup_meters ();
2099 // reset peak when meter point changes
2100 gpm.reset_peak_display();
2103 /** The bus that we are displaying sends to has changed, or been turned off.
2104 * @param send_to New bus that we are displaying sends to, or 0.
2107 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2109 RouteUI::bus_send_display_changed (send_to);
2112 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2117 revert_to_default_display ();
2120 revert_to_default_display ();
2125 MixerStrip::drop_send ()
2127 boost::shared_ptr<Send> current_send;
2129 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2130 current_send->set_metering (false);
2133 send_gone_connection.disconnect ();
2134 input_button.set_sensitive (true);
2135 output_button.set_sensitive (true);
2136 group_button.set_sensitive (true);
2137 set_invert_sensitive (true);
2138 gpm.meter_point_button.set_sensitive (true);
2139 mute_button->set_sensitive (true);
2140 solo_button->set_sensitive (true);
2141 solo_isolated_led->set_sensitive (true);
2142 solo_safe_led->set_sensitive (true);
2143 monitor_input_button->set_sensitive (true);
2144 monitor_disk_button->set_sensitive (true);
2145 _comment_button.set_sensitive (true);
2146 RouteUI::check_rec_enable_sensitivity ();
2147 set_button_names (); // update solo button visual state
2151 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2153 _current_delivery = d;
2154 DeliveryChanged (_current_delivery);
2158 MixerStrip::show_send (boost::shared_ptr<Send> send)
2164 set_current_delivery (send);
2166 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2167 send->set_metering (true);
2168 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2170 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2171 gain_meter().setup_meters ();
2173 uint32_t const in = _current_delivery->pans_required();
2174 uint32_t const out = _current_delivery->pan_outs();
2176 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2177 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2178 panner_ui().setup_pan ();
2179 panner_ui().set_send_drawing_mode (true);
2180 panner_ui().show_all ();
2182 input_button.set_sensitive (false);
2183 group_button.set_sensitive (false);
2184 set_invert_sensitive (false);
2185 gpm.meter_point_button.set_sensitive (false);
2186 mute_button->set_sensitive (false);
2187 solo_button->set_sensitive (false);
2188 rec_enable_button->set_sensitive (false);
2189 solo_isolated_led->set_sensitive (false);
2190 solo_safe_led->set_sensitive (false);
2191 monitor_input_button->set_sensitive (false);
2192 monitor_disk_button->set_sensitive (false);
2193 _comment_button.set_sensitive (false);
2195 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2196 output_button.set_sensitive (false);
2199 reset_strip_style ();
2203 MixerStrip::revert_to_default_display ()
2207 set_current_delivery (_route->main_outs ());
2209 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2210 gain_meter().setup_meters ();
2212 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2213 update_panner_choices();
2214 panner_ui().setup_pan ();
2215 panner_ui().set_send_drawing_mode (false);
2217 if (has_audio_outputs ()) {
2218 panners.show_all ();
2220 panners.hide_all ();
2223 reset_strip_style ();
2227 MixerStrip::set_button_names ()
2231 mute_button->set_text (_("Mute"));
2232 monitor_input_button->set_text (_("In"));
2233 monitor_disk_button->set_text (_("Disk"));
2234 if (monitor_section_button) {
2235 monitor_section_button->set_text (_("Mon"));
2238 if (_route && _route->solo_safe_control()->solo_safe()) {
2239 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2241 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2243 if (!Config->get_solo_control_is_listen_control()) {
2244 solo_button->set_text (_("Solo"));
2246 switch (Config->get_listen_position()) {
2247 case AfterFaderListen:
2248 solo_button->set_text (_("AFL"));
2250 case PreFaderListen:
2251 solo_button->set_text (_("PFL"));
2255 solo_isolated_led->set_text (_("Iso"));
2256 solo_safe_led->set_text (S_("SoloLock|Lock"));
2260 mute_button->set_text (S_("Mute|M"));
2261 monitor_input_button->set_text (S_("MonitorInput|I"));
2262 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2263 if (monitor_section_button) {
2264 monitor_section_button->set_text (S_("Mon|O"));
2267 if (_route && _route->solo_safe_control()->solo_safe()) {
2268 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2270 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2272 if (!Config->get_solo_control_is_listen_control()) {
2273 solo_button->set_text (S_("Solo|S"));
2275 switch (Config->get_listen_position()) {
2276 case AfterFaderListen:
2277 solo_button->set_text (S_("AfterFader|A"));
2279 case PreFaderListen:
2280 solo_button->set_text (S_("Prefader|P"));
2285 solo_isolated_led->set_text (S_("SoloIso|I"));
2286 solo_safe_led->set_text (S_("SoloLock|L"));
2291 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2293 gpm.meter_point_button.set_text ("");
2298 MixerStrip::plugin_selector()
2300 return _mixer.plugin_selector();
2304 MixerStrip::hide_things ()
2306 processor_box.hide_things ();
2310 MixerStrip::input_active_button_press (GdkEventButton*)
2312 /* nothing happens on press */
2317 MixerStrip::input_active_button_release (GdkEventButton* ev)
2319 boost::shared_ptr<MidiTrack> mt = midi_track ();
2325 boost::shared_ptr<RouteList> rl (new RouteList);
2327 rl->push_back (route());
2329 _session->set_exclusive_input_active (rl, !mt->input_active(),
2330 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2336 MixerStrip::midi_input_status_changed ()
2338 if (midi_input_enable_button) {
2339 boost::shared_ptr<MidiTrack> mt = midi_track ();
2341 midi_input_enable_button->set_active (mt->input_active ());
2346 MixerStrip::state_id () const
2348 return string_compose ("strip %1", _route->id().to_s());
2352 MixerStrip::parameter_changed (string p)
2354 if (p == _visibility.get_state_name()) {
2355 /* The user has made changes to the mixer strip visibility, so get
2356 our VisibilityGroup to reflect these changes in our widgets.
2358 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2359 } else if (p == "track-name-number") {
2361 } else if (p == "use-monitor-bus") {
2362 if (monitor_section_button) {
2363 if (mute_button->get_parent()) {
2364 mute_button->get_parent()->remove(*mute_button);
2366 if (monitor_section_button->get_parent()) {
2367 monitor_section_button->get_parent()->remove(*monitor_section_button);
2369 if (Config->get_use_monitor_bus ()) {
2370 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2371 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2372 mute_button->show();
2373 monitor_section_button->show();
2375 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2376 mute_button->show();
2379 } else if (p == "track-name-number") {
2380 update_track_number_visibility();
2384 /** Called to decide whether the solo isolate / solo lock button visibility should
2385 * be overridden from that configured by the user. We do this for the master bus.
2387 * @return optional value that is present if visibility state should be overridden.
2389 boost::optional<bool>
2390 MixerStrip::override_solo_visibility () const
2392 if (_route && _route->is_master ()) {
2393 return boost::optional<bool> (false);
2396 return boost::optional<bool> ();
2400 MixerStrip::add_input_port (DataType t)
2402 _route->input()->add_port ("", this, t);
2406 MixerStrip::add_output_port (DataType t)
2408 _route->output()->add_port ("", this, t);
2412 MixerStrip::route_active_changed ()
2414 reset_strip_style ();
2418 MixerStrip::copy_processors ()
2420 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2424 MixerStrip::cut_processors ()
2426 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2430 MixerStrip::paste_processors ()
2432 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2436 MixerStrip::select_all_processors ()
2438 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2442 MixerStrip::deselect_all_processors ()
2444 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2448 MixerStrip::delete_processors ()
2450 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2454 MixerStrip::toggle_processors ()
2456 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2460 MixerStrip::ab_plugins ()
2462 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2466 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2468 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2471 if (ev->button == 3) {
2472 popup_level_meter_menu (ev);
2480 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2482 using namespace Gtk::Menu_Helpers;
2484 Gtk::Menu* m = manage (new Menu);
2485 MenuList& items = m->items ();
2487 RadioMenuItem::Group group;
2489 _suspend_menu_callbacks = true;
2490 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2491 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2492 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2493 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2494 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2496 if (gpm.meter_channels().n_audio() == 0) {
2497 m->popup (ev->button, ev->time);
2498 _suspend_menu_callbacks = false;
2502 RadioMenuItem::Group tgroup;
2503 items.push_back (SeparatorElem());
2505 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2506 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2507 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2508 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2509 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2510 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2511 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2512 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2513 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2514 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2515 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2518 if (_route->is_master()) {
2521 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2522 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2523 /* non-master bus */
2526 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2533 MeterType cmt = _route->meter_type();
2534 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2536 items.push_back (SeparatorElem());
2537 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2538 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2539 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2540 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2541 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2542 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2544 m->popup (ev->button, ev->time);
2545 _suspend_menu_callbacks = false;
2549 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2550 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2552 using namespace Menu_Helpers;
2554 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2555 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2556 i->set_active (_route->meter_point() == point);
2560 MixerStrip::set_meter_point (MeterPoint p)
2562 if (_suspend_menu_callbacks) return;
2563 _route->set_meter_point (p);
2567 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2568 RadioMenuItem::Group& group, string const & name, MeterType type)
2570 using namespace Menu_Helpers;
2572 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2573 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2574 i->set_active (_route->meter_type() == type);
2578 MixerStrip::set_meter_type (MeterType t)
2580 if (_suspend_menu_callbacks) return;
2585 MixerStrip::update_track_number_visibility ()
2587 DisplaySuspender ds;
2588 bool show_label = _session->config.get_track_name_number();
2590 if (_route && _route->is_master()) {
2595 number_label.show ();
2596 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2597 // except the width of the number label is subtracted from the name-hbox, so we
2598 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2599 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2601 number_label.set_size_request(tnw, -1);
2602 number_label.show ();
2604 number_label.hide ();
2609 MixerStrip::color () const
2611 return route_color ();
2615 MixerStrip::marked_for_display () const
2617 return !_route->presentation_info().hidden();
2621 MixerStrip::set_marked_for_display (bool yn)
2623 return RouteUI::mark_hidden (!yn);