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 "enums_convert.h"
61 #include "mixer_strip.h"
64 #include "ardour_button.h"
65 #include "public_editor.h"
67 #include "io_selector.h"
69 #include "gui_thread.h"
70 #include "route_group_menu.h"
71 #include "meter_patterns.h"
73 #include "ui_config.h"
77 using namespace ARDOUR;
78 using namespace ARDOUR_UI_UTILS;
81 using namespace Gtkmm2ext;
83 using namespace ArdourMeter;
85 MixerStrip* MixerStrip::_entered_mixer_strip;
86 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
88 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
89 : SessionHandlePtr (sess)
92 , _mixer_owned (in_mixer)
93 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
96 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
97 , rec_mon_table (2, 2)
98 , solo_iso_table (1, 2)
99 , mute_solo_table (1, 2)
100 , bottom_button_table (1, 3)
101 , monitor_section_button (0)
102 , midi_input_enable_button (0)
103 , _plugin_insert_cnt (0)
104 , _comment_button (_("Comments"))
105 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
106 , _visibility (X_("mixer-element-visibility"))
107 , control_slave_ui (sess)
112 /* the editor mixer strip: don't destroy it every time
113 the underlying route goes away.
116 self_destruct = false;
120 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
121 : SessionHandlePtr (sess)
124 , _mixer_owned (in_mixer)
125 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
128 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
129 , rec_mon_table (2, 2)
130 , solo_iso_table (1, 2)
131 , mute_solo_table (1, 2)
132 , bottom_button_table (1, 3)
133 , monitor_section_button (0)
134 , midi_input_enable_button (0)
135 , _plugin_insert_cnt (0)
136 , _comment_button (_("Comments"))
137 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
138 , _visibility (X_("mixer-element-visibility"))
139 , control_slave_ui (sess)
148 _entered_mixer_strip= 0;
151 ignore_comment_edit = false;
152 ignore_toggle = false;
156 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
157 longest_label = "longest label";
159 string t = _("Click to toggle the width of this mixer strip.");
161 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
164 width_button.set_icon (ArdourIcon::StripWidth);
165 hide_button.set_tweaks (ArdourButton::Square);
166 set_tooltip (width_button, t);
168 hide_button.set_icon (ArdourIcon::CloseCross);
169 hide_button.set_tweaks (ArdourButton::Square);
170 set_tooltip (&hide_button, _("Hide this mixer strip"));
172 input_button_box.set_spacing(2);
174 input_button.set_text (_("Input"));
175 input_button.set_name ("mixer strip button");
176 input_button_box.pack_start (input_button, true, true);
178 output_button.set_text (_("Output"));
179 output_button.set_name ("mixer strip button");
181 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
183 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
185 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
186 solo_isolated_led->show ();
187 solo_isolated_led->set_no_show_all (true);
188 solo_isolated_led->set_name (X_("solo isolate"));
189 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
190 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
191 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
193 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
194 solo_safe_led->show ();
195 solo_safe_led->set_no_show_all (true);
196 solo_safe_led->set_name (X_("solo safe"));
197 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
198 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
199 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
201 solo_safe_led->set_text (S_("SoloLock|Lock"));
202 solo_isolated_led->set_text (_("Iso"));
204 solo_iso_table.set_homogeneous (true);
205 solo_iso_table.set_spacings (2);
206 if (!ARDOUR::Profile->get_trx()) {
207 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
208 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
210 solo_iso_table.show ();
212 rec_mon_table.set_homogeneous (true);
213 rec_mon_table.set_row_spacings (2);
214 rec_mon_table.set_col_spacings (2);
215 if (ARDOUR::Profile->get_mixbus()) {
216 rec_mon_table.resize (1, 3);
217 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
218 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
219 } else if (!ARDOUR::Profile->get_trx()) {
220 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
221 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
223 rec_mon_table.show ();
225 if (solo_isolated_led) {
226 button_size_group->add_widget (*solo_isolated_led);
229 button_size_group->add_widget (*solo_safe_led);
232 if (!ARDOUR::Profile->get_mixbus()) {
233 if (rec_enable_button) {
234 button_size_group->add_widget (*rec_enable_button);
236 if (monitor_disk_button) {
237 button_size_group->add_widget (*monitor_disk_button);
239 if (monitor_input_button) {
240 button_size_group->add_widget (*monitor_input_button);
244 mute_solo_table.set_homogeneous (true);
245 mute_solo_table.set_spacings (2);
247 bottom_button_table.set_spacings (2);
248 bottom_button_table.set_homogeneous (true);
249 bottom_button_table.attach (group_button, 1, 2, 0, 1);
250 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
252 name_button.set_name ("mixer strip button");
253 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
254 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
256 set_tooltip (&group_button, _("Mix group"));
257 group_button.set_name ("mixer strip button");
259 _comment_button.set_name (X_("mixer strip button"));
260 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
262 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
264 // TODO implement ArdourKnob::on_size_request properly
265 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
266 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
268 trim_control.set_tooltip_prefix (_("Trim: "));
269 trim_control.set_name ("trim knob");
270 trim_control.set_no_show_all (true);
271 input_button_box.pack_start (trim_control, false, false);
273 global_vpacker.set_border_width (1);
274 global_vpacker.set_spacing (0);
276 width_button.set_name ("mixer strip button");
277 hide_button.set_name ("mixer strip button");
279 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
280 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
282 width_hide_box.set_spacing (2);
283 width_hide_box.pack_start (width_button, false, true);
284 width_hide_box.pack_start (number_label, true, true);
285 width_hide_box.pack_end (hide_button, false, true);
287 number_label.set_text ("-");
288 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
289 number_label.set_no_show_all ();
290 number_label.set_name ("tracknumber label");
291 number_label.set_fixed_colors (0x80808080, 0x80808080);
292 number_label.set_alignment (.5, .5);
293 number_label.set_fallthrough_to_parent (true);
294 number_label.set_tweaks (ArdourButton::OccasionalText);
296 global_vpacker.set_spacing (2);
297 if (!ARDOUR::Profile->get_trx()) {
298 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
299 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
300 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
301 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
302 global_vpacker.pack_start (processor_box, true, true);
304 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
311 if (!ARDOUR::Profile->get_trx()) {
312 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
319 //add a spacer underneath the master bus;
320 //this fills the area that is taken up by the scrollbar on the tracks;
321 //and therefore keeps the faders "even" across the bottom
322 int scrollbar_height = 0;
324 Gtk::Window window (WINDOW_TOPLEVEL);
325 HScrollbar scrollbar;
326 window.add (scrollbar);
327 scrollbar.set_name ("MixerWindow");
328 scrollbar.ensure_style();
329 Gtk::Requisition requisition(scrollbar.size_request ());
330 scrollbar_height = requisition.height;
332 spacer.set_size_request (-1, scrollbar_height);
333 global_vpacker.pack_end (spacer, false, false);
336 global_frame.add (global_vpacker);
337 global_frame.set_shadow_type (Gtk::SHADOW_IN);
338 global_frame.set_name ("BaseFrame");
342 /* force setting of visible selected status */
345 set_selected (false);
350 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
351 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
353 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
354 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
355 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
357 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
358 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
360 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
361 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
362 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
364 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
366 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
368 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
372 /* start off as a passthru strip. we'll correct this, if necessary,
373 in update_diskstream_display().
376 /* start off as a passthru strip. we'll correct this, if necessary,
377 in update_diskstream_display().
380 if (is_midi_track()) {
381 set_name ("MidiTrackStripBase");
383 set_name ("AudioTrackStripBase");
386 add_events (Gdk::BUTTON_RELEASE_MASK|
387 Gdk::ENTER_NOTIFY_MASK|
388 Gdk::LEAVE_NOTIFY_MASK|
390 Gdk::KEY_RELEASE_MASK);
392 set_flags (get_flags() | Gtk::CAN_FOCUS);
394 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
395 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
398 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
399 must be the same as those used in RCOptionEditor so that the configuration changes
400 are recognised when they occur.
402 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
403 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
404 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
405 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
406 _visibility.add (&output_button, X_("Output"), _("Output"), false);
407 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
408 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
410 parameter_changed (X_("mixer-element-visibility"));
411 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
412 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
413 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
415 //watch for mouse enter/exit so we can do some stuff
416 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
417 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
419 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
422 MixerStrip::~MixerStrip ()
424 CatchDeletion (this);
426 if (this ==_entered_mixer_strip)
427 _entered_mixer_strip = NULL;
431 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
433 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
435 sl->assign(vca, false);
439 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
441 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
447 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
449 _entered_mixer_strip = this;
451 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
452 //because the mixerstrip control is a parent that encompasses the strip
453 deselect_all_processors();
459 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
461 //if we have moved outside our strip, but not into a child view, then deselect ourselves
462 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
463 _entered_mixer_strip= 0;
465 //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
466 gpm.gain_display.set_sensitive(false);
468 gpm.gain_display.set_sensitive(true);
470 //if we leave this mixer strip we need to clear out any selections
471 //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
478 MixerStrip::name() const
481 return _route->name();
487 MixerStrip::update_trim_control ()
489 if (route()->trim() && route()->trim()->active() &&
490 route()->n_inputs().n_audio() > 0) {
491 trim_control.show ();
492 trim_control.set_controllable (route()->trim()->gain_control());
494 trim_control.hide ();
495 boost::shared_ptr<Controllable> none;
496 trim_control.set_controllable (none);
501 MixerStrip::set_route (boost::shared_ptr<Route> rt)
503 //the rec/monitor stuff only shows up for tracks.
504 //the show_sends only shows up for buses.
505 //remove them all here, and we may add them back later
506 if (show_sends_button->get_parent()) {
507 rec_mon_table.remove (*show_sends_button);
509 if (rec_enable_button->get_parent()) {
510 rec_mon_table.remove (*rec_enable_button);
512 if (monitor_input_button->get_parent()) {
513 rec_mon_table.remove (*monitor_input_button);
515 if (monitor_disk_button->get_parent()) {
516 rec_mon_table.remove (*monitor_disk_button);
518 if (group_button.get_parent()) {
519 bottom_button_table.remove (group_button);
522 RouteUI::set_route (rt);
524 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
526 /* ProcessorBox needs access to _route so that it can read
529 processor_box.set_route (rt);
531 revert_to_default_display ();
533 /* unpack these from the parent and stuff them into our own
537 if (gpm.peak_display.get_parent()) {
538 gpm.peak_display.get_parent()->remove (gpm.peak_display);
540 if (gpm.gain_display.get_parent()) {
541 gpm.gain_display.get_parent()->remove (gpm.gain_display);
544 gpm.set_type (rt->meter_type());
546 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
547 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
549 if (solo_button->get_parent()) {
550 mute_solo_table.remove (*solo_button);
553 if (mute_button->get_parent()) {
554 mute_solo_table.remove (*mute_button);
557 if (route()->is_master()) {
558 solo_button->hide ();
559 mute_button->show ();
560 rec_mon_table.hide ();
561 solo_iso_table.set_sensitive(false);
562 control_slave_ui.set_sensitive(false);
563 if (monitor_section_button == 0) {
564 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
565 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
567 monitor_section_button = manage (new ArdourButton);
569 monitor_section_button->set_related_action (act);
570 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
571 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
572 monitor_section_button->show();
573 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
575 parameter_changed ("use-monitor-bus");
577 bottom_button_table.attach (group_button, 1, 2, 0, 1);
578 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
579 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
580 mute_button->show ();
581 solo_button->show ();
582 rec_mon_table.show ();
583 solo_iso_table.set_sensitive(true);
584 control_slave_ui.set_sensitive(true);
587 if (_mixer_owned && route()->is_master() ) {
594 monitor_input_button->show ();
595 monitor_disk_button->show ();
597 monitor_input_button->hide();
598 monitor_disk_button->hide ();
601 update_trim_control();
603 if (is_midi_track()) {
604 if (midi_input_enable_button == 0) {
605 midi_input_enable_button = manage (new ArdourButton);
606 midi_input_enable_button->set_name ("midi input button");
607 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
608 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
609 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
610 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
611 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
613 input_button_box.remove (*midi_input_enable_button);
615 /* get current state */
616 midi_input_status_changed ();
617 input_button_box.pack_start (*midi_input_enable_button, false, false);
619 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
621 if (midi_input_enable_button) {
622 /* removal from the container will delete it */
623 input_button_box.remove (*midi_input_enable_button);
624 midi_input_enable_button = 0;
628 if (is_audio_track()) {
629 boost::shared_ptr<AudioTrack> at = audio_track();
630 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
635 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
636 rec_enable_button->show();
638 if (ARDOUR::Profile->get_mixbus()) {
639 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
640 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
641 } else if (ARDOUR::Profile->get_trx()) {
642 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
644 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
645 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
652 if (!_route->is_master()) {
653 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
654 show_sends_button->show();
658 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
660 delete route_ops_menu;
663 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
664 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
665 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
666 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
668 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
670 if (_route->panner_shell()) {
671 update_panner_choices();
672 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
675 if (is_audio_track()) {
676 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
679 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
681 set_stuff_from_route ();
683 /* now force an update of all the various elements */
685 update_mute_display ();
686 update_solo_display ();
689 route_group_changed ();
690 update_track_number_visibility ();
693 panners.setup_pan ();
695 if (has_audio_outputs ()) {
701 update_diskstream_display ();
702 update_input_display ();
703 update_output_display ();
705 add_events (Gdk::BUTTON_RELEASE_MASK);
707 processor_box.show ();
709 if (!route()->is_master() && !route()->is_monitor()) {
710 /* we don't allow master or control routes to be hidden */
715 gpm.reset_peak_display ();
716 gpm.gain_display.show ();
717 gpm.peak_display.show ();
720 width_hide_box.show();
722 global_vpacker.show();
723 mute_solo_table.show();
724 bottom_button_table.show();
726 gpm.meter_point_button.show();
727 input_button_box.show_all();
728 output_button.show();
730 _comment_button.show();
732 gpm.gain_automation_state_button.show();
734 parameter_changed ("mixer-element-visibility");
741 MixerStrip::set_stuff_from_route ()
743 /* if width is not set, it will be set by the MixerUI or editor */
746 if (get_gui_property ("strip-width", width)) {
747 set_width_enum (width, this);
752 MixerStrip::set_width_enum (Width w, void* owner)
754 /* always set the gpm width again, things may be hidden */
757 panners.set_width (w);
759 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
761 _width_owner = owner;
765 if (_width_owner == this) {
766 set_gui_property ("strip-width", _width);
771 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
776 if (show_sends_button) {
777 show_sends_button->set_text (_("Aux"));
780 gpm.gain_automation_style_button.set_text (
781 gpm.astyle_string(gain_automation->automation_style()));
782 gpm.gain_automation_state_button.set_text (
783 gpm.astate_string(gain_automation->automation_state()));
785 if (_route->panner()) {
786 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
787 panners.astyle_string(_route->panner()->automation_style()));
788 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
789 panners.astate_string(_route->panner()->automation_state()));
793 // panners expect an even number of horiz. pixels
794 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
796 set_size_request (width, -1);
802 if (show_sends_button) {
803 show_sends_button->set_text (_("Snd"));
806 gpm.gain_automation_style_button.set_text (
807 gpm.short_astyle_string(gain_automation->automation_style()));
808 gpm.gain_automation_state_button.set_text (
809 gpm.short_astate_string(gain_automation->automation_state()));
810 gain_meter().setup_meters (); // recalc meter width
812 if (_route->panner()) {
813 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
814 panners.short_astyle_string(_route->panner()->automation_style()));
815 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
816 panners.short_astate_string(_route->panner()->automation_state()));
820 // panners expect an even number of horiz. pixels
821 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
823 set_size_request (width, -1);
828 processor_box.set_width (w);
830 update_input_display ();
831 update_output_display ();
832 setup_comment_button ();
833 route_group_changed ();
839 MixerStrip::set_packed (bool yn)
842 set_gui_property ("visible", _packed);
846 struct RouteCompareByName {
847 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
848 return a->name().compare (b->name()) < 0;
853 MixerStrip::output_release (GdkEventButton *ev)
855 switch (ev->button) {
857 edit_output_configuration ();
865 MixerStrip::output_press (GdkEventButton *ev)
867 using namespace Menu_Helpers;
868 if (!_session->engine().connected()) {
869 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
874 MenuList& citems = output_menu.items();
875 switch (ev->button) {
878 return false; //wait for the mouse-up to pop the dialog
882 output_menu.set_name ("ArdourContextMenu");
884 output_menu_bundles.clear ();
886 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
888 citems.push_back (SeparatorElem());
889 uint32_t const n_with_separator = citems.size ();
891 ARDOUR::BundleList current = _route->output()->bundles_connected ();
893 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
895 /* give user bundles first chance at being in the menu */
897 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
898 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
899 maybe_add_bundle_to_output_menu (*i, current);
903 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
904 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
905 maybe_add_bundle_to_output_menu (*i, current);
909 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
910 RouteList copy = *routes;
911 copy.sort (RouteCompareByName ());
912 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
913 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
916 if (citems.size() == n_with_separator) {
917 /* no routes added; remove the separator */
921 if (!ARDOUR::Profile->get_mixbus()) {
922 citems.push_back (SeparatorElem());
924 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
927 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
928 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
934 citems.push_back (SeparatorElem());
935 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
937 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
950 MixerStrip::input_release (GdkEventButton *ev)
952 switch (ev->button) {
955 edit_input_configuration ();
967 MixerStrip::input_press (GdkEventButton *ev)
969 using namespace Menu_Helpers;
971 MenuList& citems = input_menu.items();
972 input_menu.set_name ("ArdourContextMenu");
975 if (!_session->engine().connected()) {
976 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
981 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
984 switch (ev->button) {
987 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
991 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
993 citems.push_back (SeparatorElem());
994 uint32_t const n_with_separator = citems.size ();
996 input_menu_bundles.clear ();
998 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1000 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1002 /* give user bundles first chance at being in the menu */
1004 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1005 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1006 maybe_add_bundle_to_input_menu (*i, current);
1010 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1011 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1012 maybe_add_bundle_to_input_menu (*i, current);
1016 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1017 RouteList copy = *routes;
1018 copy.sort (RouteCompareByName ());
1019 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1020 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1023 if (citems.size() == n_with_separator) {
1024 /* no routes added; remove the separator */
1028 citems.push_back (SeparatorElem());
1029 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1032 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1033 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1038 citems.push_back (SeparatorElem());
1039 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1041 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1053 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1055 if (ignore_toggle) {
1059 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1061 if (std::find (current.begin(), current.end(), c) == current.end()) {
1062 _route->input()->connect_ports_to_bundle (c, true, this);
1064 _route->input()->disconnect_ports_from_bundle (c, this);
1069 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1071 if (ignore_toggle) {
1075 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1077 if (std::find (current.begin(), current.end(), c) == current.end()) {
1078 _route->output()->connect_ports_to_bundle (c, true, this);
1080 _route->output()->disconnect_ports_from_bundle (c, this);
1085 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1087 using namespace Menu_Helpers;
1089 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1093 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1094 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1098 if (i != input_menu_bundles.end()) {
1102 input_menu_bundles.push_back (b);
1104 MenuList& citems = input_menu.items();
1106 std::string n = b->name ();
1107 replace_all (n, "_", " ");
1109 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1113 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1115 using namespace Menu_Helpers;
1117 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1121 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1122 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1126 if (i != output_menu_bundles.end()) {
1130 output_menu_bundles.push_back (b);
1132 MenuList& citems = output_menu.items();
1134 std::string n = b->name ();
1135 replace_all (n, "_", " ");
1137 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1141 MixerStrip::update_diskstream_display ()
1143 if (is_track() && input_selector) {
1144 input_selector->hide_all ();
1147 route_color_changed ();
1151 MixerStrip::connect_to_pan ()
1153 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1155 panstate_connection.disconnect ();
1156 panstyle_connection.disconnect ();
1158 if (!_route->panner()) {
1162 boost::shared_ptr<Pannable> p = _route->pannable ();
1164 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1165 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1167 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1168 * However, that only works a panner was previously set.
1170 * PannerUI must remain subscribed to _panshell->Changed() in case
1171 * we switch the panner eg. AUX-Send and back
1172 * _route->panner_shell()->Changed() vs _panshell->Changed
1174 if (panners._panner == 0) {
1175 panners.panshell_changed ();
1177 update_panner_choices();
1181 MixerStrip::update_panner_choices ()
1183 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1184 if (!_route->panner_shell()) { return; }
1186 uint32_t in = _route->output()->n_ports().n_audio();
1188 if (_route->panner()) {
1189 in = _route->panner()->in().n_audio();
1192 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1196 * Output port labelling
1197 * =====================
1199 * Case 1: Each output has one connection, all connections are to system:playback_%i
1200 * out 1 -> system:playback_1
1201 * out 2 -> system:playback_2
1202 * out 3 -> system:playback_3
1205 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1206 * out 1 -> ardour:track_x/in 1
1207 * out 2 -> ardour:track_x/in 2
1208 * Display as: track_x
1210 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1211 * out 1 -> program x:foo
1212 * out 2 -> program x:foo
1213 * Display as: program x
1215 * Case 4: No connections (Disconnected)
1218 * Default case (unusual routing):
1219 * Display as: *number of connections*
1223 * .-----------------------------------------------.
1225 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1226 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1227 * '-----------------------------------------------'
1228 * .-----------------------------------------------.
1231 * '-----------------------------------------------'
1235 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1239 boost::shared_ptr<IO> io;
1240 boost::shared_ptr<Port> port;
1241 vector<string> port_connections;
1243 uint32_t total_connection_count = 0;
1244 uint32_t io_connection_count = 0;
1245 uint32_t ardour_connection_count = 0;
1246 uint32_t system_connection_count = 0;
1247 uint32_t other_connection_count = 0;
1248 uint32_t typed_connection_count = 0;
1250 ostringstream label;
1252 bool have_label = false;
1253 bool each_io_has_one_connection = true;
1255 string connection_name;
1256 string ardour_track_name;
1257 string other_connection_type;
1258 string system_ports;
1261 ostringstream tooltip;
1262 char * tooltip_cstr;
1264 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1266 * First of all, if the user made only connections to a given type, we should use that one since
1267 * it is very probably what the user expects. If there are several connections types, then show
1268 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1269 * synthesisers. This first heuristic can be expressed with these two rules:
1270 * A) If there are connected audio ports, consider audio as primary type.
1271 * B) Else, if there are connected midi ports, consider midi as primary type.
1273 * If there are no connected ports, then we choose the primary type based on the type of existing
1274 * but unconnected ports. Again:
1275 * C) If there are audio ports, consider audio as primary type.
1276 * D) Else, if there are midi ports, consider midi as primary type. */
1278 DataType dt = DataType::AUDIO;
1282 io = route->input();
1284 io = route->output();
1287 io_count = io->n_ports().n_total();
1288 for (io_index = 0; io_index < io_count; ++io_index) {
1289 port = io->nth (io_index);
1290 if (port->connected()) {
1292 if (port->type() == DataType::AUDIO) {
1293 /* Rule A) applies no matter the remaining ports */
1294 dt = DataType::AUDIO;
1297 if (port->type() == DataType::MIDI) {
1298 /* Rule B) is a good candidate... */
1299 dt = DataType::MIDI;
1300 /* ...but continue the loop to check remaining ports for rule A) */
1306 /* Neither rule A) nor rule B) matched */
1307 if ( io->n_ports().n_audio() > 0 ) {
1309 dt = DataType::AUDIO;
1310 } else if ( io->n_ports().n_midi() > 0 ) {
1312 dt = DataType::MIDI;
1316 if ( dt == DataType::MIDI ) {
1317 tooltip << _("MIDI ");
1321 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1323 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1326 for (io_index = 0; io_index < io_count; ++io_index) {
1327 port = io->nth (io_index);
1329 port_connections.clear ();
1330 port->get_connections(port_connections);
1332 //ignore any port connections that don't match our DataType
1333 if (port->type() != dt) {
1334 if (!port_connections.empty()) {
1335 ++typed_connection_count;
1340 io_connection_count = 0;
1342 if (!port_connections.empty()) {
1343 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1345 string& connection_name (*i);
1347 if (connection_name.find("system:") == 0) {
1348 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1351 if (io_connection_count == 0) {
1352 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1354 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1357 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1360 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1361 if (ardour_track_name.empty()) {
1362 // "ardour:Master/in 1" -> "ardour:Master/"
1363 string::size_type slash = connection_name.find("/");
1364 if (slash != string::npos) {
1365 ardour_track_name = connection_name.substr(0, slash + 1);
1369 if (connection_name.find(ardour_track_name) == 0) {
1370 ++ardour_connection_count;
1372 } else if (!pn.empty()) {
1373 if (system_ports.empty()) {
1376 system_ports += "/" + pn;
1378 if (connection_name.find("system:") == 0) {
1379 ++system_connection_count;
1381 } else if (connection_name.find("system:midi_") == 0) {
1383 // "system:midi_capture_123" -> "123"
1384 system_port = "M " + connection_name.substr(20);
1386 // "system:midi_playback_123" -> "123"
1387 system_port = "M " + connection_name.substr(21);
1390 if (system_ports.empty()) {
1391 system_ports += system_port;
1393 system_ports += "/" + system_port;
1396 ++system_connection_count;
1398 } else if (connection_name.find("system:") == 0) {
1400 // "system:capture_123" -> "123"
1401 system_port = connection_name.substr(15);
1403 // "system:playback_123" -> "123"
1404 system_port = connection_name.substr(16);
1407 if (system_ports.empty()) {
1408 system_ports += system_port;
1410 system_ports += "/" + system_port;
1413 ++system_connection_count;
1415 if (other_connection_type.empty()) {
1416 // "jamin:in 1" -> "jamin:"
1417 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1420 if (connection_name.find(other_connection_type) == 0) {
1421 ++other_connection_count;
1425 ++total_connection_count;
1426 ++io_connection_count;
1430 if (io_connection_count != 1) {
1431 each_io_has_one_connection = false;
1435 if (total_connection_count == 0) {
1436 tooltip << endl << _("Disconnected");
1439 tooltip_cstr = new char[tooltip.str().size() + 1];
1440 strcpy(tooltip_cstr, tooltip.str().c_str());
1443 set_tooltip (&input_button, tooltip_cstr);
1445 set_tooltip (&output_button, tooltip_cstr);
1448 delete [] tooltip_cstr;
1450 if (each_io_has_one_connection) {
1451 if (total_connection_count == ardour_connection_count) {
1452 // all connections are to the same track in ardour
1453 // "ardour:Master/" -> "Master"
1454 string::size_type slash = ardour_track_name.find("/");
1455 if (slash != string::npos) {
1456 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1457 label << ardour_track_name.substr (ppps, slash - ppps);
1461 else if (total_connection_count == system_connection_count) {
1462 // all connections are to system ports
1463 label << system_ports;
1466 else if (total_connection_count == other_connection_count) {
1467 // all connections are to the same external program eg jamin
1468 // "jamin:" -> "jamin"
1469 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1475 if (total_connection_count == 0) {
1479 // Odd configuration
1480 label << "*" << total_connection_count << "*";
1482 if (typed_connection_count > 0) {
1483 label << "\u2295"; // circled plus
1488 input_button.set_text (label.str());
1490 output_button.set_text (label.str());
1495 MixerStrip::update_input_display ()
1497 update_io_button (_route, _width, true);
1498 panners.setup_pan ();
1500 if (has_audio_outputs ()) {
1501 panners.show_all ();
1503 panners.hide_all ();
1509 MixerStrip::update_output_display ()
1511 update_io_button (_route, _width, false);
1512 gpm.setup_meters ();
1513 panners.setup_pan ();
1515 if (has_audio_outputs ()) {
1516 panners.show_all ();
1518 panners.hide_all ();
1523 MixerStrip::fast_update ()
1525 gpm.update_meters ();
1529 MixerStrip::diskstream_changed ()
1531 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1535 MixerStrip::io_changed_proxy ()
1537 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1538 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1542 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1544 boost::shared_ptr<Port> a = wa.lock ();
1545 boost::shared_ptr<Port> b = wb.lock ();
1547 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1548 update_input_display ();
1549 set_width_enum (_width, this);
1552 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1553 update_output_display ();
1554 set_width_enum (_width, this);
1559 MixerStrip::setup_comment_button ()
1561 std::string comment = _route->comment();
1563 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1565 if (comment.empty ()) {
1566 _comment_button.set_name ("generic button");
1567 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1571 _comment_button.set_name ("comment button");
1573 string::size_type pos = comment.find_first_of (" \t\n");
1574 if (pos != string::npos) {
1575 comment = comment.substr (0, pos);
1577 if (comment.empty()) {
1578 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1580 _comment_button.set_text (comment);
1585 MixerStrip::select_route_group (GdkEventButton *ev)
1587 using namespace Menu_Helpers;
1589 if (ev->button == 1) {
1591 if (group_menu == 0) {
1593 PropertyList* plist = new PropertyList();
1595 plist->add (Properties::group_gain, true);
1596 plist->add (Properties::group_mute, true);
1597 plist->add (Properties::group_solo, true);
1599 group_menu = new RouteGroupMenu (_session, plist);
1603 r.push_back (route ());
1604 group_menu->build (r);
1606 RouteGroup *rg = _route->route_group();
1608 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1609 rg ? rg->name() : _("No Group"),
1617 MixerStrip::route_group_changed ()
1619 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1621 RouteGroup *rg = _route->route_group();
1624 group_button.set_text (PBD::short_version (rg->name(), 5));
1628 group_button.set_text (_("Grp"));
1631 group_button.set_text (_("~G"));
1638 MixerStrip::route_color_changed ()
1640 name_button.modify_bg (STATE_NORMAL, color());
1641 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1642 reset_strip_style ();
1646 MixerStrip::show_passthru_color ()
1648 reset_strip_style ();
1653 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1655 boost::shared_ptr<Processor> processor (p.lock ());
1656 if (!processor || !processor->display_to_user()) {
1659 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1661 if (pi && pi->is_channelstrip ()) {
1666 ++_plugin_insert_cnt;
1670 MixerStrip::build_route_ops_menu ()
1672 using namespace Menu_Helpers;
1673 route_ops_menu = new Menu;
1674 route_ops_menu->set_name ("ArdourContextMenu");
1676 MenuList& items = route_ops_menu->items();
1678 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1680 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1682 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1684 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1686 if (!Profile->get_mixbus()) {
1687 items.push_back (SeparatorElem());
1690 if (!_route->is_master()
1692 && !_route->mixbus()
1695 if (Profile->get_mixbus()) {
1696 items.push_back (SeparatorElem());
1698 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1701 if (!Profile->get_mixbus()) {
1702 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1703 /* do not allow rename if the track is record-enabled */
1704 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1707 items.push_back (SeparatorElem());
1708 items.push_back (CheckMenuElem (_("Active")));
1709 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1710 i->set_active (_route->active());
1711 i->set_sensitive(! _session->transport_rolling());
1712 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1714 if (!Profile->get_mixbus ()) {
1715 items.push_back (SeparatorElem());
1716 items.push_back (CheckMenuElem (_("Strict I/O")));
1717 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1718 i->set_active (_route->strict_io());
1719 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1722 _plugin_insert_cnt = 0;
1723 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1724 if (_plugin_insert_cnt > 0) {
1725 items.push_back (SeparatorElem());
1726 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1729 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1730 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1731 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1732 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1735 items.push_back (SeparatorElem());
1736 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1738 items.push_back (SeparatorElem());
1739 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1740 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1741 denormal_menu_item->set_active (_route->denormal_protection());
1744 /* note that this relies on selection being shared across editor and
1745 mixer (or global to the backend, in the future), which is the only
1746 sane thing for users anyway.
1749 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1751 Selection& selection (PublicEditor::instance().get_selection());
1752 if (!selection.selected (rtav)) {
1753 selection.set (rtav);
1756 if (!_route->is_master()) {
1757 items.push_back (SeparatorElem());
1758 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1761 items.push_back (SeparatorElem());
1762 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1768 MixerStrip::name_button_button_press (GdkEventButton* ev)
1770 if (ev->button == 1 || ev->button == 3) {
1771 list_route_operations ();
1773 if (ev->button == 1) {
1774 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1777 route_ops_menu->popup (3, ev->time);
1787 MixerStrip::number_button_button_press (GdkEventButton* ev)
1789 if ( ev->button == 3 ) {
1790 list_route_operations ();
1792 route_ops_menu->popup (1, ev->time);
1801 MixerStrip::list_route_operations ()
1803 delete route_ops_menu;
1804 build_route_ops_menu ();
1808 MixerStrip::set_selected (bool yn)
1810 AxisView::set_selected (yn);
1813 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1814 global_frame.set_name ("MixerStripSelectedFrame");
1816 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1817 global_frame.set_name ("MixerStripFrame");
1820 global_frame.queue_draw ();
1823 // processor_box.deselect_all_processors();
1827 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1829 if (what_changed.contains (ARDOUR::Properties::name)) {
1835 MixerStrip::name_changed ()
1839 name_button.set_text (_route->name());
1842 name_button.set_text (PBD::short_version (_route->name(), 5));
1846 set_tooltip (name_button, _route->name());
1848 if (_session->config.get_track_name_number()) {
1849 const int64_t track_number = _route->track_number ();
1850 if (track_number == 0) {
1851 number_label.set_text ("-");
1853 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1856 number_label.set_text ("");
1861 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1863 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1867 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1869 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1873 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1875 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1879 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1881 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1885 MixerStrip::width_button_pressed (GdkEventButton* ev)
1887 if (ev->button != 1) {
1891 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1894 _mixer.set_strip_width (Narrow, true);
1898 _mixer.set_strip_width (Wide, true);
1904 set_width_enum (Narrow, this);
1907 set_width_enum (Wide, this);
1916 MixerStrip::hide_clicked ()
1918 // LAME fix to reset the button status for when it is redisplayed (part 1)
1919 hide_button.set_sensitive(false);
1922 Hiding(); /* EMIT_SIGNAL */
1924 _mixer.hide_strip (this);
1928 hide_button.set_sensitive(true);
1932 MixerStrip::set_embedded (bool yn)
1938 MixerStrip::map_frozen ()
1940 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1942 boost::shared_ptr<AudioTrack> at = audio_track();
1945 switch (at->freeze_state()) {
1946 case AudioTrack::Frozen:
1947 processor_box.set_sensitive (false);
1948 hide_redirect_editors ();
1951 processor_box.set_sensitive (true);
1952 // XXX need some way, maybe, to retoggle redirect editors
1956 processor_box.set_sensitive (true);
1958 RouteUI::map_frozen ();
1962 MixerStrip::hide_redirect_editors ()
1964 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1968 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1970 boost::shared_ptr<Processor> processor (p.lock ());
1975 Gtk::Window* w = processor_box.get_processor_ui (processor);
1983 MixerStrip::reset_strip_style ()
1985 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1987 gpm.set_fader_name ("SendStripBase");
1991 if (is_midi_track()) {
1992 if (_route->active()) {
1993 set_name ("MidiTrackStripBase");
1995 set_name ("MidiTrackStripBaseInactive");
1997 gpm.set_fader_name ("MidiTrackFader");
1998 } else if (is_audio_track()) {
1999 if (_route->active()) {
2000 set_name ("AudioTrackStripBase");
2002 set_name ("AudioTrackStripBaseInactive");
2004 gpm.set_fader_name ("AudioTrackFader");
2006 if (_route->active()) {
2007 set_name ("AudioBusStripBase");
2009 set_name ("AudioBusStripBaseInactive");
2011 gpm.set_fader_name ("AudioBusFader");
2013 /* (no MIDI busses yet) */
2020 MixerStrip::engine_stopped ()
2025 MixerStrip::engine_running ()
2030 MixerStrip::meter_point_string (MeterPoint mp)
2043 case MeterPostFader:
2060 return S_("Meter|In");
2064 return S_("Meter|Pr");
2067 case MeterPostFader:
2068 return S_("Meter|Po");
2072 return S_("Meter|O");
2077 return S_("Meter|C");
2086 /** Called when the monitor-section state */
2088 MixerStrip::monitor_changed ()
2090 assert (monitor_section_button);
2091 if (_session->monitor_active()) {
2092 monitor_section_button->set_name ("master monitor section button active");
2094 monitor_section_button->set_name ("master monitor section button normal");
2098 /** Called when the metering point has changed */
2100 MixerStrip::meter_changed ()
2102 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2103 gpm.setup_meters ();
2104 // reset peak when meter point changes
2105 gpm.reset_peak_display();
2108 /** The bus that we are displaying sends to has changed, or been turned off.
2109 * @param send_to New bus that we are displaying sends to, or 0.
2112 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2114 RouteUI::bus_send_display_changed (send_to);
2117 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2122 revert_to_default_display ();
2125 revert_to_default_display ();
2130 MixerStrip::drop_send ()
2132 boost::shared_ptr<Send> current_send;
2134 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2135 current_send->set_metering (false);
2138 send_gone_connection.disconnect ();
2139 input_button.set_sensitive (true);
2140 output_button.set_sensitive (true);
2141 group_button.set_sensitive (true);
2142 set_invert_sensitive (true);
2143 gpm.meter_point_button.set_sensitive (true);
2144 mute_button->set_sensitive (true);
2145 solo_button->set_sensitive (true);
2146 solo_isolated_led->set_sensitive (true);
2147 solo_safe_led->set_sensitive (true);
2148 monitor_input_button->set_sensitive (true);
2149 monitor_disk_button->set_sensitive (true);
2150 _comment_button.set_sensitive (true);
2151 RouteUI::check_rec_enable_sensitivity ();
2152 set_button_names (); // update solo button visual state
2156 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2158 _current_delivery = d;
2159 DeliveryChanged (_current_delivery);
2163 MixerStrip::show_send (boost::shared_ptr<Send> send)
2169 set_current_delivery (send);
2171 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2172 send->set_metering (true);
2173 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2175 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2176 gain_meter().setup_meters ();
2178 uint32_t const in = _current_delivery->pans_required();
2179 uint32_t const out = _current_delivery->pan_outs();
2181 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2182 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2183 panner_ui().setup_pan ();
2184 panner_ui().set_send_drawing_mode (true);
2185 panner_ui().show_all ();
2187 input_button.set_sensitive (false);
2188 group_button.set_sensitive (false);
2189 set_invert_sensitive (false);
2190 gpm.meter_point_button.set_sensitive (false);
2191 mute_button->set_sensitive (false);
2192 solo_button->set_sensitive (false);
2193 rec_enable_button->set_sensitive (false);
2194 solo_isolated_led->set_sensitive (false);
2195 solo_safe_led->set_sensitive (false);
2196 monitor_input_button->set_sensitive (false);
2197 monitor_disk_button->set_sensitive (false);
2198 _comment_button.set_sensitive (false);
2200 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2201 output_button.set_sensitive (false);
2204 reset_strip_style ();
2208 MixerStrip::revert_to_default_display ()
2212 set_current_delivery (_route->main_outs ());
2214 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2215 gain_meter().setup_meters ();
2217 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2218 update_panner_choices();
2219 panner_ui().setup_pan ();
2220 panner_ui().set_send_drawing_mode (false);
2222 if (has_audio_outputs ()) {
2223 panners.show_all ();
2225 panners.hide_all ();
2228 reset_strip_style ();
2232 MixerStrip::set_button_names ()
2236 mute_button->set_text (_("Mute"));
2237 monitor_input_button->set_text (_("In"));
2238 monitor_disk_button->set_text (_("Disk"));
2239 if (monitor_section_button) {
2240 monitor_section_button->set_text (_("Mon"));
2243 if (_route && _route->solo_safe_control()->solo_safe()) {
2244 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2246 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2248 if (!Config->get_solo_control_is_listen_control()) {
2249 solo_button->set_text (_("Solo"));
2251 switch (Config->get_listen_position()) {
2252 case AfterFaderListen:
2253 solo_button->set_text (_("AFL"));
2255 case PreFaderListen:
2256 solo_button->set_text (_("PFL"));
2260 solo_isolated_led->set_text (_("Iso"));
2261 solo_safe_led->set_text (S_("SoloLock|Lock"));
2265 mute_button->set_text (S_("Mute|M"));
2266 monitor_input_button->set_text (S_("MonitorInput|I"));
2267 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2268 if (monitor_section_button) {
2269 monitor_section_button->set_text (S_("Mon|O"));
2272 if (_route && _route->solo_safe_control()->solo_safe()) {
2273 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2275 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2277 if (!Config->get_solo_control_is_listen_control()) {
2278 solo_button->set_text (S_("Solo|S"));
2280 switch (Config->get_listen_position()) {
2281 case AfterFaderListen:
2282 solo_button->set_text (S_("AfterFader|A"));
2284 case PreFaderListen:
2285 solo_button->set_text (S_("Prefader|P"));
2290 solo_isolated_led->set_text (S_("SoloIso|I"));
2291 solo_safe_led->set_text (S_("SoloLock|L"));
2296 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2298 gpm.meter_point_button.set_text ("");
2303 MixerStrip::plugin_selector()
2305 return _mixer.plugin_selector();
2309 MixerStrip::hide_things ()
2311 processor_box.hide_things ();
2315 MixerStrip::input_active_button_press (GdkEventButton*)
2317 /* nothing happens on press */
2322 MixerStrip::input_active_button_release (GdkEventButton* ev)
2324 boost::shared_ptr<MidiTrack> mt = midi_track ();
2330 boost::shared_ptr<RouteList> rl (new RouteList);
2332 rl->push_back (route());
2334 _session->set_exclusive_input_active (rl, !mt->input_active(),
2335 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2341 MixerStrip::midi_input_status_changed ()
2343 if (midi_input_enable_button) {
2344 boost::shared_ptr<MidiTrack> mt = midi_track ();
2346 midi_input_enable_button->set_active (mt->input_active ());
2351 MixerStrip::state_id () const
2353 return string_compose ("strip %1", _route->id().to_s());
2357 MixerStrip::parameter_changed (string p)
2359 if (p == _visibility.get_state_name()) {
2360 /* The user has made changes to the mixer strip visibility, so get
2361 our VisibilityGroup to reflect these changes in our widgets.
2363 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2364 } else if (p == "track-name-number") {
2366 } else if (p == "use-monitor-bus") {
2367 if (monitor_section_button) {
2368 if (mute_button->get_parent()) {
2369 mute_button->get_parent()->remove(*mute_button);
2371 if (monitor_section_button->get_parent()) {
2372 monitor_section_button->get_parent()->remove(*monitor_section_button);
2374 if (Config->get_use_monitor_bus ()) {
2375 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2376 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2377 mute_button->show();
2378 monitor_section_button->show();
2380 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2381 mute_button->show();
2384 } else if (p == "track-name-number") {
2385 update_track_number_visibility();
2389 /** Called to decide whether the solo isolate / solo lock button visibility should
2390 * be overridden from that configured by the user. We do this for the master bus.
2392 * @return optional value that is present if visibility state should be overridden.
2394 boost::optional<bool>
2395 MixerStrip::override_solo_visibility () const
2397 if (_route && _route->is_master ()) {
2398 return boost::optional<bool> (false);
2401 return boost::optional<bool> ();
2405 MixerStrip::add_input_port (DataType t)
2407 _route->input()->add_port ("", this, t);
2411 MixerStrip::add_output_port (DataType t)
2413 _route->output()->add_port ("", this, t);
2417 MixerStrip::route_active_changed ()
2419 reset_strip_style ();
2423 MixerStrip::copy_processors ()
2425 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2429 MixerStrip::cut_processors ()
2431 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2435 MixerStrip::paste_processors ()
2437 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2441 MixerStrip::select_all_processors ()
2443 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2447 MixerStrip::deselect_all_processors ()
2449 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2453 MixerStrip::delete_processors ()
2455 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2459 MixerStrip::toggle_processors ()
2461 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2465 MixerStrip::ab_plugins ()
2467 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2471 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2473 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2476 if (ev->button == 3) {
2477 popup_level_meter_menu (ev);
2485 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2487 using namespace Gtk::Menu_Helpers;
2489 Gtk::Menu* m = manage (new Menu);
2490 MenuList& items = m->items ();
2492 RadioMenuItem::Group group;
2494 _suspend_menu_callbacks = true;
2495 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2496 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2497 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2498 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2499 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2501 if (gpm.meter_channels().n_audio() == 0) {
2502 m->popup (ev->button, ev->time);
2503 _suspend_menu_callbacks = false;
2507 RadioMenuItem::Group tgroup;
2508 items.push_back (SeparatorElem());
2510 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2511 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2512 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2513 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2514 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2515 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2516 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2517 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2518 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2519 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2520 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2523 if (_route->is_master()) {
2526 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2527 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2528 /* non-master bus */
2531 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2538 MeterType cmt = _route->meter_type();
2539 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2541 items.push_back (SeparatorElem());
2542 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2543 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2544 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2545 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2546 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2547 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2549 m->popup (ev->button, ev->time);
2550 _suspend_menu_callbacks = false;
2554 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2555 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2557 using namespace Menu_Helpers;
2559 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2560 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2561 i->set_active (_route->meter_point() == point);
2565 MixerStrip::set_meter_point (MeterPoint p)
2567 if (_suspend_menu_callbacks) return;
2568 _route->set_meter_point (p);
2572 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2573 RadioMenuItem::Group& group, string const & name, MeterType type)
2575 using namespace Menu_Helpers;
2577 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2578 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2579 i->set_active (_route->meter_type() == type);
2583 MixerStrip::set_meter_type (MeterType t)
2585 if (_suspend_menu_callbacks) return;
2590 MixerStrip::update_track_number_visibility ()
2592 DisplaySuspender ds;
2593 bool show_label = _session->config.get_track_name_number();
2595 if (_route && _route->is_master()) {
2600 number_label.show ();
2601 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2602 // except the width of the number label is subtracted from the name-hbox, so we
2603 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2604 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2606 number_label.set_size_request(tnw, -1);
2607 number_label.show ();
2609 number_label.hide ();
2614 MixerStrip::color () const
2616 return route_color ();
2620 MixerStrip::marked_for_display () const
2622 return !_route->presentation_info().hidden();
2626 MixerStrip::set_marked_for_display (bool yn)
2628 return RouteUI::mark_hidden (!yn);