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 <gtkmm/messagedialog.h>
27 #include "pbd/convert.h"
28 #include "pbd/enumwriter.h"
29 #include "pbd/replace_all.h"
30 #include "pbd/stacktrace.h"
32 #include "ardour/amp.h"
33 #include "ardour/audio_track.h"
34 #include "ardour/audioengine.h"
35 #include "ardour/internal_send.h"
36 #include "ardour/io.h"
37 #include "ardour/meter.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/pannable.h"
40 #include "ardour/panner.h"
41 #include "ardour/panner_shell.h"
42 #include "ardour/panner_manager.h"
43 #include "ardour/port.h"
44 #include "ardour/profile.h"
45 #include "ardour/route.h"
46 #include "ardour/route_group.h"
47 #include "ardour/send.h"
48 #include "ardour/session.h"
49 #include "ardour/types.h"
50 #include "ardour/user_bundle.h"
51 #include "ardour/vca.h"
52 #include "ardour/vca_manager.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/menu_elems.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/doi.h"
59 #include "widgets/tooltips.h"
61 #include "ardour_window.h"
62 #include "enums_convert.h"
63 #include "mixer_strip.h"
66 #include "public_editor.h"
68 #include "io_selector.h"
70 #include "gui_thread.h"
71 #include "route_group_menu.h"
72 #include "meter_patterns.h"
73 #include "ui_config.h"
77 using namespace ARDOUR;
78 using namespace ArdourWidgets;
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() );
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_state_button.set_text (
781 gpm.astate_string(gain_automation->automation_state()));
783 if (_route->panner()) {
784 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
785 panners.astate_string(_route->panner()->automation_state()));
789 // panners expect an even number of horiz. pixels
790 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
792 set_size_request (width, -1);
798 if (show_sends_button) {
799 show_sends_button->set_text (_("Snd"));
802 gpm.gain_automation_state_button.set_text (
803 gpm.short_astate_string(gain_automation->automation_state()));
804 gain_meter().setup_meters (); // recalc meter width
806 if (_route->panner()) {
807 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
808 panners.short_astate_string(_route->panner()->automation_state()));
812 // panners expect an even number of horiz. pixels
813 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
815 set_size_request (width, -1);
820 processor_box.set_width (w);
822 update_input_display ();
823 update_output_display ();
824 setup_comment_button ();
825 route_group_changed ();
831 MixerStrip::set_packed (bool yn)
834 set_gui_property ("visible", _packed);
838 struct RouteCompareByName {
839 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
840 return a->name().compare (b->name()) < 0;
845 MixerStrip::output_release (GdkEventButton *ev)
847 switch (ev->button) {
849 edit_output_configuration ();
857 MixerStrip::output_press (GdkEventButton *ev)
859 using namespace Menu_Helpers;
860 if (!_session->engine().connected()) {
861 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
866 MenuList& citems = output_menu.items();
867 switch (ev->button) {
870 return false; //wait for the mouse-up to pop the dialog
874 output_menu.set_name ("ArdourContextMenu");
876 output_menu_bundles.clear ();
878 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
880 citems.push_back (SeparatorElem());
881 uint32_t const n_with_separator = citems.size ();
883 ARDOUR::BundleList current = _route->output()->bundles_connected ();
885 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
887 /* give user bundles first chance at being in the menu */
889 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
890 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
891 maybe_add_bundle_to_output_menu (*i, current);
895 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
896 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
897 maybe_add_bundle_to_output_menu (*i, current);
901 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
902 RouteList copy = *routes;
903 copy.sort (RouteCompareByName ());
904 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
905 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
908 if (citems.size() == n_with_separator) {
909 /* no routes added; remove the separator */
913 if (!ARDOUR::Profile->get_mixbus()) {
914 citems.push_back (SeparatorElem());
916 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
919 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
920 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
926 citems.push_back (SeparatorElem());
927 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
929 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
942 MixerStrip::input_release (GdkEventButton *ev)
944 switch (ev->button) {
947 edit_input_configuration ();
959 MixerStrip::input_press (GdkEventButton *ev)
961 using namespace Menu_Helpers;
963 MenuList& citems = input_menu.items();
964 input_menu.set_name ("ArdourContextMenu");
967 if (!_session->engine().connected()) {
968 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
973 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
976 switch (ev->button) {
979 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
983 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
985 citems.push_back (SeparatorElem());
986 uint32_t const n_with_separator = citems.size ();
988 input_menu_bundles.clear ();
990 ARDOUR::BundleList current = _route->input()->bundles_connected ();
992 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
994 /* give user bundles first chance at being in the menu */
996 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
997 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
998 maybe_add_bundle_to_input_menu (*i, current);
1002 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1003 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1004 maybe_add_bundle_to_input_menu (*i, current);
1008 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1009 RouteList copy = *routes;
1010 copy.sort (RouteCompareByName ());
1011 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1012 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1015 if (citems.size() == n_with_separator) {
1016 /* no routes added; remove the separator */
1020 citems.push_back (SeparatorElem());
1021 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1024 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1025 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1030 citems.push_back (SeparatorElem());
1031 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1033 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1045 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1047 if (ignore_toggle) {
1051 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1053 if (std::find (current.begin(), current.end(), c) == current.end()) {
1054 _route->input()->connect_ports_to_bundle (c, true, this);
1056 _route->input()->disconnect_ports_from_bundle (c, this);
1061 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1063 if (ignore_toggle) {
1067 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1069 if (std::find (current.begin(), current.end(), c) == current.end()) {
1070 _route->output()->connect_ports_to_bundle (c, true, this);
1072 _route->output()->disconnect_ports_from_bundle (c, this);
1077 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1079 using namespace Menu_Helpers;
1081 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1085 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1086 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1090 if (i != input_menu_bundles.end()) {
1094 input_menu_bundles.push_back (b);
1096 MenuList& citems = input_menu.items();
1097 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1101 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1103 using namespace Menu_Helpers;
1105 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1109 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1110 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1114 if (i != output_menu_bundles.end()) {
1118 output_menu_bundles.push_back (b);
1120 MenuList& citems = output_menu.items();
1121 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1125 MixerStrip::update_diskstream_display ()
1127 if (is_track() && input_selector) {
1128 input_selector->hide_all ();
1131 route_color_changed ();
1135 MixerStrip::connect_to_pan ()
1137 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1139 panstate_connection.disconnect ();
1140 panstyle_connection.disconnect ();
1142 if (!_route->panner()) {
1146 boost::shared_ptr<Pannable> p = _route->pannable ();
1148 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1150 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1151 * However, that only works a panner was previously set.
1153 * PannerUI must remain subscribed to _panshell->Changed() in case
1154 * we switch the panner eg. AUX-Send and back
1155 * _route->panner_shell()->Changed() vs _panshell->Changed
1157 if (panners._panner == 0) {
1158 panners.panshell_changed ();
1160 update_panner_choices();
1164 MixerStrip::update_panner_choices ()
1166 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1167 if (!_route->panner_shell()) { return; }
1169 uint32_t in = _route->output()->n_ports().n_audio();
1171 if (_route->panner()) {
1172 in = _route->panner()->in().n_audio();
1175 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1179 * Output port labelling
1180 * =====================
1182 * Case 1: Each output has one connection, all connections are to system:playback_%i
1183 * out 1 -> system:playback_1
1184 * out 2 -> system:playback_2
1185 * out 3 -> system:playback_3
1188 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1189 * out 1 -> ardour:track_x/in 1
1190 * out 2 -> ardour:track_x/in 2
1191 * Display as: track_x
1193 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1194 * out 1 -> program x:foo
1195 * out 2 -> program x:foo
1196 * Display as: program x
1198 * Case 4: No connections (Disconnected)
1201 * Default case (unusual routing):
1202 * Display as: *number of connections*
1206 * .-----------------------------------------------.
1208 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1209 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1210 * '-----------------------------------------------'
1211 * .-----------------------------------------------.
1214 * '-----------------------------------------------'
1218 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1222 boost::shared_ptr<IO> io;
1223 boost::shared_ptr<Port> port;
1224 vector<string> port_connections;
1226 uint32_t total_connection_count = 0;
1227 uint32_t io_connection_count = 0;
1228 uint32_t ardour_connection_count = 0;
1229 uint32_t system_connection_count = 0;
1230 uint32_t other_connection_count = 0;
1231 uint32_t typed_connection_count = 0;
1233 ostringstream label;
1235 bool have_label = false;
1236 bool each_io_has_one_connection = true;
1238 string connection_name;
1239 string ardour_track_name;
1240 string other_connection_type;
1241 string system_ports;
1244 ostringstream tooltip;
1245 char * tooltip_cstr;
1247 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1249 * First of all, if the user made only connections to a given type, we should use that one since
1250 * it is very probably what the user expects. If there are several connections types, then show
1251 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1252 * synthesisers. This first heuristic can be expressed with these two rules:
1253 * A) If there are connected audio ports, consider audio as primary type.
1254 * B) Else, if there are connected midi ports, consider midi as primary type.
1256 * If there are no connected ports, then we choose the primary type based on the type of existing
1257 * but unconnected ports. Again:
1258 * C) If there are audio ports, consider audio as primary type.
1259 * D) Else, if there are midi ports, consider midi as primary type. */
1261 DataType dt = DataType::AUDIO;
1265 io = route->input();
1267 io = route->output();
1270 io_count = io->n_ports().n_total();
1271 for (io_index = 0; io_index < io_count; ++io_index) {
1272 port = io->nth (io_index);
1273 if (port->connected()) {
1275 if (port->type() == DataType::AUDIO) {
1276 /* Rule A) applies no matter the remaining ports */
1277 dt = DataType::AUDIO;
1280 if (port->type() == DataType::MIDI) {
1281 /* Rule B) is a good candidate... */
1282 dt = DataType::MIDI;
1283 /* ...but continue the loop to check remaining ports for rule A) */
1289 /* Neither rule A) nor rule B) matched */
1290 if ( io->n_ports().n_audio() > 0 ) {
1292 dt = DataType::AUDIO;
1293 } else if ( io->n_ports().n_midi() > 0 ) {
1295 dt = DataType::MIDI;
1299 if ( dt == DataType::MIDI ) {
1300 tooltip << _("MIDI ");
1304 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1306 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1309 for (io_index = 0; io_index < io_count; ++io_index) {
1310 port = io->nth (io_index);
1312 port_connections.clear ();
1313 port->get_connections(port_connections);
1315 //ignore any port connections that don't match our DataType
1316 if (port->type() != dt) {
1317 if (!port_connections.empty()) {
1318 ++typed_connection_count;
1323 io_connection_count = 0;
1325 if (!port_connections.empty()) {
1326 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1328 string& connection_name (*i);
1330 if (connection_name.find("system:") == 0) {
1331 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1334 if (io_connection_count == 0) {
1335 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1337 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1340 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1343 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1344 if (ardour_track_name.empty()) {
1345 // "ardour:Master/in 1" -> "ardour:Master/"
1346 string::size_type slash = connection_name.find("/");
1347 if (slash != string::npos) {
1348 ardour_track_name = connection_name.substr(0, slash + 1);
1352 if (connection_name.find(ardour_track_name) == 0) {
1353 ++ardour_connection_count;
1355 } else if (!pn.empty()) {
1356 if (system_ports.empty()) {
1359 system_ports += "/" + pn;
1361 if (connection_name.find("system:") == 0) {
1362 ++system_connection_count;
1364 } else if (connection_name.find("system:midi_") == 0) {
1366 // "system:midi_capture_123" -> "123"
1367 system_port = "M " + connection_name.substr(20);
1369 // "system:midi_playback_123" -> "123"
1370 system_port = "M " + connection_name.substr(21);
1373 if (system_ports.empty()) {
1374 system_ports += system_port;
1376 system_ports += "/" + system_port;
1379 ++system_connection_count;
1381 } else if (connection_name.find("system:") == 0) {
1383 // "system:capture_123" -> "123"
1384 system_port = connection_name.substr(15);
1386 // "system:playback_123" -> "123"
1387 system_port = connection_name.substr(16);
1390 if (system_ports.empty()) {
1391 system_ports += system_port;
1393 system_ports += "/" + system_port;
1396 ++system_connection_count;
1398 if (other_connection_type.empty()) {
1399 // "jamin:in 1" -> "jamin:"
1400 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1403 if (connection_name.find(other_connection_type) == 0) {
1404 ++other_connection_count;
1408 ++total_connection_count;
1409 ++io_connection_count;
1413 if (io_connection_count != 1) {
1414 each_io_has_one_connection = false;
1418 if (total_connection_count == 0) {
1419 tooltip << endl << _("Disconnected");
1422 tooltip_cstr = new char[tooltip.str().size() + 1];
1423 strcpy(tooltip_cstr, tooltip.str().c_str());
1426 set_tooltip (&input_button, tooltip_cstr);
1428 set_tooltip (&output_button, tooltip_cstr);
1431 delete [] tooltip_cstr;
1433 if (each_io_has_one_connection) {
1434 if (total_connection_count == ardour_connection_count) {
1435 // all connections are to the same track in ardour
1436 // "ardour:Master/" -> "Master"
1437 string::size_type slash = ardour_track_name.find("/");
1438 if (slash != string::npos) {
1439 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1440 label << ardour_track_name.substr (ppps, slash - ppps);
1444 else if (total_connection_count == system_connection_count) {
1445 // all connections are to system ports
1446 label << system_ports;
1449 else if (total_connection_count == other_connection_count) {
1450 // all connections are to the same external program eg jamin
1451 // "jamin:" -> "jamin"
1452 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1458 if (total_connection_count == 0) {
1462 // Odd configuration
1463 label << "*" << total_connection_count << "*";
1465 if (typed_connection_count > 0) {
1466 label << "\u2295"; // circled plus
1471 input_button.set_text (label.str());
1473 output_button.set_text (label.str());
1478 MixerStrip::update_input_display ()
1480 update_io_button (_route, _width, true);
1481 panners.setup_pan ();
1483 if (has_audio_outputs ()) {
1484 panners.show_all ();
1486 panners.hide_all ();
1492 MixerStrip::update_output_display ()
1494 update_io_button (_route, _width, false);
1495 gpm.setup_meters ();
1496 panners.setup_pan ();
1498 if (has_audio_outputs ()) {
1499 panners.show_all ();
1501 panners.hide_all ();
1506 MixerStrip::fast_update ()
1508 gpm.update_meters ();
1512 MixerStrip::diskstream_changed ()
1514 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1518 MixerStrip::io_changed_proxy ()
1520 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1521 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1525 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1527 boost::shared_ptr<Port> a = wa.lock ();
1528 boost::shared_ptr<Port> b = wb.lock ();
1530 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1531 update_input_display ();
1532 set_width_enum (_width, this);
1535 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1536 update_output_display ();
1537 set_width_enum (_width, this);
1542 MixerStrip::setup_comment_button ()
1544 std::string comment = _route->comment();
1546 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1548 if (comment.empty ()) {
1549 _comment_button.set_name ("generic button");
1550 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1554 _comment_button.set_name ("comment button");
1556 string::size_type pos = comment.find_first_of (" \t\n");
1557 if (pos != string::npos) {
1558 comment = comment.substr (0, pos);
1560 if (comment.empty()) {
1561 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1563 _comment_button.set_text (comment);
1568 MixerStrip::select_route_group (GdkEventButton *ev)
1570 using namespace Menu_Helpers;
1572 if (ev->button == 1) {
1574 if (group_menu == 0) {
1576 PropertyList* plist = new PropertyList();
1578 plist->add (Properties::group_gain, true);
1579 plist->add (Properties::group_mute, true);
1580 plist->add (Properties::group_solo, true);
1582 group_menu = new RouteGroupMenu (_session, plist);
1586 r.push_back (route ());
1587 group_menu->build (r);
1589 RouteGroup *rg = _route->route_group();
1591 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1592 rg ? rg->name() : _("No Group"),
1600 MixerStrip::route_group_changed ()
1602 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1604 RouteGroup *rg = _route->route_group();
1607 group_button.set_text (PBD::short_version (rg->name(), 5));
1611 group_button.set_text (_("Grp"));
1614 group_button.set_text (_("~G"));
1621 MixerStrip::route_color_changed ()
1623 using namespace ARDOUR_UI_UTILS;
1624 name_button.modify_bg (STATE_NORMAL, color());
1625 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1626 reset_strip_style ();
1630 MixerStrip::show_passthru_color ()
1632 reset_strip_style ();
1637 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1639 boost::shared_ptr<Processor> processor (p.lock ());
1640 if (!processor || !processor->display_to_user()) {
1643 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1645 if (pi && pi->is_channelstrip ()) {
1650 ++_plugin_insert_cnt;
1654 MixerStrip::build_route_ops_menu ()
1656 using namespace Menu_Helpers;
1657 route_ops_menu = new Menu;
1658 route_ops_menu->set_name ("ArdourContextMenu");
1660 MenuList& items = route_ops_menu->items();
1662 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1664 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1666 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1668 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1670 if (!Profile->get_mixbus()) {
1671 items.push_back (SeparatorElem());
1674 if (!_route->is_master()
1676 && !_route->mixbus()
1679 if (Profile->get_mixbus()) {
1680 items.push_back (SeparatorElem());
1682 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1685 if (!Profile->get_mixbus()) {
1686 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1687 /* do not allow rename if the track is record-enabled */
1688 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1691 items.push_back (SeparatorElem());
1692 items.push_back (CheckMenuElem (_("Active")));
1693 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1694 i->set_active (_route->active());
1695 i->set_sensitive(! _session->transport_rolling());
1696 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1698 if (!Profile->get_mixbus ()) {
1699 items.push_back (SeparatorElem());
1700 items.push_back (CheckMenuElem (_("Strict I/O")));
1701 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1702 i->set_active (_route->strict_io());
1703 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1706 _plugin_insert_cnt = 0;
1707 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1708 if (_plugin_insert_cnt > 0) {
1709 items.push_back (SeparatorElem());
1710 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1713 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1714 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1715 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1716 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1719 items.push_back (SeparatorElem());
1720 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1722 items.push_back (SeparatorElem());
1723 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1724 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1725 denormal_menu_item->set_active (_route->denormal_protection());
1728 /* note that this relies on selection being shared across editor and
1729 mixer (or global to the backend, in the future), which is the only
1730 sane thing for users anyway.
1733 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1735 Selection& selection (PublicEditor::instance().get_selection());
1736 if (!selection.selected (rtav)) {
1737 selection.set (rtav);
1740 if (!_route->is_master()) {
1741 items.push_back (SeparatorElem());
1742 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1745 items.push_back (SeparatorElem());
1746 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1752 MixerStrip::name_button_button_press (GdkEventButton* ev)
1754 if (ev->button == 1 || ev->button == 3) {
1755 list_route_operations ();
1757 if (ev->button == 1) {
1758 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1761 route_ops_menu->popup (3, ev->time);
1771 MixerStrip::number_button_button_press (GdkEventButton* ev)
1773 if ( ev->button == 3 ) {
1774 list_route_operations ();
1776 route_ops_menu->popup (1, ev->time);
1785 MixerStrip::list_route_operations ()
1787 delete route_ops_menu;
1788 build_route_ops_menu ();
1792 MixerStrip::set_selected (bool yn)
1794 AxisView::set_selected (yn);
1797 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1798 global_frame.set_name ("MixerStripSelectedFrame");
1800 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1801 global_frame.set_name ("MixerStripFrame");
1804 global_frame.queue_draw ();
1807 // processor_box.deselect_all_processors();
1811 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1813 if (what_changed.contains (ARDOUR::Properties::name)) {
1819 MixerStrip::name_changed ()
1823 name_button.set_text (_route->name());
1826 name_button.set_text (PBD::short_version (_route->name(), 5));
1830 set_tooltip (name_button, _route->name());
1832 if (_session->config.get_track_name_number()) {
1833 const int64_t track_number = _route->track_number ();
1834 if (track_number == 0) {
1835 number_label.set_text ("-");
1837 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1840 number_label.set_text ("");
1845 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1847 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1851 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1853 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1857 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1859 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1863 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1865 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1869 MixerStrip::width_button_pressed (GdkEventButton* ev)
1871 if (ev->button != 1) {
1875 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1878 _mixer.set_strip_width (Narrow, true);
1882 _mixer.set_strip_width (Wide, true);
1888 set_width_enum (Narrow, this);
1891 set_width_enum (Wide, this);
1900 MixerStrip::hide_clicked ()
1902 // LAME fix to reset the button status for when it is redisplayed (part 1)
1903 hide_button.set_sensitive(false);
1906 Hiding(); /* EMIT_SIGNAL */
1908 _mixer.hide_strip (this);
1912 hide_button.set_sensitive(true);
1916 MixerStrip::set_embedded (bool yn)
1922 MixerStrip::map_frozen ()
1924 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1926 boost::shared_ptr<AudioTrack> at = audio_track();
1929 switch (at->freeze_state()) {
1930 case AudioTrack::Frozen:
1931 processor_box.set_sensitive (false);
1932 hide_redirect_editors ();
1935 processor_box.set_sensitive (true);
1936 // XXX need some way, maybe, to retoggle redirect editors
1940 processor_box.set_sensitive (true);
1942 RouteUI::map_frozen ();
1946 MixerStrip::hide_redirect_editors ()
1948 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1952 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1954 boost::shared_ptr<Processor> processor (p.lock ());
1959 Gtk::Window* w = processor_box.get_processor_ui (processor);
1967 MixerStrip::reset_strip_style ()
1969 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1971 gpm.set_fader_name ("SendStripBase");
1975 if (is_midi_track()) {
1976 if (_route->active()) {
1977 set_name ("MidiTrackStripBase");
1979 set_name ("MidiTrackStripBaseInactive");
1981 gpm.set_fader_name ("MidiTrackFader");
1982 } else if (is_audio_track()) {
1983 if (_route->active()) {
1984 set_name ("AudioTrackStripBase");
1986 set_name ("AudioTrackStripBaseInactive");
1988 gpm.set_fader_name ("AudioTrackFader");
1990 if (_route->active()) {
1991 set_name ("AudioBusStripBase");
1993 set_name ("AudioBusStripBaseInactive");
1995 gpm.set_fader_name ("AudioBusFader");
1997 /* (no MIDI busses yet) */
2004 MixerStrip::engine_stopped ()
2009 MixerStrip::engine_running ()
2014 MixerStrip::meter_point_string (MeterPoint mp)
2027 case MeterPostFader:
2044 return S_("Meter|In");
2048 return S_("Meter|Pr");
2051 case MeterPostFader:
2052 return S_("Meter|Po");
2056 return S_("Meter|O");
2061 return S_("Meter|C");
2070 /** Called when the monitor-section state */
2072 MixerStrip::monitor_changed ()
2074 assert (monitor_section_button);
2075 if (_session->monitor_active()) {
2076 monitor_section_button->set_name ("master monitor section button active");
2078 monitor_section_button->set_name ("master monitor section button normal");
2082 /** Called when the metering point has changed */
2084 MixerStrip::meter_changed ()
2086 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2087 gpm.setup_meters ();
2088 // reset peak when meter point changes
2089 gpm.reset_peak_display();
2092 /** The bus that we are displaying sends to has changed, or been turned off.
2093 * @param send_to New bus that we are displaying sends to, or 0.
2096 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2098 RouteUI::bus_send_display_changed (send_to);
2101 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2106 revert_to_default_display ();
2109 revert_to_default_display ();
2114 MixerStrip::drop_send ()
2116 boost::shared_ptr<Send> current_send;
2118 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2119 current_send->set_metering (false);
2122 send_gone_connection.disconnect ();
2123 input_button.set_sensitive (true);
2124 output_button.set_sensitive (true);
2125 group_button.set_sensitive (true);
2126 set_invert_sensitive (true);
2127 gpm.meter_point_button.set_sensitive (true);
2128 mute_button->set_sensitive (true);
2129 solo_button->set_sensitive (true);
2130 solo_isolated_led->set_sensitive (true);
2131 solo_safe_led->set_sensitive (true);
2132 monitor_input_button->set_sensitive (true);
2133 monitor_disk_button->set_sensitive (true);
2134 _comment_button.set_sensitive (true);
2135 RouteUI::check_rec_enable_sensitivity ();
2136 set_button_names (); // update solo button visual state
2140 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2142 _current_delivery = d;
2143 DeliveryChanged (_current_delivery);
2147 MixerStrip::show_send (boost::shared_ptr<Send> send)
2153 set_current_delivery (send);
2155 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2156 send->set_metering (true);
2157 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2159 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2160 gain_meter().setup_meters ();
2162 uint32_t const in = _current_delivery->pans_required();
2163 uint32_t const out = _current_delivery->pan_outs();
2165 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2166 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2167 panner_ui().setup_pan ();
2168 panner_ui().set_send_drawing_mode (true);
2169 panner_ui().show_all ();
2171 input_button.set_sensitive (false);
2172 group_button.set_sensitive (false);
2173 set_invert_sensitive (false);
2174 gpm.meter_point_button.set_sensitive (false);
2175 mute_button->set_sensitive (false);
2176 solo_button->set_sensitive (false);
2177 rec_enable_button->set_sensitive (false);
2178 solo_isolated_led->set_sensitive (false);
2179 solo_safe_led->set_sensitive (false);
2180 monitor_input_button->set_sensitive (false);
2181 monitor_disk_button->set_sensitive (false);
2182 _comment_button.set_sensitive (false);
2184 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2185 output_button.set_sensitive (false);
2188 reset_strip_style ();
2192 MixerStrip::revert_to_default_display ()
2196 set_current_delivery (_route->main_outs ());
2198 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2199 gain_meter().setup_meters ();
2201 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2202 update_panner_choices();
2203 panner_ui().setup_pan ();
2204 panner_ui().set_send_drawing_mode (false);
2206 if (has_audio_outputs ()) {
2207 panners.show_all ();
2209 panners.hide_all ();
2212 reset_strip_style ();
2216 MixerStrip::set_button_names ()
2220 mute_button->set_text (_("Mute"));
2221 monitor_input_button->set_text (_("In"));
2222 monitor_disk_button->set_text (_("Disk"));
2223 if (monitor_section_button) {
2224 monitor_section_button->set_text (_("Mon"));
2227 if (_route && _route->solo_safe_control()->solo_safe()) {
2228 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2230 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2232 if (!Config->get_solo_control_is_listen_control()) {
2233 solo_button->set_text (_("Solo"));
2235 switch (Config->get_listen_position()) {
2236 case AfterFaderListen:
2237 solo_button->set_text (_("AFL"));
2239 case PreFaderListen:
2240 solo_button->set_text (_("PFL"));
2244 solo_isolated_led->set_text (_("Iso"));
2245 solo_safe_led->set_text (S_("SoloLock|Lock"));
2249 mute_button->set_text (S_("Mute|M"));
2250 monitor_input_button->set_text (S_("MonitorInput|I"));
2251 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2252 if (monitor_section_button) {
2253 monitor_section_button->set_text (S_("Mon|O"));
2256 if (_route && _route->solo_safe_control()->solo_safe()) {
2257 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2259 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2261 if (!Config->get_solo_control_is_listen_control()) {
2262 solo_button->set_text (S_("Solo|S"));
2264 switch (Config->get_listen_position()) {
2265 case AfterFaderListen:
2266 solo_button->set_text (S_("AfterFader|A"));
2268 case PreFaderListen:
2269 solo_button->set_text (S_("Prefader|P"));
2274 solo_isolated_led->set_text (S_("SoloIso|I"));
2275 solo_safe_led->set_text (S_("SoloLock|L"));
2280 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2282 gpm.meter_point_button.set_text ("");
2287 MixerStrip::plugin_selector()
2289 return _mixer.plugin_selector();
2293 MixerStrip::hide_things ()
2295 processor_box.hide_things ();
2299 MixerStrip::input_active_button_press (GdkEventButton*)
2301 /* nothing happens on press */
2306 MixerStrip::input_active_button_release (GdkEventButton* ev)
2308 boost::shared_ptr<MidiTrack> mt = midi_track ();
2314 boost::shared_ptr<RouteList> rl (new RouteList);
2316 rl->push_back (route());
2318 _session->set_exclusive_input_active (rl, !mt->input_active(),
2319 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2325 MixerStrip::midi_input_status_changed ()
2327 if (midi_input_enable_button) {
2328 boost::shared_ptr<MidiTrack> mt = midi_track ();
2330 midi_input_enable_button->set_active (mt->input_active ());
2335 MixerStrip::state_id () const
2337 return string_compose ("strip %1", _route->id().to_s());
2341 MixerStrip::parameter_changed (string p)
2343 if (p == _visibility.get_state_name()) {
2344 /* The user has made changes to the mixer strip visibility, so get
2345 our VisibilityGroup to reflect these changes in our widgets.
2347 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2348 } else if (p == "track-name-number") {
2350 } else if (p == "use-monitor-bus") {
2351 if (monitor_section_button) {
2352 if (mute_button->get_parent()) {
2353 mute_button->get_parent()->remove(*mute_button);
2355 if (monitor_section_button->get_parent()) {
2356 monitor_section_button->get_parent()->remove(*monitor_section_button);
2358 if (Config->get_use_monitor_bus ()) {
2359 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2360 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2361 mute_button->show();
2362 monitor_section_button->show();
2364 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2365 mute_button->show();
2368 } else if (p == "track-name-number") {
2369 update_track_number_visibility();
2373 /** Called to decide whether the solo isolate / solo lock button visibility should
2374 * be overridden from that configured by the user. We do this for the master bus.
2376 * @return optional value that is present if visibility state should be overridden.
2378 boost::optional<bool>
2379 MixerStrip::override_solo_visibility () const
2381 if (_route && _route->is_master ()) {
2382 return boost::optional<bool> (false);
2385 return boost::optional<bool> ();
2389 MixerStrip::add_input_port (DataType t)
2391 _route->input()->add_port ("", this, t);
2395 MixerStrip::add_output_port (DataType t)
2397 _route->output()->add_port ("", this, t);
2401 MixerStrip::route_active_changed ()
2403 reset_strip_style ();
2407 MixerStrip::copy_processors ()
2409 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2413 MixerStrip::cut_processors ()
2415 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2419 MixerStrip::paste_processors ()
2421 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2425 MixerStrip::select_all_processors ()
2427 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2431 MixerStrip::deselect_all_processors ()
2433 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2437 MixerStrip::delete_processors ()
2439 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2443 MixerStrip::toggle_processors ()
2445 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2449 MixerStrip::ab_plugins ()
2451 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2455 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2457 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2460 if (ev->button == 3) {
2461 popup_level_meter_menu (ev);
2469 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2471 using namespace Gtk::Menu_Helpers;
2473 Gtk::Menu* m = manage (new Menu);
2474 MenuList& items = m->items ();
2476 RadioMenuItem::Group group;
2478 _suspend_menu_callbacks = true;
2479 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2480 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2481 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2482 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2483 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2485 if (gpm.meter_channels().n_audio() == 0) {
2486 m->popup (ev->button, ev->time);
2487 _suspend_menu_callbacks = false;
2491 RadioMenuItem::Group tgroup;
2492 items.push_back (SeparatorElem());
2494 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2495 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2496 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2497 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2498 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2499 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2500 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2501 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2502 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2503 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2504 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2507 if (_route->is_master()) {
2510 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2511 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2512 /* non-master bus */
2515 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2522 MeterType cmt = _route->meter_type();
2523 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2525 items.push_back (SeparatorElem());
2526 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2527 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2528 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2529 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2530 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2531 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2533 m->popup (ev->button, ev->time);
2534 _suspend_menu_callbacks = false;
2538 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2539 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2541 using namespace Menu_Helpers;
2543 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2544 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2545 i->set_active (_route->meter_point() == point);
2549 MixerStrip::set_meter_point (MeterPoint p)
2551 if (_suspend_menu_callbacks) return;
2552 _route->set_meter_point (p);
2556 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2557 RadioMenuItem::Group& group, string const & name, MeterType type)
2559 using namespace Menu_Helpers;
2561 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2562 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2563 i->set_active (_route->meter_type() == type);
2567 MixerStrip::set_meter_type (MeterType t)
2569 if (_suspend_menu_callbacks) return;
2574 MixerStrip::update_track_number_visibility ()
2576 DisplaySuspender ds;
2577 bool show_label = _session->config.get_track_name_number();
2579 if (_route && _route->is_master()) {
2584 number_label.show ();
2585 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2586 // except the width of the number label is subtracted from the name-hbox, so we
2587 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2588 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2590 number_label.set_size_request(tnw, -1);
2591 number_label.show ();
2593 number_label.hide ();
2598 MixerStrip::color () const
2600 return route_color ();
2604 MixerStrip::marked_for_display () const
2606 return !_route->presentation_info().hidden();
2610 MixerStrip::set_marked_for_display (bool yn)
2612 return RouteUI::mark_hidden (!yn);