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 items.push_back (SeparatorElem());
1700 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1702 items.push_back (SeparatorElem());
1703 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1704 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1705 denormal_menu_item->set_active (_route->denormal_protection());
1708 /* note that this relies on selection being shared across editor and
1709 mixer (or global to the backend, in the future), which is the only
1710 sane thing for users anyway.
1713 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1715 Selection& selection (PublicEditor::instance().get_selection());
1716 if (!selection.selected (rtav)) {
1717 selection.set (rtav);
1720 if (!_route->is_master()) {
1721 items.push_back (SeparatorElem());
1722 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1725 items.push_back (SeparatorElem());
1726 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1732 MixerStrip::name_button_button_press (GdkEventButton* ev)
1734 if (ev->button == 1 || ev->button == 3) {
1735 list_route_operations ();
1737 /* do not allow rename if the track is record-enabled */
1738 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1739 if (ev->button == 1) {
1740 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1743 route_ops_menu->popup (3, ev->time);
1753 MixerStrip::number_button_button_press (GdkEventButton* ev)
1755 if ( ev->button == 3 ) {
1756 list_route_operations ();
1758 /* do not allow rename if the track is record-enabled */
1759 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1760 route_ops_menu->popup (1, ev->time);
1769 MixerStrip::list_route_operations ()
1771 delete route_ops_menu;
1772 build_route_ops_menu ();
1776 MixerStrip::set_selected (bool yn)
1778 AxisView::set_selected (yn);
1781 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1782 global_frame.set_name ("MixerStripSelectedFrame");
1784 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1785 global_frame.set_name ("MixerStripFrame");
1788 global_frame.queue_draw ();
1791 // processor_box.deselect_all_processors();
1795 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1797 if (what_changed.contains (ARDOUR::Properties::name)) {
1803 MixerStrip::name_changed ()
1807 name_button.set_text (_route->name());
1810 name_button.set_text (PBD::short_version (_route->name(), 5));
1814 set_tooltip (name_button, _route->name());
1816 if (_session->config.get_track_name_number()) {
1817 const int64_t track_number = _route->track_number ();
1818 if (track_number == 0) {
1819 number_label.set_text ("-");
1821 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1824 number_label.set_text ("");
1829 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1831 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1835 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1837 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1841 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1843 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1847 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1849 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1853 MixerStrip::width_button_pressed (GdkEventButton* ev)
1855 if (ev->button != 1) {
1859 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1862 _mixer.set_strip_width (Narrow, true);
1866 _mixer.set_strip_width (Wide, true);
1872 set_width_enum (Narrow, this);
1875 set_width_enum (Wide, this);
1884 MixerStrip::hide_clicked ()
1886 // LAME fix to reset the button status for when it is redisplayed (part 1)
1887 hide_button.set_sensitive(false);
1890 Hiding(); /* EMIT_SIGNAL */
1892 _mixer.hide_strip (this);
1896 hide_button.set_sensitive(true);
1900 MixerStrip::set_embedded (bool yn)
1906 MixerStrip::map_frozen ()
1908 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1910 boost::shared_ptr<AudioTrack> at = audio_track();
1913 switch (at->freeze_state()) {
1914 case AudioTrack::Frozen:
1915 processor_box.set_sensitive (false);
1916 hide_redirect_editors ();
1919 processor_box.set_sensitive (true);
1920 // XXX need some way, maybe, to retoggle redirect editors
1924 processor_box.set_sensitive (true);
1926 RouteUI::map_frozen ();
1930 MixerStrip::hide_redirect_editors ()
1932 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1936 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1938 boost::shared_ptr<Processor> processor (p.lock ());
1943 Gtk::Window* w = processor_box.get_processor_ui (processor);
1951 MixerStrip::reset_strip_style ()
1953 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1955 gpm.set_fader_name ("SendStripBase");
1959 if (is_midi_track()) {
1960 if (_route->active()) {
1961 set_name ("MidiTrackStripBase");
1963 set_name ("MidiTrackStripBaseInactive");
1965 gpm.set_fader_name ("MidiTrackFader");
1966 } else if (is_audio_track()) {
1967 if (_route->active()) {
1968 set_name ("AudioTrackStripBase");
1970 set_name ("AudioTrackStripBaseInactive");
1972 gpm.set_fader_name ("AudioTrackFader");
1974 if (_route->active()) {
1975 set_name ("AudioBusStripBase");
1977 set_name ("AudioBusStripBaseInactive");
1979 gpm.set_fader_name ("AudioBusFader");
1981 /* (no MIDI busses yet) */
1988 MixerStrip::engine_stopped ()
1993 MixerStrip::engine_running ()
1998 MixerStrip::meter_point_string (MeterPoint mp)
2011 case MeterPostFader:
2028 return S_("Meter|In");
2032 return S_("Meter|Pr");
2035 case MeterPostFader:
2036 return S_("Meter|Po");
2040 return S_("Meter|O");
2045 return S_("Meter|C");
2054 /** Called when the monitor-section state */
2056 MixerStrip::monitor_changed ()
2058 assert (monitor_section_button);
2059 if (_session->monitor_active()) {
2060 monitor_section_button->set_name ("master monitor section button active");
2062 monitor_section_button->set_name ("master monitor section button normal");
2066 /** Called when the metering point has changed */
2068 MixerStrip::meter_changed ()
2070 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2071 gpm.setup_meters ();
2072 // reset peak when meter point changes
2073 gpm.reset_peak_display();
2076 /** The bus that we are displaying sends to has changed, or been turned off.
2077 * @param send_to New bus that we are displaying sends to, or 0.
2080 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2082 RouteUI::bus_send_display_changed (send_to);
2085 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2090 revert_to_default_display ();
2093 revert_to_default_display ();
2098 MixerStrip::drop_send ()
2100 boost::shared_ptr<Send> current_send;
2102 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2103 current_send->set_metering (false);
2106 send_gone_connection.disconnect ();
2107 input_button.set_sensitive (true);
2108 output_button.set_sensitive (true);
2109 group_button.set_sensitive (true);
2110 set_invert_sensitive (true);
2111 meter_point_button.set_sensitive (true);
2112 mute_button->set_sensitive (true);
2113 solo_button->set_sensitive (true);
2114 solo_isolated_led->set_sensitive (true);
2115 solo_safe_led->set_sensitive (true);
2116 monitor_input_button->set_sensitive (true);
2117 monitor_disk_button->set_sensitive (true);
2118 _comment_button.set_sensitive (true);
2119 RouteUI::check_rec_enable_sensitivity ();
2120 set_button_names (); // update solo button visual state
2124 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2126 _current_delivery = d;
2127 DeliveryChanged (_current_delivery);
2131 MixerStrip::show_send (boost::shared_ptr<Send> send)
2137 set_current_delivery (send);
2139 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2140 send->set_metering (true);
2141 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2143 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2144 gain_meter().setup_meters ();
2146 uint32_t const in = _current_delivery->pans_required();
2147 uint32_t const out = _current_delivery->pan_outs();
2149 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2150 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2151 panner_ui().setup_pan ();
2152 panner_ui().set_send_drawing_mode (true);
2153 panner_ui().show_all ();
2155 input_button.set_sensitive (false);
2156 group_button.set_sensitive (false);
2157 set_invert_sensitive (false);
2158 meter_point_button.set_sensitive (false);
2159 mute_button->set_sensitive (false);
2160 solo_button->set_sensitive (false);
2161 rec_enable_button->set_sensitive (false);
2162 solo_isolated_led->set_sensitive (false);
2163 solo_safe_led->set_sensitive (false);
2164 monitor_input_button->set_sensitive (false);
2165 monitor_disk_button->set_sensitive (false);
2166 _comment_button.set_sensitive (false);
2168 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2169 output_button.set_sensitive (false);
2172 reset_strip_style ();
2176 MixerStrip::revert_to_default_display ()
2180 set_current_delivery (_route->main_outs ());
2182 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2183 gain_meter().setup_meters ();
2185 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2186 update_panner_choices();
2187 panner_ui().setup_pan ();
2188 panner_ui().set_send_drawing_mode (false);
2190 if (has_audio_outputs ()) {
2191 panners.show_all ();
2193 panners.hide_all ();
2196 reset_strip_style ();
2200 MixerStrip::set_button_names ()
2204 mute_button->set_text (_("Mute"));
2205 monitor_input_button->set_text (_("In"));
2206 monitor_disk_button->set_text (_("Disk"));
2207 if (monitor_section_button) {
2208 monitor_section_button->set_text (_("Mon"));
2211 if (_route && _route->solo_safe_control()->solo_safe()) {
2212 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2214 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2216 if (!Config->get_solo_control_is_listen_control()) {
2217 solo_button->set_text (_("Solo"));
2219 switch (Config->get_listen_position()) {
2220 case AfterFaderListen:
2221 solo_button->set_text (_("AFL"));
2223 case PreFaderListen:
2224 solo_button->set_text (_("PFL"));
2228 solo_isolated_led->set_text (_("Iso"));
2229 solo_safe_led->set_text (S_("SoloLock|Lock"));
2233 mute_button->set_text (S_("Mute|M"));
2234 monitor_input_button->set_text (S_("MonitorInput|I"));
2235 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2236 if (monitor_section_button) {
2237 monitor_section_button->set_text (S_("Mon|O"));
2240 if (_route && _route->solo_safe_control()->solo_safe()) {
2241 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2243 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2245 if (!Config->get_solo_control_is_listen_control()) {
2246 solo_button->set_text (S_("Solo|S"));
2248 switch (Config->get_listen_position()) {
2249 case AfterFaderListen:
2250 solo_button->set_text (S_("AfterFader|A"));
2252 case PreFaderListen:
2253 solo_button->set_text (S_("Prefader|P"));
2258 solo_isolated_led->set_text (S_("SoloIso|I"));
2259 solo_safe_led->set_text (S_("SoloLock|L"));
2264 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2266 meter_point_button.set_text ("");
2271 MixerStrip::plugin_selector()
2273 return _mixer.plugin_selector();
2277 MixerStrip::hide_things ()
2279 processor_box.hide_things ();
2283 MixerStrip::input_active_button_press (GdkEventButton*)
2285 /* nothing happens on press */
2290 MixerStrip::input_active_button_release (GdkEventButton* ev)
2292 boost::shared_ptr<MidiTrack> mt = midi_track ();
2298 boost::shared_ptr<RouteList> rl (new RouteList);
2300 rl->push_back (route());
2302 _session->set_exclusive_input_active (rl, !mt->input_active(),
2303 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2309 MixerStrip::midi_input_status_changed ()
2311 if (midi_input_enable_button) {
2312 boost::shared_ptr<MidiTrack> mt = midi_track ();
2314 midi_input_enable_button->set_active (mt->input_active ());
2319 MixerStrip::state_id () const
2321 return string_compose ("strip %1", _route->id().to_s());
2325 MixerStrip::parameter_changed (string p)
2327 if (p == _visibility.get_state_name()) {
2328 /* The user has made changes to the mixer strip visibility, so get
2329 our VisibilityGroup to reflect these changes in our widgets.
2331 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2332 } else if (p == "track-name-number") {
2334 } else if (p == "use-monitor-bus") {
2335 if (monitor_section_button) {
2336 if (mute_button->get_parent()) {
2337 mute_button->get_parent()->remove(*mute_button);
2339 if (monitor_section_button->get_parent()) {
2340 monitor_section_button->get_parent()->remove(*monitor_section_button);
2342 if (Config->get_use_monitor_bus ()) {
2343 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2344 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2345 mute_button->show();
2346 monitor_section_button->show();
2348 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2349 mute_button->show();
2352 } else if (p == "track-name-number") {
2353 update_track_number_visibility();
2357 /** Called to decide whether the solo isolate / solo lock button visibility should
2358 * be overridden from that configured by the user. We do this for the master bus.
2360 * @return optional value that is present if visibility state should be overridden.
2362 boost::optional<bool>
2363 MixerStrip::override_solo_visibility () const
2365 if (_route && _route->is_master ()) {
2366 return boost::optional<bool> (false);
2369 return boost::optional<bool> ();
2373 MixerStrip::add_input_port (DataType t)
2375 _route->input()->add_port ("", this, t);
2379 MixerStrip::add_output_port (DataType t)
2381 _route->output()->add_port ("", this, t);
2385 MixerStrip::route_active_changed ()
2387 reset_strip_style ();
2391 MixerStrip::copy_processors ()
2393 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2397 MixerStrip::cut_processors ()
2399 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2403 MixerStrip::paste_processors ()
2405 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2409 MixerStrip::select_all_processors ()
2411 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2415 MixerStrip::deselect_all_processors ()
2417 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2421 MixerStrip::delete_processors ()
2423 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2427 MixerStrip::toggle_processors ()
2429 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2433 MixerStrip::ab_plugins ()
2435 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2439 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2441 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2444 if (ev->button == 3) {
2445 popup_level_meter_menu (ev);
2453 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2455 using namespace Gtk::Menu_Helpers;
2457 Gtk::Menu* m = manage (new Menu);
2458 MenuList& items = m->items ();
2460 RadioMenuItem::Group group;
2462 _suspend_menu_callbacks = true;
2463 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2464 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2465 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2466 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2467 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2469 if (gpm.meter_channels().n_audio() == 0) {
2470 m->popup (ev->button, ev->time);
2471 _suspend_menu_callbacks = false;
2475 RadioMenuItem::Group tgroup;
2476 items.push_back (SeparatorElem());
2478 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2479 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2480 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2481 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2482 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2483 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2484 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2485 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2486 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2487 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2488 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2491 if (_route->is_master()) {
2494 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2495 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2496 /* non-master bus */
2499 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2506 MeterType cmt = _route->meter_type();
2507 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2509 items.push_back (SeparatorElem());
2510 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2511 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2512 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2513 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2514 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2515 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2517 m->popup (ev->button, ev->time);
2518 _suspend_menu_callbacks = false;
2522 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2523 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2525 using namespace Menu_Helpers;
2527 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2528 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2529 i->set_active (_route->meter_point() == point);
2533 MixerStrip::set_meter_point (MeterPoint p)
2535 if (_suspend_menu_callbacks) return;
2536 _route->set_meter_point (p);
2540 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2541 RadioMenuItem::Group& group, string const & name, MeterType type)
2543 using namespace Menu_Helpers;
2545 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2546 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2547 i->set_active (_route->meter_type() == type);
2551 MixerStrip::set_meter_type (MeterType t)
2553 if (_suspend_menu_callbacks) return;
2558 MixerStrip::update_track_number_visibility ()
2560 DisplaySuspender ds;
2561 bool show_label = _session->config.get_track_name_number();
2563 if (_route && _route->is_master()) {
2568 number_label.show ();
2569 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2570 // except the width of the number label is subtracted from the name-hbox, so we
2571 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2572 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2574 number_label.set_size_request(tnw, -1);
2575 number_label.show ();
2577 number_label.hide ();
2582 MixerStrip::color () const
2584 return route_color ();
2588 MixerStrip::marked_for_display () const
2590 return !_route->presentation_info().hidden();
2594 MixerStrip::set_marked_for_display (bool yn)
2596 return RouteUI::mark_hidden (!yn);