2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <sigc++/bind.h>
25 #include "pbd/convert.h"
26 #include "pbd/enumwriter.h"
27 #include "pbd/replace_all.h"
28 #include "pbd/stacktrace.h"
30 #include <gtkmm2ext/gtk_ui.h>
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/choice.h>
33 #include <gtkmm2ext/doi.h>
34 #include <gtkmm2ext/slider_controller.h>
35 #include <gtkmm2ext/bindable_button.h>
37 #include "ardour/amp.h"
38 #include "ardour/audio_track.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/internal_send.h"
41 #include "ardour/io.h"
42 #include "ardour/meter.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/pannable.h"
45 #include "ardour/panner.h"
46 #include "ardour/panner_shell.h"
47 #include "ardour/panner_manager.h"
48 #include "ardour/port.h"
49 #include "ardour/profile.h"
50 #include "ardour/route.h"
51 #include "ardour/route_group.h"
52 #include "ardour/send.h"
53 #include "ardour/session.h"
54 #include "ardour/types.h"
55 #include "ardour/user_bundle.h"
56 #include "ardour/vca.h"
57 #include "ardour/vca_manager.h"
59 #include "ardour_window.h"
60 #include "mixer_strip.h"
63 #include "ardour_button.h"
64 #include "public_editor.h"
66 #include "io_selector.h"
68 #include "gui_thread.h"
69 #include "route_group_menu.h"
70 #include "meter_patterns.h"
72 #include "ui_config.h"
76 using namespace ARDOUR;
77 using namespace ARDOUR_UI_UTILS;
80 using namespace Gtkmm2ext;
82 using namespace ArdourMeter;
84 MixerStrip* MixerStrip::_entered_mixer_strip;
85 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
87 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
88 : SessionHandlePtr (sess)
91 , _mixer_owned (in_mixer)
92 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
95 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
96 , rec_mon_table (2, 2)
97 , solo_iso_table (1, 2)
98 , mute_solo_table (1, 2)
99 , bottom_button_table (1, 3)
100 , meter_point_button (_("pre"))
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 , meter_point_button (_("pre"))
134 , monitor_section_button (0)
135 , midi_input_enable_button (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;
157 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
158 longest_label = "longest label";
160 string t = _("Click to toggle the width of this mixer strip.");
162 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
165 width_button.set_icon (ArdourIcon::StripWidth);
166 hide_button.set_tweaks (ArdourButton::Square);
167 set_tooltip (width_button, t);
169 hide_button.set_icon (ArdourIcon::CloseCross);
170 hide_button.set_tweaks (ArdourButton::Square);
171 set_tooltip (&hide_button, _("Hide this mixer strip"));
173 input_button_box.set_spacing(2);
175 input_button.set_text (_("Input"));
176 input_button.set_name ("mixer strip button");
177 input_button_box.pack_start (input_button, true, true);
179 output_button.set_text (_("Output"));
180 output_button.set_name ("mixer strip button");
182 set_tooltip (&meter_point_button, _("Click to select metering point"));
183 meter_point_button.set_name ("mixer strip button");
185 bottom_button_table.attach (meter_point_button, 2, 3, 0, 1);
187 meter_point_button.signal_button_press_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_press), false);
188 meter_point_button.signal_button_release_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_release), false);
190 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
192 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
193 solo_isolated_led->show ();
194 solo_isolated_led->set_no_show_all (true);
195 solo_isolated_led->set_name (X_("solo isolate"));
196 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
197 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
198 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
200 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
201 solo_safe_led->show ();
202 solo_safe_led->set_no_show_all (true);
203 solo_safe_led->set_name (X_("solo safe"));
204 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
205 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
206 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
208 solo_safe_led->set_text (S_("SoloLock|Lock"));
209 solo_isolated_led->set_text (_("Iso"));
211 solo_iso_table.set_homogeneous (true);
212 solo_iso_table.set_spacings (2);
213 if (!ARDOUR::Profile->get_trx()) {
214 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
215 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
217 solo_iso_table.show ();
219 rec_mon_table.set_homogeneous (true);
220 rec_mon_table.set_row_spacings (2);
221 rec_mon_table.set_col_spacings (2);
222 if (ARDOUR::Profile->get_mixbus()) {
223 rec_mon_table.resize (1, 3);
224 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
225 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
226 } else if (!ARDOUR::Profile->get_trx()) {
227 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
228 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
230 rec_mon_table.show ();
232 if (solo_isolated_led) {
233 button_size_group->add_widget (*solo_isolated_led);
236 button_size_group->add_widget (*solo_safe_led);
239 if (!ARDOUR::Profile->get_mixbus()) {
240 if (rec_enable_button) {
241 button_size_group->add_widget (*rec_enable_button);
243 if (monitor_disk_button) {
244 button_size_group->add_widget (*monitor_disk_button);
246 if (monitor_input_button) {
247 button_size_group->add_widget (*monitor_input_button);
251 mute_solo_table.set_homogeneous (true);
252 mute_solo_table.set_spacings (2);
254 bottom_button_table.set_spacings (2);
255 bottom_button_table.set_homogeneous (true);
256 bottom_button_table.attach (group_button, 1, 2, 0, 1);
257 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
259 name_button.set_name ("mixer strip button");
260 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
263 set_tooltip (&group_button, _("Mix group"));
264 group_button.set_name ("mixer strip button");
266 _comment_button.set_name (X_("mixer strip button"));
267 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
268 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
269 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
271 // TODO implement ArdourKnob::on_size_request properly
272 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
273 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
275 trim_control.set_tooltip_prefix (_("Trim: "));
276 trim_control.set_name ("trim knob");
277 trim_control.set_no_show_all (true);
278 input_button_box.pack_start (trim_control, false, false);
280 global_vpacker.set_border_width (1);
281 global_vpacker.set_spacing (0);
283 width_button.set_name ("mixer strip button");
284 hide_button.set_name ("mixer strip button");
286 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
287 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
289 width_hide_box.set_spacing (2);
290 width_hide_box.pack_start (width_button, false, true);
291 width_hide_box.pack_start (number_label, true, true);
292 width_hide_box.pack_end (hide_button, false, true);
294 number_label.set_text ("-");
295 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
296 number_label.set_no_show_all ();
297 number_label.set_name ("tracknumber label");
298 number_label.set_fixed_colors (0x80808080, 0x80808080);
299 number_label.set_alignment (.5, .5);
300 number_label.set_fallthrough_to_parent (true);
301 number_label.set_tweaks (ArdourButton::OccasionalText);
303 global_vpacker.set_spacing (2);
304 if (!ARDOUR::Profile->get_trx()) {
305 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (processor_box, true, true);
311 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
318 if (!ARDOUR::Profile->get_trx()) {
319 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
320 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
322 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
325 global_frame.add (global_vpacker);
326 global_frame.set_shadow_type (Gtk::SHADOW_IN);
327 global_frame.set_name ("BaseFrame");
331 /* force setting of visible selected status */
334 set_selected (false);
339 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
340 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
342 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
343 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
344 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
346 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
347 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
349 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
350 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
351 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
353 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
355 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
357 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
361 /* start off as a passthru strip. we'll correct this, if necessary,
362 in update_diskstream_display().
365 /* start off as a passthru strip. we'll correct this, if necessary,
366 in update_diskstream_display().
369 if (is_midi_track()) {
370 set_name ("MidiTrackStripBase");
372 set_name ("AudioTrackStripBase");
375 add_events (Gdk::BUTTON_RELEASE_MASK|
376 Gdk::ENTER_NOTIFY_MASK|
377 Gdk::LEAVE_NOTIFY_MASK|
379 Gdk::KEY_RELEASE_MASK);
381 set_flags (get_flags() | Gtk::CAN_FOCUS);
383 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
384 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
387 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
388 must be the same as those used in RCOptionEditor so that the configuration changes
389 are recognised when they occur.
391 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
392 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
393 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
394 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
395 _visibility.add (&output_button, X_("Output"), _("Output"), false);
396 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
397 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
399 parameter_changed (X_("mixer-element-visibility"));
400 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
401 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
402 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
404 //watch for mouse enter/exit so we can do some stuff
405 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
406 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
408 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
411 MixerStrip::~MixerStrip ()
413 CatchDeletion (this);
415 if (this ==_entered_mixer_strip)
416 _entered_mixer_strip = NULL;
420 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
422 _entered_mixer_strip = this;
424 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
425 //because the mixerstrip control is a parent that encompasses the strip
426 deselect_all_processors();
432 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
434 //if we have moved outside our strip, but not into a child view, then deselect ourselves
435 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
436 _entered_mixer_strip= 0;
438 //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
439 gpm.gain_display.set_sensitive(false);
441 gpm.gain_display.set_sensitive(true);
443 //if we leave this mixer strip we need to clear out any selections
444 //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
451 MixerStrip::name() const
454 return _route->name();
460 MixerStrip::update_trim_control ()
462 if (route()->trim() && route()->trim()->active() &&
463 route()->n_inputs().n_audio() > 0) {
464 trim_control.show ();
465 trim_control.set_controllable (route()->trim()->gain_control());
467 trim_control.hide ();
468 boost::shared_ptr<Controllable> none;
469 trim_control.set_controllable (none);
474 MixerStrip::set_route (boost::shared_ptr<Route> rt)
476 //the rec/monitor stuff only shows up for tracks.
477 //the show_sends only shows up for buses.
478 //remove them all here, and we may add them back later
479 if (show_sends_button->get_parent()) {
480 rec_mon_table.remove (*show_sends_button);
482 if (rec_enable_button->get_parent()) {
483 rec_mon_table.remove (*rec_enable_button);
485 if (monitor_input_button->get_parent()) {
486 rec_mon_table.remove (*monitor_input_button);
488 if (monitor_disk_button->get_parent()) {
489 rec_mon_table.remove (*monitor_disk_button);
491 if (group_button.get_parent()) {
492 bottom_button_table.remove (group_button);
495 RouteUI::set_route (rt);
497 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
499 /* ProcessorBox needs access to _route so that it can read
502 processor_box.set_route (rt);
504 revert_to_default_display ();
506 /* unpack these from the parent and stuff them into our own
510 if (gpm.peak_display.get_parent()) {
511 gpm.peak_display.get_parent()->remove (gpm.peak_display);
513 if (gpm.gain_display.get_parent()) {
514 gpm.gain_display.get_parent()->remove (gpm.gain_display);
517 gpm.set_type (rt->meter_type());
519 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
520 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
522 if (solo_button->get_parent()) {
523 mute_solo_table.remove (*solo_button);
526 if (mute_button->get_parent()) {
527 mute_solo_table.remove (*mute_button);
530 if (route()->is_master()) {
531 solo_button->hide ();
532 mute_button->show ();
533 rec_mon_table.hide ();
534 if (solo_iso_table.get_parent()) {
535 solo_iso_table.get_parent()->remove(solo_iso_table);
537 if (monitor_section_button == 0) {
538 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
539 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
541 monitor_section_button = manage (new ArdourButton);
543 monitor_section_button->set_related_action (act);
544 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
545 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
546 monitor_section_button->show();
547 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
549 parameter_changed ("use-monitor-bus");
551 bottom_button_table.attach (group_button, 1, 2, 0, 1);
552 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
553 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
554 mute_button->show ();
555 solo_button->show ();
556 rec_mon_table.show ();
559 if (_mixer_owned && route()->is_master() ) {
561 HScrollbar scrollbar;
562 Gtk::Requisition requisition(scrollbar.size_request ());
563 int scrollbar_height = requisition.height;
565 spacer = manage (new EventBox);
566 spacer->set_size_request (-1, scrollbar_height+2);
567 global_vpacker.pack_start (*spacer, false, false);
572 monitor_input_button->show ();
573 monitor_disk_button->show ();
575 monitor_input_button->hide();
576 monitor_disk_button->hide ();
579 update_trim_control();
581 if (is_midi_track()) {
582 if (midi_input_enable_button == 0) {
583 midi_input_enable_button = manage (new ArdourButton);
584 midi_input_enable_button->set_name ("midi input button");
585 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
586 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
587 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
588 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
589 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
591 input_button_box.remove (*midi_input_enable_button);
593 /* get current state */
594 midi_input_status_changed ();
595 input_button_box.pack_start (*midi_input_enable_button, false, false);
597 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
599 if (midi_input_enable_button) {
600 /* removal from the container will delete it */
601 input_button_box.remove (*midi_input_enable_button);
602 midi_input_enable_button = 0;
606 if (is_audio_track()) {
607 boost::shared_ptr<AudioTrack> at = audio_track();
608 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
613 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
614 rec_enable_button->show();
616 if (ARDOUR::Profile->get_mixbus()) {
617 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
618 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
619 } else if (ARDOUR::Profile->get_trx()) {
620 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
622 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
623 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
630 if (!_route->is_master()) {
631 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
632 show_sends_button->show();
636 meter_point_button.set_text (meter_point_string (_route->meter_point()));
638 delete route_ops_menu;
641 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
642 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
643 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
644 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
646 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
648 if (_route->panner_shell()) {
649 update_panner_choices();
650 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
653 if (is_audio_track()) {
654 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
657 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
659 set_stuff_from_route ();
661 /* now force an update of all the various elements */
663 update_mute_display ();
664 update_solo_display ();
667 route_group_changed ();
668 update_track_number_visibility ();
671 panners.setup_pan ();
673 if (has_audio_outputs ()) {
679 update_diskstream_display ();
680 update_input_display ();
681 update_output_display ();
683 add_events (Gdk::BUTTON_RELEASE_MASK);
685 processor_box.show ();
687 if (!route()->is_master() && !route()->is_monitor()) {
688 /* we don't allow master or control routes to be hidden */
693 gpm.reset_peak_display ();
694 gpm.gain_display.show ();
695 gpm.peak_display.show ();
698 width_hide_box.show();
700 global_vpacker.show();
701 mute_solo_table.show();
702 bottom_button_table.show();
704 meter_point_button.show();
705 input_button_box.show_all();
706 output_button.show();
708 _comment_button.show();
710 gpm.gain_automation_state_button.show();
712 parameter_changed ("mixer-element-visibility");
719 MixerStrip::set_stuff_from_route ()
721 /* if width is not set, it will be set by the MixerUI or editor */
723 string str = gui_property ("strip-width");
725 set_width_enum (Width (string_2_enum (str, _width)), this);
730 MixerStrip::set_width_enum (Width w, void* owner)
732 /* always set the gpm width again, things may be hidden */
735 panners.set_width (w);
737 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
739 _width_owner = owner;
743 if (_width_owner == this) {
744 set_gui_property ("strip-width", enum_2_string (_width));
749 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
754 if (show_sends_button) {
755 show_sends_button->set_text (_("Aux"));
758 gpm.gain_automation_style_button.set_text (
759 gpm.astyle_string(gain_automation->automation_style()));
760 gpm.gain_automation_state_button.set_text (
761 gpm.astate_string(gain_automation->automation_state()));
763 if (_route->panner()) {
764 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
765 panners.astyle_string(_route->panner()->automation_style()));
766 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
767 panners.astate_string(_route->panner()->automation_state()));
771 // panners expect an even number of horiz. pixels
772 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
774 set_size_request (width, -1);
780 if (show_sends_button) {
781 show_sends_button->set_text (_("Snd"));
784 gpm.gain_automation_style_button.set_text (
785 gpm.short_astyle_string(gain_automation->automation_style()));
786 gpm.gain_automation_state_button.set_text (
787 gpm.short_astate_string(gain_automation->automation_state()));
788 gain_meter().setup_meters (); // recalc meter width
790 if (_route->panner()) {
791 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
792 panners.short_astyle_string(_route->panner()->automation_style()));
793 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
794 panners.short_astate_string(_route->panner()->automation_state()));
798 // panners expect an even number of horiz. pixels
799 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
801 set_size_request (width, -1);
806 processor_box.set_width (w);
808 update_input_display ();
809 update_output_display ();
810 setup_comment_button ();
811 route_group_changed ();
817 MixerStrip::set_packed (bool yn)
822 set_gui_property ("visible", true);
824 set_gui_property ("visible", false);
829 struct RouteCompareByName {
830 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
831 return a->name().compare (b->name()) < 0;
836 MixerStrip::output_release (GdkEventButton *ev)
838 switch (ev->button) {
840 edit_output_configuration ();
848 MixerStrip::output_press (GdkEventButton *ev)
850 using namespace Menu_Helpers;
851 if (!_session->engine().connected()) {
852 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
857 MenuList& citems = output_menu.items();
858 switch (ev->button) {
861 return false; //wait for the mouse-up to pop the dialog
865 output_menu.set_name ("ArdourContextMenu");
867 output_menu_bundles.clear ();
869 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
871 citems.push_back (SeparatorElem());
872 uint32_t const n_with_separator = citems.size ();
874 ARDOUR::BundleList current = _route->output()->bundles_connected ();
876 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
878 /* give user bundles first chance at being in the menu */
880 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
881 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
882 maybe_add_bundle_to_output_menu (*i, current);
886 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
887 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
888 maybe_add_bundle_to_output_menu (*i, current);
892 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
893 RouteList copy = *routes;
894 copy.sort (RouteCompareByName ());
895 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
896 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
899 if (citems.size() == n_with_separator) {
900 /* no routes added; remove the separator */
904 if (!ARDOUR::Profile->get_mixbus()) {
905 citems.push_back (SeparatorElem());
907 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
910 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
911 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
917 citems.push_back (SeparatorElem());
918 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
920 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
933 MixerStrip::input_release (GdkEventButton *ev)
935 switch (ev->button) {
938 edit_input_configuration ();
950 MixerStrip::input_press (GdkEventButton *ev)
952 using namespace Menu_Helpers;
954 MenuList& citems = input_menu.items();
955 input_menu.set_name ("ArdourContextMenu");
958 if (!_session->engine().connected()) {
959 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
964 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
967 switch (ev->button) {
970 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
974 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
976 citems.push_back (SeparatorElem());
977 uint32_t const n_with_separator = citems.size ();
979 input_menu_bundles.clear ();
981 ARDOUR::BundleList current = _route->input()->bundles_connected ();
983 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
985 /* give user bundles first chance at being in the menu */
987 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
988 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
989 maybe_add_bundle_to_input_menu (*i, current);
993 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
994 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
995 maybe_add_bundle_to_input_menu (*i, current);
999 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1000 RouteList copy = *routes;
1001 copy.sort (RouteCompareByName ());
1002 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1003 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1006 if (citems.size() == n_with_separator) {
1007 /* no routes added; remove the separator */
1011 citems.push_back (SeparatorElem());
1012 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1015 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1016 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1021 citems.push_back (SeparatorElem());
1022 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1024 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1036 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1038 if (ignore_toggle) {
1042 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1044 if (std::find (current.begin(), current.end(), c) == current.end()) {
1045 _route->input()->connect_ports_to_bundle (c, true, this);
1047 _route->input()->disconnect_ports_from_bundle (c, this);
1052 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1054 if (ignore_toggle) {
1058 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1060 if (std::find (current.begin(), current.end(), c) == current.end()) {
1061 _route->output()->connect_ports_to_bundle (c, true, this);
1063 _route->output()->disconnect_ports_from_bundle (c, this);
1068 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1070 using namespace Menu_Helpers;
1072 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1076 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1077 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1081 if (i != input_menu_bundles.end()) {
1085 input_menu_bundles.push_back (b);
1087 MenuList& citems = input_menu.items();
1089 std::string n = b->name ();
1090 replace_all (n, "_", " ");
1092 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1096 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1098 using namespace Menu_Helpers;
1100 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1104 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1105 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1109 if (i != output_menu_bundles.end()) {
1113 output_menu_bundles.push_back (b);
1115 MenuList& citems = output_menu.items();
1117 std::string n = b->name ();
1118 replace_all (n, "_", " ");
1120 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1124 MixerStrip::update_diskstream_display ()
1126 if (is_track() && input_selector) {
1127 input_selector->hide_all ();
1130 route_color_changed ();
1134 MixerStrip::connect_to_pan ()
1136 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1138 panstate_connection.disconnect ();
1139 panstyle_connection.disconnect ();
1141 if (!_route->panner()) {
1145 boost::shared_ptr<Pannable> p = _route->pannable ();
1147 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1148 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_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 name_button.modify_bg (STATE_NORMAL, color());
1624 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1625 reset_strip_style ();
1629 MixerStrip::show_passthru_color ()
1631 reset_strip_style ();
1636 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1638 boost::shared_ptr<Processor> processor (p.lock ());
1639 if (!processor || !processor->display_to_user()) {
1642 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1644 if (pi && pi->is_channelstrip ()) {
1649 ++_plugin_insert_cnt;
1653 MixerStrip::build_route_ops_menu ()
1655 using namespace Menu_Helpers;
1656 route_ops_menu = new Menu;
1657 route_ops_menu->set_name ("ArdourContextMenu");
1659 MenuList& items = route_ops_menu->items();
1661 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1663 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1665 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1667 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1669 items.push_back (SeparatorElem());
1671 if (!_route->is_master()) {
1672 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1674 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1675 rename_menu_item = &items.back();
1677 items.push_back (SeparatorElem());
1678 items.push_back (CheckMenuElem (_("Active")));
1679 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1680 i->set_active (_route->active());
1681 i->set_sensitive(! _session->transport_rolling());
1682 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1684 if (!Profile->get_mixbus ()) {
1685 items.push_back (SeparatorElem());
1686 items.push_back (CheckMenuElem (_("Strict I/O")));
1687 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1688 i->set_active (_route->strict_io());
1689 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1692 _plugin_insert_cnt = 0;
1693 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1694 if (_plugin_insert_cnt > 0) {
1695 items.push_back (SeparatorElem());
1696 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1699 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1700 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1701 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1702 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1705 items.push_back (SeparatorElem());
1706 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1708 items.push_back (SeparatorElem());
1709 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1710 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1711 denormal_menu_item->set_active (_route->denormal_protection());
1714 /* note that this relies on selection being shared across editor and
1715 mixer (or global to the backend, in the future), which is the only
1716 sane thing for users anyway.
1719 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1721 Selection& selection (PublicEditor::instance().get_selection());
1722 if (!selection.selected (rtav)) {
1723 selection.set (rtav);
1726 if (!_route->is_master()) {
1727 items.push_back (SeparatorElem());
1728 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1731 items.push_back (SeparatorElem());
1732 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1738 MixerStrip::name_button_button_press (GdkEventButton* ev)
1740 if (ev->button == 1 || ev->button == 3) {
1741 list_route_operations ();
1743 /* do not allow rename if the track is record-enabled */
1744 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1745 if (ev->button == 1) {
1746 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1749 route_ops_menu->popup (3, ev->time);
1759 MixerStrip::number_button_button_press (GdkEventButton* ev)
1761 if ( ev->button == 3 ) {
1762 list_route_operations ();
1764 /* do not allow rename if the track is record-enabled */
1765 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1766 route_ops_menu->popup (1, ev->time);
1775 MixerStrip::list_route_operations ()
1777 delete route_ops_menu;
1778 build_route_ops_menu ();
1782 MixerStrip::set_selected (bool yn)
1784 AxisView::set_selected (yn);
1787 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1788 global_frame.set_name ("MixerStripSelectedFrame");
1790 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1791 global_frame.set_name ("MixerStripFrame");
1794 global_frame.queue_draw ();
1797 // processor_box.deselect_all_processors();
1801 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1803 if (what_changed.contains (ARDOUR::Properties::name)) {
1809 MixerStrip::name_changed ()
1813 name_button.set_text (_route->name());
1816 name_button.set_text (PBD::short_version (_route->name(), 5));
1820 set_tooltip (name_button, _route->name());
1822 if (_session->config.get_track_name_number()) {
1823 const int64_t track_number = _route->track_number ();
1824 if (track_number == 0) {
1825 number_label.set_text ("-");
1827 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1830 number_label.set_text ("");
1835 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1837 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1841 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1843 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1847 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1849 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1853 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1855 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1859 MixerStrip::width_button_pressed (GdkEventButton* ev)
1861 if (ev->button != 1) {
1865 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1868 _mixer.set_strip_width (Narrow, true);
1872 _mixer.set_strip_width (Wide, true);
1878 set_width_enum (Narrow, this);
1881 set_width_enum (Wide, this);
1890 MixerStrip::hide_clicked ()
1892 // LAME fix to reset the button status for when it is redisplayed (part 1)
1893 hide_button.set_sensitive(false);
1896 Hiding(); /* EMIT_SIGNAL */
1898 _mixer.hide_strip (this);
1902 hide_button.set_sensitive(true);
1906 MixerStrip::set_embedded (bool yn)
1912 MixerStrip::map_frozen ()
1914 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1916 boost::shared_ptr<AudioTrack> at = audio_track();
1919 switch (at->freeze_state()) {
1920 case AudioTrack::Frozen:
1921 processor_box.set_sensitive (false);
1922 hide_redirect_editors ();
1925 processor_box.set_sensitive (true);
1926 // XXX need some way, maybe, to retoggle redirect editors
1930 processor_box.set_sensitive (true);
1932 RouteUI::map_frozen ();
1936 MixerStrip::hide_redirect_editors ()
1938 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1942 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1944 boost::shared_ptr<Processor> processor (p.lock ());
1949 Gtk::Window* w = processor_box.get_processor_ui (processor);
1957 MixerStrip::reset_strip_style ()
1959 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1961 gpm.set_fader_name ("SendStripBase");
1965 if (is_midi_track()) {
1966 if (_route->active()) {
1967 set_name ("MidiTrackStripBase");
1969 set_name ("MidiTrackStripBaseInactive");
1971 gpm.set_fader_name ("MidiTrackFader");
1972 } else if (is_audio_track()) {
1973 if (_route->active()) {
1974 set_name ("AudioTrackStripBase");
1976 set_name ("AudioTrackStripBaseInactive");
1978 gpm.set_fader_name ("AudioTrackFader");
1980 if (_route->active()) {
1981 set_name ("AudioBusStripBase");
1983 set_name ("AudioBusStripBaseInactive");
1985 gpm.set_fader_name ("AudioBusFader");
1987 /* (no MIDI busses yet) */
1994 MixerStrip::engine_stopped ()
1999 MixerStrip::engine_running ()
2004 MixerStrip::meter_point_string (MeterPoint mp)
2017 case MeterPostFader:
2034 return S_("Meter|In");
2038 return S_("Meter|Pr");
2041 case MeterPostFader:
2042 return S_("Meter|Po");
2046 return S_("Meter|O");
2051 return S_("Meter|C");
2060 /** Called when the monitor-section state */
2062 MixerStrip::monitor_changed ()
2064 assert (monitor_section_button);
2065 if (_session->monitor_active()) {
2066 monitor_section_button->set_name ("master monitor section button active");
2068 monitor_section_button->set_name ("master monitor section button normal");
2072 /** Called when the metering point has changed */
2074 MixerStrip::meter_changed ()
2076 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2077 gpm.setup_meters ();
2078 // reset peak when meter point changes
2079 gpm.reset_peak_display();
2082 /** The bus that we are displaying sends to has changed, or been turned off.
2083 * @param send_to New bus that we are displaying sends to, or 0.
2086 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2088 RouteUI::bus_send_display_changed (send_to);
2091 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2096 revert_to_default_display ();
2099 revert_to_default_display ();
2104 MixerStrip::drop_send ()
2106 boost::shared_ptr<Send> current_send;
2108 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2109 current_send->set_metering (false);
2112 send_gone_connection.disconnect ();
2113 input_button.set_sensitive (true);
2114 output_button.set_sensitive (true);
2115 group_button.set_sensitive (true);
2116 set_invert_sensitive (true);
2117 meter_point_button.set_sensitive (true);
2118 mute_button->set_sensitive (true);
2119 solo_button->set_sensitive (true);
2120 solo_isolated_led->set_sensitive (true);
2121 solo_safe_led->set_sensitive (true);
2122 monitor_input_button->set_sensitive (true);
2123 monitor_disk_button->set_sensitive (true);
2124 _comment_button.set_sensitive (true);
2125 RouteUI::check_rec_enable_sensitivity ();
2126 set_button_names (); // update solo button visual state
2130 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2132 _current_delivery = d;
2133 DeliveryChanged (_current_delivery);
2137 MixerStrip::show_send (boost::shared_ptr<Send> send)
2143 set_current_delivery (send);
2145 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2146 send->set_metering (true);
2147 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2149 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2150 gain_meter().setup_meters ();
2152 uint32_t const in = _current_delivery->pans_required();
2153 uint32_t const out = _current_delivery->pan_outs();
2155 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2156 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2157 panner_ui().setup_pan ();
2158 panner_ui().set_send_drawing_mode (true);
2159 panner_ui().show_all ();
2161 input_button.set_sensitive (false);
2162 group_button.set_sensitive (false);
2163 set_invert_sensitive (false);
2164 meter_point_button.set_sensitive (false);
2165 mute_button->set_sensitive (false);
2166 solo_button->set_sensitive (false);
2167 rec_enable_button->set_sensitive (false);
2168 solo_isolated_led->set_sensitive (false);
2169 solo_safe_led->set_sensitive (false);
2170 monitor_input_button->set_sensitive (false);
2171 monitor_disk_button->set_sensitive (false);
2172 _comment_button.set_sensitive (false);
2174 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2175 output_button.set_sensitive (false);
2178 reset_strip_style ();
2182 MixerStrip::revert_to_default_display ()
2186 set_current_delivery (_route->main_outs ());
2188 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2189 gain_meter().setup_meters ();
2191 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2192 update_panner_choices();
2193 panner_ui().setup_pan ();
2194 panner_ui().set_send_drawing_mode (false);
2196 if (has_audio_outputs ()) {
2197 panners.show_all ();
2199 panners.hide_all ();
2202 reset_strip_style ();
2206 MixerStrip::set_button_names ()
2210 mute_button->set_text (_("Mute"));
2211 monitor_input_button->set_text (_("In"));
2212 monitor_disk_button->set_text (_("Disk"));
2213 if (monitor_section_button) {
2214 monitor_section_button->set_text (_("Mon"));
2217 if (_route && _route->solo_safe_control()->solo_safe()) {
2218 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2220 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2222 if (!Config->get_solo_control_is_listen_control()) {
2223 solo_button->set_text (_("Solo"));
2225 switch (Config->get_listen_position()) {
2226 case AfterFaderListen:
2227 solo_button->set_text (_("AFL"));
2229 case PreFaderListen:
2230 solo_button->set_text (_("PFL"));
2234 solo_isolated_led->set_text (_("Iso"));
2235 solo_safe_led->set_text (S_("SoloLock|Lock"));
2239 mute_button->set_text (S_("Mute|M"));
2240 monitor_input_button->set_text (S_("MonitorInput|I"));
2241 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2242 if (monitor_section_button) {
2243 monitor_section_button->set_text (S_("Mon|O"));
2246 if (_route && _route->solo_safe_control()->solo_safe()) {
2247 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2249 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2251 if (!Config->get_solo_control_is_listen_control()) {
2252 solo_button->set_text (S_("Solo|S"));
2254 switch (Config->get_listen_position()) {
2255 case AfterFaderListen:
2256 solo_button->set_text (S_("AfterFader|A"));
2258 case PreFaderListen:
2259 solo_button->set_text (S_("Prefader|P"));
2264 solo_isolated_led->set_text (S_("SoloIso|I"));
2265 solo_safe_led->set_text (S_("SoloLock|L"));
2270 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2272 meter_point_button.set_text ("");
2277 MixerStrip::plugin_selector()
2279 return _mixer.plugin_selector();
2283 MixerStrip::hide_things ()
2285 processor_box.hide_things ();
2289 MixerStrip::input_active_button_press (GdkEventButton*)
2291 /* nothing happens on press */
2296 MixerStrip::input_active_button_release (GdkEventButton* ev)
2298 boost::shared_ptr<MidiTrack> mt = midi_track ();
2304 boost::shared_ptr<RouteList> rl (new RouteList);
2306 rl->push_back (route());
2308 _session->set_exclusive_input_active (rl, !mt->input_active(),
2309 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2315 MixerStrip::midi_input_status_changed ()
2317 if (midi_input_enable_button) {
2318 boost::shared_ptr<MidiTrack> mt = midi_track ();
2320 midi_input_enable_button->set_active (mt->input_active ());
2325 MixerStrip::state_id () const
2327 return string_compose ("strip %1", _route->id().to_s());
2331 MixerStrip::parameter_changed (string p)
2333 if (p == _visibility.get_state_name()) {
2334 /* The user has made changes to the mixer strip visibility, so get
2335 our VisibilityGroup to reflect these changes in our widgets.
2337 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2338 } else if (p == "track-name-number") {
2340 } else if (p == "use-monitor-bus") {
2341 if (monitor_section_button) {
2342 if (mute_button->get_parent()) {
2343 mute_button->get_parent()->remove(*mute_button);
2345 if (monitor_section_button->get_parent()) {
2346 monitor_section_button->get_parent()->remove(*monitor_section_button);
2348 if (Config->get_use_monitor_bus ()) {
2349 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2350 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2351 mute_button->show();
2352 monitor_section_button->show();
2354 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2355 mute_button->show();
2358 } else if (p == "track-name-number") {
2359 update_track_number_visibility();
2363 /** Called to decide whether the solo isolate / solo lock button visibility should
2364 * be overridden from that configured by the user. We do this for the master bus.
2366 * @return optional value that is present if visibility state should be overridden.
2368 boost::optional<bool>
2369 MixerStrip::override_solo_visibility () const
2371 if (_route && _route->is_master ()) {
2372 return boost::optional<bool> (false);
2375 return boost::optional<bool> ();
2379 MixerStrip::add_input_port (DataType t)
2381 _route->input()->add_port ("", this, t);
2385 MixerStrip::add_output_port (DataType t)
2387 _route->output()->add_port ("", this, t);
2391 MixerStrip::route_active_changed ()
2393 reset_strip_style ();
2397 MixerStrip::copy_processors ()
2399 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2403 MixerStrip::cut_processors ()
2405 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2409 MixerStrip::paste_processors ()
2411 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2415 MixerStrip::select_all_processors ()
2417 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2421 MixerStrip::deselect_all_processors ()
2423 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2427 MixerStrip::delete_processors ()
2429 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2433 MixerStrip::toggle_processors ()
2435 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2439 MixerStrip::ab_plugins ()
2441 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2445 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2447 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2450 if (ev->button == 3) {
2451 popup_level_meter_menu (ev);
2459 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2461 using namespace Gtk::Menu_Helpers;
2463 Gtk::Menu* m = manage (new Menu);
2464 MenuList& items = m->items ();
2466 RadioMenuItem::Group group;
2468 _suspend_menu_callbacks = true;
2469 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2470 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2471 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2472 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2473 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2475 if (gpm.meter_channels().n_audio() == 0) {
2476 m->popup (ev->button, ev->time);
2477 _suspend_menu_callbacks = false;
2481 RadioMenuItem::Group tgroup;
2482 items.push_back (SeparatorElem());
2484 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2485 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2486 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2487 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2488 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2489 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2490 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2491 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2492 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2493 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2494 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2497 if (_route->is_master()) {
2500 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2501 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2502 /* non-master bus */
2505 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2512 MeterType cmt = _route->meter_type();
2513 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2515 items.push_back (SeparatorElem());
2516 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2517 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2518 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2519 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2520 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2521 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2523 m->popup (ev->button, ev->time);
2524 _suspend_menu_callbacks = false;
2528 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2529 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2531 using namespace Menu_Helpers;
2533 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2534 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2535 i->set_active (_route->meter_point() == point);
2539 MixerStrip::set_meter_point (MeterPoint p)
2541 if (_suspend_menu_callbacks) return;
2542 _route->set_meter_point (p);
2546 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2547 RadioMenuItem::Group& group, string const & name, MeterType type)
2549 using namespace Menu_Helpers;
2551 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2552 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2553 i->set_active (_route->meter_type() == type);
2557 MixerStrip::set_meter_type (MeterType t)
2559 if (_suspend_menu_callbacks) return;
2564 MixerStrip::update_track_number_visibility ()
2566 DisplaySuspender ds;
2567 bool show_label = _session->config.get_track_name_number();
2569 if (_route && _route->is_master()) {
2574 number_label.show ();
2575 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2576 // except the width of the number label is subtracted from the name-hbox, so we
2577 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2578 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2580 number_label.set_size_request(tnw, -1);
2581 number_label.show ();
2583 number_label.hide ();
2588 MixerStrip::color () const
2590 return route_color ();
2594 MixerStrip::marked_for_display () const
2596 return !_route->presentation_info().hidden();
2600 MixerStrip::set_marked_for_display (bool yn)
2602 return RouteUI::mark_hidden (!yn);