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 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1643 ++_plugin_insert_cnt;
1647 MixerStrip::build_route_ops_menu ()
1649 using namespace Menu_Helpers;
1650 route_ops_menu = new Menu;
1651 route_ops_menu->set_name ("ArdourContextMenu");
1653 MenuList& items = route_ops_menu->items();
1655 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1657 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1659 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1661 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1663 items.push_back (SeparatorElem());
1665 if (!_route->is_master()) {
1666 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1668 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1669 rename_menu_item = &items.back();
1671 items.push_back (SeparatorElem());
1672 items.push_back (CheckMenuElem (_("Active")));
1673 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1674 i->set_active (_route->active());
1675 i->set_sensitive(! _session->transport_rolling());
1676 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1678 if (!Profile->get_mixbus ()) {
1679 items.push_back (SeparatorElem());
1680 items.push_back (CheckMenuElem (_("Strict I/O")));
1681 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1682 i->set_active (_route->strict_io());
1683 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1686 _plugin_insert_cnt = 0;
1687 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1688 if (_plugin_insert_cnt > 0) {
1689 items.push_back (SeparatorElem());
1690 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1693 items.push_back (SeparatorElem());
1694 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1696 items.push_back (SeparatorElem());
1697 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1698 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1699 denormal_menu_item->set_active (_route->denormal_protection());
1702 /* note that this relies on selection being shared across editor and
1703 mixer (or global to the backend, in the future), which is the only
1704 sane thing for users anyway.
1707 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1709 Selection& selection (PublicEditor::instance().get_selection());
1710 if (!selection.selected (rtav)) {
1711 selection.set (rtav);
1714 if (!_route->is_master()) {
1715 items.push_back (SeparatorElem());
1716 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1719 items.push_back (SeparatorElem());
1720 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1726 MixerStrip::name_button_button_press (GdkEventButton* ev)
1728 if (ev->button == 1 || ev->button == 3) {
1729 list_route_operations ();
1731 /* do not allow rename if the track is record-enabled */
1732 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1733 if (ev->button == 1) {
1734 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1737 route_ops_menu->popup (3, ev->time);
1747 MixerStrip::number_button_button_press (GdkEventButton* ev)
1749 if ( ev->button == 3 ) {
1750 list_route_operations ();
1752 /* do not allow rename if the track is record-enabled */
1753 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1754 route_ops_menu->popup (1, ev->time);
1763 MixerStrip::list_route_operations ()
1765 delete route_ops_menu;
1766 build_route_ops_menu ();
1770 MixerStrip::set_selected (bool yn)
1772 AxisView::set_selected (yn);
1775 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1776 global_frame.set_name ("MixerStripSelectedFrame");
1778 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1779 global_frame.set_name ("MixerStripFrame");
1782 global_frame.queue_draw ();
1785 // processor_box.deselect_all_processors();
1789 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1791 if (what_changed.contains (ARDOUR::Properties::name)) {
1797 MixerStrip::name_changed ()
1801 name_button.set_text (_route->name());
1804 name_button.set_text (PBD::short_version (_route->name(), 5));
1808 set_tooltip (name_button, _route->name());
1810 if (_session->config.get_track_name_number()) {
1811 const int64_t track_number = _route->track_number ();
1812 if (track_number == 0) {
1813 number_label.set_text ("-");
1815 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1818 number_label.set_text ("");
1823 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1825 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1829 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1831 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1835 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1837 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1841 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1843 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1847 MixerStrip::width_button_pressed (GdkEventButton* ev)
1849 if (ev->button != 1) {
1853 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1856 _mixer.set_strip_width (Narrow, true);
1860 _mixer.set_strip_width (Wide, true);
1866 set_width_enum (Narrow, this);
1869 set_width_enum (Wide, this);
1878 MixerStrip::hide_clicked ()
1880 // LAME fix to reset the button status for when it is redisplayed (part 1)
1881 hide_button.set_sensitive(false);
1884 Hiding(); /* EMIT_SIGNAL */
1886 _mixer.hide_strip (this);
1890 hide_button.set_sensitive(true);
1894 MixerStrip::set_embedded (bool yn)
1900 MixerStrip::map_frozen ()
1902 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1904 boost::shared_ptr<AudioTrack> at = audio_track();
1907 switch (at->freeze_state()) {
1908 case AudioTrack::Frozen:
1909 processor_box.set_sensitive (false);
1910 hide_redirect_editors ();
1913 processor_box.set_sensitive (true);
1914 // XXX need some way, maybe, to retoggle redirect editors
1918 processor_box.set_sensitive (true);
1920 RouteUI::map_frozen ();
1924 MixerStrip::hide_redirect_editors ()
1926 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1930 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1932 boost::shared_ptr<Processor> processor (p.lock ());
1937 Gtk::Window* w = processor_box.get_processor_ui (processor);
1945 MixerStrip::reset_strip_style ()
1947 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1949 gpm.set_fader_name ("SendStripBase");
1953 if (is_midi_track()) {
1954 if (_route->active()) {
1955 set_name ("MidiTrackStripBase");
1957 set_name ("MidiTrackStripBaseInactive");
1959 gpm.set_fader_name ("MidiTrackFader");
1960 } else if (is_audio_track()) {
1961 if (_route->active()) {
1962 set_name ("AudioTrackStripBase");
1964 set_name ("AudioTrackStripBaseInactive");
1966 gpm.set_fader_name ("AudioTrackFader");
1968 if (_route->active()) {
1969 set_name ("AudioBusStripBase");
1971 set_name ("AudioBusStripBaseInactive");
1973 gpm.set_fader_name ("AudioBusFader");
1975 /* (no MIDI busses yet) */
1982 MixerStrip::engine_stopped ()
1987 MixerStrip::engine_running ()
1992 MixerStrip::meter_point_string (MeterPoint mp)
2005 case MeterPostFader:
2022 return S_("Meter|In");
2026 return S_("Meter|Pr");
2029 case MeterPostFader:
2030 return S_("Meter|Po");
2034 return S_("Meter|O");
2039 return S_("Meter|C");
2048 /** Called when the monitor-section state */
2050 MixerStrip::monitor_changed ()
2052 assert (monitor_section_button);
2053 if (_session->monitor_active()) {
2054 monitor_section_button->set_name ("master monitor section button active");
2056 monitor_section_button->set_name ("master monitor section button normal");
2060 /** Called when the metering point has changed */
2062 MixerStrip::meter_changed ()
2064 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2065 gpm.setup_meters ();
2066 // reset peak when meter point changes
2067 gpm.reset_peak_display();
2070 /** The bus that we are displaying sends to has changed, or been turned off.
2071 * @param send_to New bus that we are displaying sends to, or 0.
2074 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2076 RouteUI::bus_send_display_changed (send_to);
2079 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2084 revert_to_default_display ();
2087 revert_to_default_display ();
2092 MixerStrip::drop_send ()
2094 boost::shared_ptr<Send> current_send;
2096 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2097 current_send->set_metering (false);
2100 send_gone_connection.disconnect ();
2101 input_button.set_sensitive (true);
2102 output_button.set_sensitive (true);
2103 group_button.set_sensitive (true);
2104 set_invert_sensitive (true);
2105 meter_point_button.set_sensitive (true);
2106 mute_button->set_sensitive (true);
2107 solo_button->set_sensitive (true);
2108 solo_isolated_led->set_sensitive (true);
2109 solo_safe_led->set_sensitive (true);
2110 monitor_input_button->set_sensitive (true);
2111 monitor_disk_button->set_sensitive (true);
2112 _comment_button.set_sensitive (true);
2113 RouteUI::check_rec_enable_sensitivity ();
2114 set_button_names (); // update solo button visual state
2118 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2120 _current_delivery = d;
2121 DeliveryChanged (_current_delivery);
2125 MixerStrip::show_send (boost::shared_ptr<Send> send)
2131 set_current_delivery (send);
2133 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2134 send->set_metering (true);
2135 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2137 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2138 gain_meter().setup_meters ();
2140 uint32_t const in = _current_delivery->pans_required();
2141 uint32_t const out = _current_delivery->pan_outs();
2143 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2144 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2145 panner_ui().setup_pan ();
2146 panner_ui().set_send_drawing_mode (true);
2147 panner_ui().show_all ();
2149 input_button.set_sensitive (false);
2150 group_button.set_sensitive (false);
2151 set_invert_sensitive (false);
2152 meter_point_button.set_sensitive (false);
2153 mute_button->set_sensitive (false);
2154 solo_button->set_sensitive (false);
2155 rec_enable_button->set_sensitive (false);
2156 solo_isolated_led->set_sensitive (false);
2157 solo_safe_led->set_sensitive (false);
2158 monitor_input_button->set_sensitive (false);
2159 monitor_disk_button->set_sensitive (false);
2160 _comment_button.set_sensitive (false);
2162 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2163 output_button.set_sensitive (false);
2166 reset_strip_style ();
2170 MixerStrip::revert_to_default_display ()
2174 set_current_delivery (_route->main_outs ());
2176 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2177 gain_meter().setup_meters ();
2179 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2180 update_panner_choices();
2181 panner_ui().setup_pan ();
2182 panner_ui().set_send_drawing_mode (false);
2184 if (has_audio_outputs ()) {
2185 panners.show_all ();
2187 panners.hide_all ();
2190 reset_strip_style ();
2194 MixerStrip::set_button_names ()
2198 mute_button->set_text (_("Mute"));
2199 monitor_input_button->set_text (_("In"));
2200 monitor_disk_button->set_text (_("Disk"));
2201 if (monitor_section_button) {
2202 monitor_section_button->set_text (_("Mon"));
2205 if (_route && _route->solo_safe_control()->solo_safe()) {
2206 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2208 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2210 if (!Config->get_solo_control_is_listen_control()) {
2211 solo_button->set_text (_("Solo"));
2213 switch (Config->get_listen_position()) {
2214 case AfterFaderListen:
2215 solo_button->set_text (_("AFL"));
2217 case PreFaderListen:
2218 solo_button->set_text (_("PFL"));
2222 solo_isolated_led->set_text (_("Iso"));
2223 solo_safe_led->set_text (S_("SoloLock|Lock"));
2227 mute_button->set_text (S_("Mute|M"));
2228 monitor_input_button->set_text (S_("MonitorInput|I"));
2229 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2230 if (monitor_section_button) {
2231 monitor_section_button->set_text (S_("Mon|O"));
2234 if (_route && _route->solo_safe_control()->solo_safe()) {
2235 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2237 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2239 if (!Config->get_solo_control_is_listen_control()) {
2240 solo_button->set_text (S_("Solo|S"));
2242 switch (Config->get_listen_position()) {
2243 case AfterFaderListen:
2244 solo_button->set_text (S_("AfterFader|A"));
2246 case PreFaderListen:
2247 solo_button->set_text (S_("Prefader|P"));
2252 solo_isolated_led->set_text (S_("SoloIso|I"));
2253 solo_safe_led->set_text (S_("SoloLock|L"));
2258 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2260 meter_point_button.set_text ("");
2265 MixerStrip::plugin_selector()
2267 return _mixer.plugin_selector();
2271 MixerStrip::hide_things ()
2273 processor_box.hide_things ();
2277 MixerStrip::input_active_button_press (GdkEventButton*)
2279 /* nothing happens on press */
2284 MixerStrip::input_active_button_release (GdkEventButton* ev)
2286 boost::shared_ptr<MidiTrack> mt = midi_track ();
2292 boost::shared_ptr<RouteList> rl (new RouteList);
2294 rl->push_back (route());
2296 _session->set_exclusive_input_active (rl, !mt->input_active(),
2297 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2303 MixerStrip::midi_input_status_changed ()
2305 if (midi_input_enable_button) {
2306 boost::shared_ptr<MidiTrack> mt = midi_track ();
2308 midi_input_enable_button->set_active (mt->input_active ());
2313 MixerStrip::state_id () const
2315 return string_compose ("strip %1", _route->id().to_s());
2319 MixerStrip::parameter_changed (string p)
2321 if (p == _visibility.get_state_name()) {
2322 /* The user has made changes to the mixer strip visibility, so get
2323 our VisibilityGroup to reflect these changes in our widgets.
2325 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2326 } else if (p == "track-name-number") {
2328 } else if (p == "use-monitor-bus") {
2329 if (monitor_section_button) {
2330 if (mute_button->get_parent()) {
2331 mute_button->get_parent()->remove(*mute_button);
2333 if (monitor_section_button->get_parent()) {
2334 monitor_section_button->get_parent()->remove(*monitor_section_button);
2336 if (Config->get_use_monitor_bus ()) {
2337 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2338 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2339 mute_button->show();
2340 monitor_section_button->show();
2342 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2343 mute_button->show();
2346 } else if (p == "track-name-number") {
2347 update_track_number_visibility();
2351 /** Called to decide whether the solo isolate / solo lock button visibility should
2352 * be overridden from that configured by the user. We do this for the master bus.
2354 * @return optional value that is present if visibility state should be overridden.
2356 boost::optional<bool>
2357 MixerStrip::override_solo_visibility () const
2359 if (_route && _route->is_master ()) {
2360 return boost::optional<bool> (false);
2363 return boost::optional<bool> ();
2367 MixerStrip::add_input_port (DataType t)
2369 _route->input()->add_port ("", this, t);
2373 MixerStrip::add_output_port (DataType t)
2375 _route->output()->add_port ("", this, t);
2379 MixerStrip::route_active_changed ()
2381 reset_strip_style ();
2385 MixerStrip::copy_processors ()
2387 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2391 MixerStrip::cut_processors ()
2393 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2397 MixerStrip::paste_processors ()
2399 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2403 MixerStrip::select_all_processors ()
2405 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2409 MixerStrip::deselect_all_processors ()
2411 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2415 MixerStrip::delete_processors ()
2417 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2421 MixerStrip::toggle_processors ()
2423 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2427 MixerStrip::ab_plugins ()
2429 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2433 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2435 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2438 if (ev->button == 3) {
2439 popup_level_meter_menu (ev);
2447 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2449 using namespace Gtk::Menu_Helpers;
2451 Gtk::Menu* m = manage (new Menu);
2452 MenuList& items = m->items ();
2454 RadioMenuItem::Group group;
2456 _suspend_menu_callbacks = true;
2457 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2458 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2459 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2460 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2461 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2463 if (gpm.meter_channels().n_audio() == 0) {
2464 m->popup (ev->button, ev->time);
2465 _suspend_menu_callbacks = false;
2469 RadioMenuItem::Group tgroup;
2470 items.push_back (SeparatorElem());
2472 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2473 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2474 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2475 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2476 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2477 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2478 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2479 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2480 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2481 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2482 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2485 if (_route->is_master()) {
2488 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2489 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2490 /* non-master bus */
2493 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2500 MeterType cmt = _route->meter_type();
2501 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2503 items.push_back (SeparatorElem());
2504 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2505 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2506 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2507 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2508 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2509 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2511 m->popup (ev->button, ev->time);
2512 _suspend_menu_callbacks = false;
2516 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2517 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2519 using namespace Menu_Helpers;
2521 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2522 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2523 i->set_active (_route->meter_point() == point);
2527 MixerStrip::set_meter_point (MeterPoint p)
2529 if (_suspend_menu_callbacks) return;
2530 _route->set_meter_point (p);
2534 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2535 RadioMenuItem::Group& group, string const & name, MeterType type)
2537 using namespace Menu_Helpers;
2539 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2540 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2541 i->set_active (_route->meter_type() == type);
2545 MixerStrip::set_meter_type (MeterType t)
2547 if (_suspend_menu_callbacks) return;
2552 MixerStrip::update_track_number_visibility ()
2554 DisplaySuspender ds;
2555 bool show_label = _session->config.get_track_name_number();
2557 if (_route && _route->is_master()) {
2562 number_label.show ();
2563 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2564 // except the width of the number label is subtracted from the name-hbox, so we
2565 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2566 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2568 number_label.set_size_request(tnw, -1);
2569 number_label.show ();
2571 number_label.hide ();
2576 MixerStrip::color () const
2578 return route_color ();
2582 MixerStrip::marked_for_display () const
2584 return !_route->presentation_info().hidden();
2588 MixerStrip::set_marked_for_display (bool yn)
2590 return RouteUI::mark_hidden (!yn);