2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <sigc++/bind.h>
25 #include "pbd/convert.h"
26 #include "pbd/enumwriter.h"
27 #include "pbd/replace_all.h"
28 #include "pbd/stacktrace.h"
30 #include <gtkmm2ext/gtk_ui.h>
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/choice.h>
33 #include <gtkmm2ext/doi.h>
34 #include <gtkmm2ext/slider_controller.h>
35 #include <gtkmm2ext/bindable_button.h>
37 #include "ardour/amp.h"
38 #include "ardour/audio_track.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/internal_send.h"
41 #include "ardour/io.h"
42 #include "ardour/meter.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/pannable.h"
45 #include "ardour/panner.h"
46 #include "ardour/panner_shell.h"
47 #include "ardour/panner_manager.h"
48 #include "ardour/port.h"
49 #include "ardour/profile.h"
50 #include "ardour/route.h"
51 #include "ardour/route_group.h"
52 #include "ardour/send.h"
53 #include "ardour/session.h"
54 #include "ardour/types.h"
55 #include "ardour/user_bundle.h"
56 #include "ardour/vca.h"
57 #include "ardour/vca_manager.h"
59 #include "ardour_window.h"
60 #include "mixer_strip.h"
63 #include "ardour_button.h"
64 #include "public_editor.h"
66 #include "io_selector.h"
68 #include "gui_thread.h"
69 #include "route_group_menu.h"
70 #include "meter_patterns.h"
72 #include "ui_config.h"
76 using namespace ARDOUR;
77 using namespace ARDOUR_UI_UTILS;
80 using namespace Gtkmm2ext;
82 using namespace ArdourMeter;
84 MixerStrip* MixerStrip::_entered_mixer_strip;
85 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
87 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
88 : SessionHandlePtr (sess)
91 , _mixer_owned (in_mixer)
92 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
95 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
96 , rec_mon_table (2, 2)
97 , solo_iso_table (1, 2)
98 , mute_solo_table (1, 2)
99 , bottom_button_table (1, 3)
100 , meter_point_button (_("pre"))
101 , monitor_section_button (0)
102 , midi_input_enable_button (0)
103 , _plugin_insert_cnt (0)
104 , _comment_button (_("Comments"))
105 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
106 , _visibility (X_("mixer-element-visibility"))
107 , control_slave_ui (sess)
112 /* the editor mixer strip: don't destroy it every time
113 the underlying route goes away.
116 self_destruct = false;
120 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
121 : SessionHandlePtr (sess)
124 , _mixer_owned (in_mixer)
125 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
128 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
129 , rec_mon_table (2, 2)
130 , solo_iso_table (1, 2)
131 , mute_solo_table (1, 2)
132 , bottom_button_table (1, 3)
133 , meter_point_button (_("pre"))
134 , monitor_section_button (0)
135 , midi_input_enable_button (0)
136 , _comment_button (_("Comments"))
137 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
138 , _visibility (X_("mixer-element-visibility"))
139 , control_slave_ui (sess)
148 _entered_mixer_strip= 0;
151 ignore_comment_edit = false;
152 ignore_toggle = false;
157 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
158 longest_label = "longest label";
160 string t = _("Click to toggle the width of this mixer strip.");
162 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
165 width_button.set_icon (ArdourIcon::StripWidth);
166 hide_button.set_tweaks (ArdourButton::Square);
167 set_tooltip (width_button, t);
169 hide_button.set_icon (ArdourIcon::CloseCross);
170 hide_button.set_tweaks (ArdourButton::Square);
171 set_tooltip (&hide_button, _("Hide this mixer strip"));
173 input_button_box.set_spacing(2);
175 input_button.set_text (_("Input"));
176 input_button.set_name ("mixer strip button");
177 input_button_box.pack_start (input_button, true, true);
179 output_button.set_text (_("Output"));
180 output_button.set_name ("mixer strip button");
182 set_tooltip (&meter_point_button, _("Click to select metering point"));
183 meter_point_button.set_name ("mixer strip button");
185 bottom_button_table.attach (meter_point_button, 2, 3, 0, 1);
187 meter_point_button.signal_button_press_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_press), false);
188 meter_point_button.signal_button_release_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_release), false);
190 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
192 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
193 solo_isolated_led->show ();
194 solo_isolated_led->set_no_show_all (true);
195 solo_isolated_led->set_name (X_("solo isolate"));
196 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
197 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
198 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
200 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
201 solo_safe_led->show ();
202 solo_safe_led->set_no_show_all (true);
203 solo_safe_led->set_name (X_("solo safe"));
204 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
205 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
206 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
208 solo_safe_led->set_text (S_("SoloLock|Lock"));
209 solo_isolated_led->set_text (_("Iso"));
211 solo_iso_table.set_homogeneous (true);
212 solo_iso_table.set_spacings (2);
213 if (!ARDOUR::Profile->get_trx()) {
214 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
215 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
217 solo_iso_table.show ();
219 rec_mon_table.set_homogeneous (true);
220 rec_mon_table.set_row_spacings (2);
221 rec_mon_table.set_col_spacings (2);
222 if (ARDOUR::Profile->get_mixbus()) {
223 rec_mon_table.resize (1, 3);
224 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
225 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
226 } else if (!ARDOUR::Profile->get_trx()) {
227 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
228 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
230 rec_mon_table.show ();
232 if (solo_isolated_led) {
233 button_size_group->add_widget (*solo_isolated_led);
236 button_size_group->add_widget (*solo_safe_led);
239 if (!ARDOUR::Profile->get_mixbus()) {
240 if (rec_enable_button) {
241 button_size_group->add_widget (*rec_enable_button);
243 if (monitor_disk_button) {
244 button_size_group->add_widget (*monitor_disk_button);
246 if (monitor_input_button) {
247 button_size_group->add_widget (*monitor_input_button);
251 mute_solo_table.set_homogeneous (true);
252 mute_solo_table.set_spacings (2);
254 bottom_button_table.set_spacings (2);
255 bottom_button_table.set_homogeneous (true);
256 bottom_button_table.attach (group_button, 1, 2, 0, 1);
257 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
259 name_button.set_name ("mixer strip button");
260 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
263 set_tooltip (&group_button, _("Mix group"));
264 group_button.set_name ("mixer strip button");
266 _comment_button.set_name (X_("mixer strip button"));
267 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
268 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
269 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
271 // TODO implement ArdourKnob::on_size_request properly
272 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
273 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
275 trim_control.set_tooltip_prefix (_("Trim: "));
276 trim_control.set_name ("trim knob");
277 trim_control.set_no_show_all (true);
278 input_button_box.pack_start (trim_control, false, false);
280 global_vpacker.set_border_width (1);
281 global_vpacker.set_spacing (0);
283 width_button.set_name ("mixer strip button");
284 hide_button.set_name ("mixer strip button");
286 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
287 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
289 width_hide_box.set_spacing (2);
290 width_hide_box.pack_start (width_button, false, true);
291 width_hide_box.pack_start (number_label, true, true);
292 width_hide_box.pack_end (hide_button, false, true);
294 number_label.set_text ("-");
295 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
296 number_label.set_no_show_all ();
297 number_label.set_name ("tracknumber label");
298 number_label.set_fixed_colors (0x80808080, 0x80808080);
299 number_label.set_alignment (.5, .5);
300 number_label.set_fallthrough_to_parent (true);
301 number_label.set_tweaks (ArdourButton::OccasionalText);
303 global_vpacker.set_spacing (2);
304 if (!ARDOUR::Profile->get_trx()) {
305 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (processor_box, true, true);
311 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
318 if (!ARDOUR::Profile->get_trx()) {
319 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
320 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
322 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
325 global_frame.add (global_vpacker);
326 global_frame.set_shadow_type (Gtk::SHADOW_IN);
327 global_frame.set_name ("BaseFrame");
331 /* force setting of visible selected status */
334 set_selected (false);
339 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
340 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
342 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
343 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
344 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
346 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
347 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
349 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
350 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
351 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
353 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
355 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
357 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
361 /* start off as a passthru strip. we'll correct this, if necessary,
362 in update_diskstream_display().
365 /* start off as a passthru strip. we'll correct this, if necessary,
366 in update_diskstream_display().
369 if (is_midi_track()) {
370 set_name ("MidiTrackStripBase");
372 set_name ("AudioTrackStripBase");
375 add_events (Gdk::BUTTON_RELEASE_MASK|
376 Gdk::ENTER_NOTIFY_MASK|
377 Gdk::LEAVE_NOTIFY_MASK|
379 Gdk::KEY_RELEASE_MASK);
381 set_flags (get_flags() | Gtk::CAN_FOCUS);
383 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
384 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
387 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
388 must be the same as those used in RCOptionEditor so that the configuration changes
389 are recognised when they occur.
391 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
392 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
393 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
394 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
395 _visibility.add (&output_button, X_("Output"), _("Output"), false);
396 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
397 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
399 parameter_changed (X_("mixer-element-visibility"));
400 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
401 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
402 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
404 //watch for mouse enter/exit so we can do some stuff
405 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
406 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
408 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
411 MixerStrip::~MixerStrip ()
413 CatchDeletion (this);
415 if (this ==_entered_mixer_strip)
416 _entered_mixer_strip = NULL;
420 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
422 _entered_mixer_strip = this;
424 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
425 //because the mixerstrip control is a parent that encompasses the strip
426 deselect_all_processors();
432 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
434 //if we have moved outside our strip, but not into a child view, then deselect ourselves
435 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
436 _entered_mixer_strip= 0;
438 //clear keyboard focus in the gain display. this is cheesy but fixes a longstanding "bug" where the user starts typing in the gain entry, and leaves it active, thereby prohibiting other keybindings from working
439 gpm.gain_display.set_sensitive(false);
441 gpm.gain_display.set_sensitive(true);
443 //if we leave this mixer strip we need to clear out any selections
444 //processor_box.processor_display.select_none(); //but this doesn't work, because it gets triggered when (for example) you open the menu or start a drag
451 MixerStrip::name() const
454 return _route->name();
460 MixerStrip::update_trim_control ()
462 if (route()->trim() && route()->trim()->active() &&
463 route()->n_inputs().n_audio() > 0) {
464 trim_control.show ();
465 trim_control.set_controllable (route()->trim()->gain_control());
467 trim_control.hide ();
468 boost::shared_ptr<Controllable> none;
469 trim_control.set_controllable (none);
474 MixerStrip::set_route (boost::shared_ptr<Route> rt)
476 //the rec/monitor stuff only shows up for tracks.
477 //the show_sends only shows up for buses.
478 //remove them all here, and we may add them back later
479 if (show_sends_button->get_parent()) {
480 rec_mon_table.remove (*show_sends_button);
482 if (rec_enable_button->get_parent()) {
483 rec_mon_table.remove (*rec_enable_button);
485 if (monitor_input_button->get_parent()) {
486 rec_mon_table.remove (*monitor_input_button);
488 if (monitor_disk_button->get_parent()) {
489 rec_mon_table.remove (*monitor_disk_button);
491 if (group_button.get_parent()) {
492 bottom_button_table.remove (group_button);
495 RouteUI::set_route (rt);
497 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
499 /* ProcessorBox needs access to _route so that it can read
502 processor_box.set_route (rt);
504 revert_to_default_display ();
506 /* unpack these from the parent and stuff them into our own
510 if (gpm.peak_display.get_parent()) {
511 gpm.peak_display.get_parent()->remove (gpm.peak_display);
513 if (gpm.gain_display.get_parent()) {
514 gpm.gain_display.get_parent()->remove (gpm.gain_display);
517 gpm.set_type (rt->meter_type());
519 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
520 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
522 if (solo_button->get_parent()) {
523 mute_solo_table.remove (*solo_button);
526 if (mute_button->get_parent()) {
527 mute_solo_table.remove (*mute_button);
530 if (route()->is_master()) {
531 solo_button->hide ();
532 mute_button->show ();
533 rec_mon_table.hide ();
534 if (solo_iso_table.get_parent()) {
535 solo_iso_table.get_parent()->remove(solo_iso_table);
537 if (monitor_section_button == 0) {
538 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
539 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
541 monitor_section_button = manage (new ArdourButton);
543 monitor_section_button->set_related_action (act);
544 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
545 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
546 monitor_section_button->show();
547 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
549 parameter_changed ("use-monitor-bus");
551 bottom_button_table.attach (group_button, 1, 2, 0, 1);
552 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
553 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
554 mute_button->show ();
555 solo_button->show ();
556 rec_mon_table.show ();
559 if (_mixer_owned && route()->is_master() ) {
561 HScrollbar scrollbar;
562 Gtk::Requisition requisition(scrollbar.size_request ());
563 int scrollbar_height = requisition.height;
565 spacer = manage (new EventBox);
566 spacer->set_size_request (-1, scrollbar_height+2);
567 global_vpacker.pack_start (*spacer, false, false);
572 monitor_input_button->show ();
573 monitor_disk_button->show ();
575 monitor_input_button->hide();
576 monitor_disk_button->hide ();
579 update_trim_control();
581 if (is_midi_track()) {
582 if (midi_input_enable_button == 0) {
583 midi_input_enable_button = manage (new ArdourButton);
584 midi_input_enable_button->set_name ("midi input button");
585 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
586 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
587 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
588 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
589 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
591 input_button_box.remove (*midi_input_enable_button);
593 /* get current state */
594 midi_input_status_changed ();
595 input_button_box.pack_start (*midi_input_enable_button, false, false);
597 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
599 if (midi_input_enable_button) {
600 /* removal from the container will delete it */
601 input_button_box.remove (*midi_input_enable_button);
602 midi_input_enable_button = 0;
606 if (is_audio_track()) {
607 boost::shared_ptr<AudioTrack> at = audio_track();
608 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
613 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
614 rec_enable_button->show();
616 if (ARDOUR::Profile->get_mixbus()) {
617 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
618 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
619 } else if (ARDOUR::Profile->get_trx()) {
620 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
622 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
623 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
630 if (!_route->is_master()) {
631 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
632 show_sends_button->show();
636 meter_point_button.set_text (meter_point_string (_route->meter_point()));
638 delete route_ops_menu;
641 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
642 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
643 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
644 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
646 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
648 if (_route->panner_shell()) {
649 update_panner_choices();
650 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
653 if (is_audio_track()) {
654 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
657 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
659 set_stuff_from_route ();
661 /* now force an update of all the various elements */
663 update_mute_display ();
664 update_solo_display ();
667 route_group_changed ();
668 update_track_number_visibility ();
671 panners.setup_pan ();
673 if (has_audio_outputs ()) {
679 update_diskstream_display ();
680 update_input_display ();
681 update_output_display ();
683 add_events (Gdk::BUTTON_RELEASE_MASK);
685 processor_box.show ();
687 if (!route()->is_master() && !route()->is_monitor()) {
688 /* we don't allow master or control routes to be hidden */
693 gpm.reset_peak_display ();
694 gpm.gain_display.show ();
695 gpm.peak_display.show ();
698 width_hide_box.show();
700 global_vpacker.show();
701 mute_solo_table.show();
702 bottom_button_table.show();
704 meter_point_button.show();
705 input_button_box.show_all();
706 output_button.show();
708 _comment_button.show();
710 gpm.gain_automation_state_button.show();
712 parameter_changed ("mixer-element-visibility");
719 MixerStrip::set_stuff_from_route ()
721 /* if width is not set, it will be set by the MixerUI or editor */
723 string str = gui_property ("strip-width");
725 set_width_enum (Width (string_2_enum (str, _width)), this);
730 MixerStrip::set_width_enum (Width w, void* owner)
732 /* always set the gpm width again, things may be hidden */
735 panners.set_width (w);
737 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
739 _width_owner = owner;
743 if (_width_owner == this) {
744 set_gui_property ("strip-width", enum_2_string (_width));
749 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
754 if (show_sends_button) {
755 show_sends_button->set_text (_("Aux"));
758 gpm.gain_automation_style_button.set_text (
759 gpm.astyle_string(gain_automation->automation_style()));
760 gpm.gain_automation_state_button.set_text (
761 gpm.astate_string(gain_automation->automation_state()));
763 if (_route->panner()) {
764 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
765 panners.astyle_string(_route->panner()->automation_style()));
766 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
767 panners.astate_string(_route->panner()->automation_state()));
771 // panners expect an even number of horiz. pixels
772 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
774 set_size_request (width, -1);
780 if (show_sends_button) {
781 show_sends_button->set_text (_("Snd"));
784 gpm.gain_automation_style_button.set_text (
785 gpm.short_astyle_string(gain_automation->automation_style()));
786 gpm.gain_automation_state_button.set_text (
787 gpm.short_astate_string(gain_automation->automation_state()));
788 gain_meter().setup_meters (); // recalc meter width
790 if (_route->panner()) {
791 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
792 panners.short_astyle_string(_route->panner()->automation_style()));
793 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
794 panners.short_astate_string(_route->panner()->automation_state()));
798 // panners expect an even number of horiz. pixels
799 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
801 set_size_request (width, -1);
806 processor_box.set_width (w);
808 update_input_display ();
809 update_output_display ();
810 setup_comment_button ();
811 route_group_changed ();
817 MixerStrip::set_packed (bool yn)
822 set_gui_property ("visible", true);
824 set_gui_property ("visible", false);
829 struct RouteCompareByName {
830 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
831 return a->name().compare (b->name()) < 0;
836 MixerStrip::output_release (GdkEventButton *ev)
838 switch (ev->button) {
840 edit_output_configuration ();
848 MixerStrip::output_press (GdkEventButton *ev)
850 using namespace Menu_Helpers;
851 if (!_session->engine().connected()) {
852 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
857 MenuList& citems = output_menu.items();
858 switch (ev->button) {
861 return false; //wait for the mouse-up to pop the dialog
865 output_menu.set_name ("ArdourContextMenu");
867 output_menu_bundles.clear ();
869 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
871 citems.push_back (SeparatorElem());
872 uint32_t const n_with_separator = citems.size ();
874 ARDOUR::BundleList current = _route->output()->bundles_connected ();
876 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
878 /* give user bundles first chance at being in the menu */
880 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
881 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
882 maybe_add_bundle_to_output_menu (*i, current);
886 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
887 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
888 maybe_add_bundle_to_output_menu (*i, current);
892 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
893 RouteList copy = *routes;
894 copy.sort (RouteCompareByName ());
895 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
896 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
899 if (citems.size() == n_with_separator) {
900 /* no routes added; remove the separator */
904 if (!ARDOUR::Profile->get_mixbus()) {
905 citems.push_back (SeparatorElem());
907 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
910 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
911 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
917 citems.push_back (SeparatorElem());
918 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
920 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
933 MixerStrip::input_release (GdkEventButton *ev)
935 switch (ev->button) {
938 edit_input_configuration ();
950 MixerStrip::input_press (GdkEventButton *ev)
952 using namespace Menu_Helpers;
954 MenuList& citems = input_menu.items();
955 input_menu.set_name ("ArdourContextMenu");
958 if (!_session->engine().connected()) {
959 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
964 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
967 switch (ev->button) {
970 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
974 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
976 citems.push_back (SeparatorElem());
977 uint32_t const n_with_separator = citems.size ();
979 input_menu_bundles.clear ();
981 ARDOUR::BundleList current = _route->input()->bundles_connected ();
983 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
985 /* give user bundles first chance at being in the menu */
987 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
988 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
989 maybe_add_bundle_to_input_menu (*i, current);
993 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
994 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
995 maybe_add_bundle_to_input_menu (*i, current);
999 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1000 RouteList copy = *routes;
1001 copy.sort (RouteCompareByName ());
1002 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1003 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1006 if (citems.size() == n_with_separator) {
1007 /* no routes added; remove the separator */
1011 citems.push_back (SeparatorElem());
1012 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1015 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1016 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1021 citems.push_back (SeparatorElem());
1022 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1024 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1036 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1038 if (ignore_toggle) {
1042 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1044 if (std::find (current.begin(), current.end(), c) == current.end()) {
1045 _route->input()->connect_ports_to_bundle (c, true, this);
1047 _route->input()->disconnect_ports_from_bundle (c, this);
1052 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1054 if (ignore_toggle) {
1058 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1060 if (std::find (current.begin(), current.end(), c) == current.end()) {
1061 _route->output()->connect_ports_to_bundle (c, true, this);
1063 _route->output()->disconnect_ports_from_bundle (c, this);
1068 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1070 using namespace Menu_Helpers;
1072 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1076 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1077 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1081 if (i != input_menu_bundles.end()) {
1085 input_menu_bundles.push_back (b);
1087 MenuList& citems = input_menu.items();
1089 std::string n = b->name ();
1090 replace_all (n, "_", " ");
1092 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1096 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1098 using namespace Menu_Helpers;
1100 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1104 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1105 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1109 if (i != output_menu_bundles.end()) {
1113 output_menu_bundles.push_back (b);
1115 MenuList& citems = output_menu.items();
1117 std::string n = b->name ();
1118 replace_all (n, "_", " ");
1120 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1124 MixerStrip::update_diskstream_display ()
1126 if (is_track() && input_selector) {
1127 input_selector->hide_all ();
1130 route_color_changed ();
1134 MixerStrip::connect_to_pan ()
1136 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1138 panstate_connection.disconnect ();
1139 panstyle_connection.disconnect ();
1141 if (!_route->panner()) {
1145 boost::shared_ptr<Pannable> p = _route->pannable ();
1147 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1148 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1150 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1151 * However, that only works a panner was previously set.
1153 * PannerUI must remain subscribed to _panshell->Changed() in case
1154 * we switch the panner eg. AUX-Send and back
1155 * _route->panner_shell()->Changed() vs _panshell->Changed
1157 if (panners._panner == 0) {
1158 panners.panshell_changed ();
1160 update_panner_choices();
1164 MixerStrip::update_panner_choices ()
1166 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1167 if (!_route->panner_shell()) { return; }
1169 uint32_t in = _route->output()->n_ports().n_audio();
1171 if (_route->panner()) {
1172 in = _route->panner()->in().n_audio();
1175 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1179 * Output port labelling
1180 * =====================
1182 * Case 1: Each output has one connection, all connections are to system:playback_%i
1183 * out 1 -> system:playback_1
1184 * out 2 -> system:playback_2
1185 * out 3 -> system:playback_3
1188 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1189 * out 1 -> ardour:track_x/in 1
1190 * out 2 -> ardour:track_x/in 2
1191 * Display as: track_x
1193 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1194 * out 1 -> program x:foo
1195 * out 2 -> program x:foo
1196 * Display as: program x
1198 * Case 4: No connections (Disconnected)
1201 * Default case (unusual routing):
1202 * Display as: *number of connections*
1206 * .-----------------------------------------------.
1208 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1209 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1210 * '-----------------------------------------------'
1211 * .-----------------------------------------------.
1214 * '-----------------------------------------------'
1218 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1222 boost::shared_ptr<IO> io;
1223 boost::shared_ptr<Port> port;
1224 vector<string> port_connections;
1226 uint32_t total_connection_count = 0;
1227 uint32_t io_connection_count = 0;
1228 uint32_t ardour_connection_count = 0;
1229 uint32_t system_connection_count = 0;
1230 uint32_t other_connection_count = 0;
1231 uint32_t typed_connection_count = 0;
1233 ostringstream label;
1235 bool have_label = false;
1236 bool each_io_has_one_connection = true;
1238 string connection_name;
1239 string ardour_track_name;
1240 string other_connection_type;
1241 string system_ports;
1244 ostringstream tooltip;
1245 char * tooltip_cstr;
1247 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1249 * First of all, if the user made only connections to a given type, we should use that one since
1250 * it is very probably what the user expects. If there are several connections types, then show
1251 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1252 * synthesisers. This first heuristic can be expressed with these two rules:
1253 * A) If there are connected audio ports, consider audio as primary type.
1254 * B) Else, if there are connected midi ports, consider midi as primary type.
1256 * If there are no connected ports, then we choose the primary type based on the type of existing
1257 * but unconnected ports. Again:
1258 * C) If there are audio ports, consider audio as primary type.
1259 * D) Else, if there are midi ports, consider midi as primary type. */
1261 DataType dt = DataType::AUDIO;
1265 io = route->input();
1267 io = route->output();
1270 io_count = io->n_ports().n_total();
1271 for (io_index = 0; io_index < io_count; ++io_index) {
1272 port = io->nth (io_index);
1273 if (port->connected()) {
1275 if (port->type() == DataType::AUDIO) {
1276 /* Rule A) applies no matter the remaining ports */
1277 dt = DataType::AUDIO;
1280 if (port->type() == DataType::MIDI) {
1281 /* Rule B) is a good candidate... */
1282 dt = DataType::MIDI;
1283 /* ...but continue the loop to check remaining ports for rule A) */
1289 /* Neither rule A) nor rule B) matched */
1290 if ( io->n_ports().n_audio() > 0 ) {
1292 dt = DataType::AUDIO;
1293 } else if ( io->n_ports().n_midi() > 0 ) {
1295 dt = DataType::MIDI;
1299 if ( dt == DataType::MIDI ) {
1300 tooltip << _("MIDI ");
1304 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1306 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1309 for (io_index = 0; io_index < io_count; ++io_index) {
1310 port = io->nth (io_index);
1312 port_connections.clear ();
1313 port->get_connections(port_connections);
1315 //ignore any port connections that don't match our DataType
1316 if (port->type() != dt) {
1317 if (!port_connections.empty()) {
1318 ++typed_connection_count;
1323 io_connection_count = 0;
1325 if (!port_connections.empty()) {
1326 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1328 string& connection_name (*i);
1330 if (connection_name.find("system:") == 0) {
1331 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1334 if (io_connection_count == 0) {
1335 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1337 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1340 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1343 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1344 if (ardour_track_name.empty()) {
1345 // "ardour:Master/in 1" -> "ardour:Master/"
1346 string::size_type slash = connection_name.find("/");
1347 if (slash != string::npos) {
1348 ardour_track_name = connection_name.substr(0, slash + 1);
1352 if (connection_name.find(ardour_track_name) == 0) {
1353 ++ardour_connection_count;
1355 } else if (!pn.empty()) {
1356 if (system_ports.empty()) {
1359 system_ports += "/" + pn;
1361 if (connection_name.find("system:") == 0) {
1362 ++system_connection_count;
1364 } else if (connection_name.find("system:midi_") == 0) {
1366 // "system:midi_capture_123" -> "123"
1367 system_port = "M " + connection_name.substr(20);
1369 // "system:midi_playback_123" -> "123"
1370 system_port = "M " + connection_name.substr(21);
1373 if (system_ports.empty()) {
1374 system_ports += system_port;
1376 system_ports += "/" + system_port;
1379 ++system_connection_count;
1381 } else if (connection_name.find("system:") == 0) {
1383 // "system:capture_123" -> "123"
1384 system_port = connection_name.substr(15);
1386 // "system:playback_123" -> "123"
1387 system_port = connection_name.substr(16);
1390 if (system_ports.empty()) {
1391 system_ports += system_port;
1393 system_ports += "/" + system_port;
1396 ++system_connection_count;
1398 if (other_connection_type.empty()) {
1399 // "jamin:in 1" -> "jamin:"
1400 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1403 if (connection_name.find(other_connection_type) == 0) {
1404 ++other_connection_count;
1408 ++total_connection_count;
1409 ++io_connection_count;
1413 if (io_connection_count != 1) {
1414 each_io_has_one_connection = false;
1418 if (total_connection_count == 0) {
1419 tooltip << endl << _("Disconnected");
1422 tooltip_cstr = new char[tooltip.str().size() + 1];
1423 strcpy(tooltip_cstr, tooltip.str().c_str());
1426 set_tooltip (&input_button, tooltip_cstr);
1428 set_tooltip (&output_button, tooltip_cstr);
1431 delete [] tooltip_cstr;
1433 if (each_io_has_one_connection) {
1434 if (total_connection_count == ardour_connection_count) {
1435 // all connections are to the same track in ardour
1436 // "ardour:Master/" -> "Master"
1437 string::size_type slash = ardour_track_name.find("/");
1438 if (slash != string::npos) {
1439 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1440 label << ardour_track_name.substr (ppps, slash - ppps);
1444 else if (total_connection_count == system_connection_count) {
1445 // all connections are to system ports
1446 label << system_ports;
1449 else if (total_connection_count == other_connection_count) {
1450 // all connections are to the same external program eg jamin
1451 // "jamin:" -> "jamin"
1452 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1458 if (total_connection_count == 0) {
1462 // Odd configuration
1463 label << "*" << total_connection_count << "*";
1465 if (typed_connection_count > 0) {
1466 label << "\u2295"; // circled plus
1471 input_button.set_text (label.str());
1473 output_button.set_text (label.str());
1478 MixerStrip::update_input_display ()
1480 update_io_button (_route, _width, true);
1481 panners.setup_pan ();
1483 if (has_audio_outputs ()) {
1484 panners.show_all ();
1486 panners.hide_all ();
1492 MixerStrip::update_output_display ()
1494 update_io_button (_route, _width, false);
1495 gpm.setup_meters ();
1496 panners.setup_pan ();
1498 if (has_audio_outputs ()) {
1499 panners.show_all ();
1501 panners.hide_all ();
1506 MixerStrip::fast_update ()
1508 gpm.update_meters ();
1512 MixerStrip::diskstream_changed ()
1514 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1518 MixerStrip::io_changed_proxy ()
1520 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1521 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1525 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1527 boost::shared_ptr<Port> a = wa.lock ();
1528 boost::shared_ptr<Port> b = wb.lock ();
1530 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1531 update_input_display ();
1532 set_width_enum (_width, this);
1535 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1536 update_output_display ();
1537 set_width_enum (_width, this);
1542 MixerStrip::setup_comment_button ()
1544 std::string comment = _route->comment();
1546 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1548 if (comment.empty ()) {
1549 _comment_button.set_name ("generic button");
1550 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1554 _comment_button.set_name ("comment button");
1556 string::size_type pos = comment.find_first_of (" \t\n");
1557 if (pos != string::npos) {
1558 comment = comment.substr (0, pos);
1560 if (comment.empty()) {
1561 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1563 _comment_button.set_text (comment);
1568 MixerStrip::select_route_group (GdkEventButton *ev)
1570 using namespace Menu_Helpers;
1572 if (ev->button == 1) {
1574 if (group_menu == 0) {
1576 PropertyList* plist = new PropertyList();
1578 plist->add (Properties::group_gain, true);
1579 plist->add (Properties::group_mute, true);
1580 plist->add (Properties::group_solo, true);
1582 group_menu = new RouteGroupMenu (_session, plist);
1586 r.push_back (route ());
1587 group_menu->build (r);
1589 RouteGroup *rg = _route->route_group();
1591 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1592 rg ? rg->name() : _("No Group"),
1600 MixerStrip::route_group_changed ()
1602 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1604 RouteGroup *rg = _route->route_group();
1607 group_button.set_text (PBD::short_version (rg->name(), 5));
1611 group_button.set_text (_("Grp"));
1614 group_button.set_text (_("~G"));
1621 MixerStrip::route_color_changed ()
1623 name_button.modify_bg (STATE_NORMAL, color());
1624 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1625 reset_strip_style ();
1629 MixerStrip::show_passthru_color ()
1631 reset_strip_style ();
1636 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1638 boost::shared_ptr<Processor> processor (p.lock ());
1639 if (!processor || !processor->display_to_user()) {
1642 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1644 if (pi && pi->is_channelstrip ()) {
1649 ++_plugin_insert_cnt;
1653 MixerStrip::build_route_ops_menu ()
1655 using namespace Menu_Helpers;
1656 route_ops_menu = new Menu;
1657 route_ops_menu->set_name ("ArdourContextMenu");
1659 MenuList& items = route_ops_menu->items();
1661 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1663 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1665 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1667 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1669 items.push_back (SeparatorElem());
1671 if (!_route->is_master()) {
1672 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1674 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1675 rename_menu_item = &items.back();
1677 items.push_back (SeparatorElem());
1678 items.push_back (CheckMenuElem (_("Active")));
1679 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1680 i->set_active (_route->active());
1681 i->set_sensitive(! _session->transport_rolling());
1682 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1684 if (!Profile->get_mixbus ()) {
1685 items.push_back (SeparatorElem());
1686 items.push_back (CheckMenuElem (_("Strict I/O")));
1687 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1688 i->set_active (_route->strict_io());
1689 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1692 _plugin_insert_cnt = 0;
1693 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1694 if (_plugin_insert_cnt > 0) {
1695 items.push_back (SeparatorElem());
1696 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1699 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1700 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1701 items.push_back (MenuElem (_("Fan Out Instrument"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1704 items.push_back (SeparatorElem());
1705 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1707 items.push_back (SeparatorElem());
1708 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1709 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1710 denormal_menu_item->set_active (_route->denormal_protection());
1713 /* note that this relies on selection being shared across editor and
1714 mixer (or global to the backend, in the future), which is the only
1715 sane thing for users anyway.
1718 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1720 Selection& selection (PublicEditor::instance().get_selection());
1721 if (!selection.selected (rtav)) {
1722 selection.set (rtav);
1725 if (!_route->is_master()) {
1726 items.push_back (SeparatorElem());
1727 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1730 items.push_back (SeparatorElem());
1731 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1737 MixerStrip::name_button_button_press (GdkEventButton* ev)
1739 if (ev->button == 1 || ev->button == 3) {
1740 list_route_operations ();
1742 /* do not allow rename if the track is record-enabled */
1743 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1744 if (ev->button == 1) {
1745 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1748 route_ops_menu->popup (3, ev->time);
1758 MixerStrip::number_button_button_press (GdkEventButton* ev)
1760 if ( ev->button == 3 ) {
1761 list_route_operations ();
1763 /* do not allow rename if the track is record-enabled */
1764 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1765 route_ops_menu->popup (1, ev->time);
1774 MixerStrip::list_route_operations ()
1776 delete route_ops_menu;
1777 build_route_ops_menu ();
1781 MixerStrip::set_selected (bool yn)
1783 AxisView::set_selected (yn);
1786 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1787 global_frame.set_name ("MixerStripSelectedFrame");
1789 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1790 global_frame.set_name ("MixerStripFrame");
1793 global_frame.queue_draw ();
1796 // processor_box.deselect_all_processors();
1800 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1802 if (what_changed.contains (ARDOUR::Properties::name)) {
1808 MixerStrip::name_changed ()
1812 name_button.set_text (_route->name());
1815 name_button.set_text (PBD::short_version (_route->name(), 5));
1819 set_tooltip (name_button, _route->name());
1821 if (_session->config.get_track_name_number()) {
1822 const int64_t track_number = _route->track_number ();
1823 if (track_number == 0) {
1824 number_label.set_text ("-");
1826 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1829 number_label.set_text ("");
1834 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1836 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1840 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1842 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1846 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1848 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1852 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1854 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1858 MixerStrip::width_button_pressed (GdkEventButton* ev)
1860 if (ev->button != 1) {
1864 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1867 _mixer.set_strip_width (Narrow, true);
1871 _mixer.set_strip_width (Wide, true);
1877 set_width_enum (Narrow, this);
1880 set_width_enum (Wide, this);
1889 MixerStrip::hide_clicked ()
1891 // LAME fix to reset the button status for when it is redisplayed (part 1)
1892 hide_button.set_sensitive(false);
1895 Hiding(); /* EMIT_SIGNAL */
1897 _mixer.hide_strip (this);
1901 hide_button.set_sensitive(true);
1905 MixerStrip::set_embedded (bool yn)
1911 MixerStrip::map_frozen ()
1913 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1915 boost::shared_ptr<AudioTrack> at = audio_track();
1918 switch (at->freeze_state()) {
1919 case AudioTrack::Frozen:
1920 processor_box.set_sensitive (false);
1921 hide_redirect_editors ();
1924 processor_box.set_sensitive (true);
1925 // XXX need some way, maybe, to retoggle redirect editors
1929 processor_box.set_sensitive (true);
1931 RouteUI::map_frozen ();
1935 MixerStrip::hide_redirect_editors ()
1937 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1941 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1943 boost::shared_ptr<Processor> processor (p.lock ());
1948 Gtk::Window* w = processor_box.get_processor_ui (processor);
1956 MixerStrip::reset_strip_style ()
1958 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1960 gpm.set_fader_name ("SendStripBase");
1964 if (is_midi_track()) {
1965 if (_route->active()) {
1966 set_name ("MidiTrackStripBase");
1968 set_name ("MidiTrackStripBaseInactive");
1970 gpm.set_fader_name ("MidiTrackFader");
1971 } else if (is_audio_track()) {
1972 if (_route->active()) {
1973 set_name ("AudioTrackStripBase");
1975 set_name ("AudioTrackStripBaseInactive");
1977 gpm.set_fader_name ("AudioTrackFader");
1979 if (_route->active()) {
1980 set_name ("AudioBusStripBase");
1982 set_name ("AudioBusStripBaseInactive");
1984 gpm.set_fader_name ("AudioBusFader");
1986 /* (no MIDI busses yet) */
1993 MixerStrip::engine_stopped ()
1998 MixerStrip::engine_running ()
2003 MixerStrip::meter_point_string (MeterPoint mp)
2016 case MeterPostFader:
2033 return S_("Meter|In");
2037 return S_("Meter|Pr");
2040 case MeterPostFader:
2041 return S_("Meter|Po");
2045 return S_("Meter|O");
2050 return S_("Meter|C");
2059 /** Called when the monitor-section state */
2061 MixerStrip::monitor_changed ()
2063 assert (monitor_section_button);
2064 if (_session->monitor_active()) {
2065 monitor_section_button->set_name ("master monitor section button active");
2067 monitor_section_button->set_name ("master monitor section button normal");
2071 /** Called when the metering point has changed */
2073 MixerStrip::meter_changed ()
2075 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2076 gpm.setup_meters ();
2077 // reset peak when meter point changes
2078 gpm.reset_peak_display();
2081 /** The bus that we are displaying sends to has changed, or been turned off.
2082 * @param send_to New bus that we are displaying sends to, or 0.
2085 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2087 RouteUI::bus_send_display_changed (send_to);
2090 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2095 revert_to_default_display ();
2098 revert_to_default_display ();
2103 MixerStrip::drop_send ()
2105 boost::shared_ptr<Send> current_send;
2107 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2108 current_send->set_metering (false);
2111 send_gone_connection.disconnect ();
2112 input_button.set_sensitive (true);
2113 output_button.set_sensitive (true);
2114 group_button.set_sensitive (true);
2115 set_invert_sensitive (true);
2116 meter_point_button.set_sensitive (true);
2117 mute_button->set_sensitive (true);
2118 solo_button->set_sensitive (true);
2119 solo_isolated_led->set_sensitive (true);
2120 solo_safe_led->set_sensitive (true);
2121 monitor_input_button->set_sensitive (true);
2122 monitor_disk_button->set_sensitive (true);
2123 _comment_button.set_sensitive (true);
2124 RouteUI::check_rec_enable_sensitivity ();
2125 set_button_names (); // update solo button visual state
2129 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2131 _current_delivery = d;
2132 DeliveryChanged (_current_delivery);
2136 MixerStrip::show_send (boost::shared_ptr<Send> send)
2142 set_current_delivery (send);
2144 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2145 send->set_metering (true);
2146 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2148 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2149 gain_meter().setup_meters ();
2151 uint32_t const in = _current_delivery->pans_required();
2152 uint32_t const out = _current_delivery->pan_outs();
2154 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2155 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2156 panner_ui().setup_pan ();
2157 panner_ui().set_send_drawing_mode (true);
2158 panner_ui().show_all ();
2160 input_button.set_sensitive (false);
2161 group_button.set_sensitive (false);
2162 set_invert_sensitive (false);
2163 meter_point_button.set_sensitive (false);
2164 mute_button->set_sensitive (false);
2165 solo_button->set_sensitive (false);
2166 rec_enable_button->set_sensitive (false);
2167 solo_isolated_led->set_sensitive (false);
2168 solo_safe_led->set_sensitive (false);
2169 monitor_input_button->set_sensitive (false);
2170 monitor_disk_button->set_sensitive (false);
2171 _comment_button.set_sensitive (false);
2173 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2174 output_button.set_sensitive (false);
2177 reset_strip_style ();
2181 MixerStrip::revert_to_default_display ()
2185 set_current_delivery (_route->main_outs ());
2187 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2188 gain_meter().setup_meters ();
2190 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2191 update_panner_choices();
2192 panner_ui().setup_pan ();
2193 panner_ui().set_send_drawing_mode (false);
2195 if (has_audio_outputs ()) {
2196 panners.show_all ();
2198 panners.hide_all ();
2201 reset_strip_style ();
2205 MixerStrip::set_button_names ()
2209 mute_button->set_text (_("Mute"));
2210 monitor_input_button->set_text (_("In"));
2211 monitor_disk_button->set_text (_("Disk"));
2212 if (monitor_section_button) {
2213 monitor_section_button->set_text (_("Mon"));
2216 if (_route && _route->solo_safe_control()->solo_safe()) {
2217 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2219 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2221 if (!Config->get_solo_control_is_listen_control()) {
2222 solo_button->set_text (_("Solo"));
2224 switch (Config->get_listen_position()) {
2225 case AfterFaderListen:
2226 solo_button->set_text (_("AFL"));
2228 case PreFaderListen:
2229 solo_button->set_text (_("PFL"));
2233 solo_isolated_led->set_text (_("Iso"));
2234 solo_safe_led->set_text (S_("SoloLock|Lock"));
2238 mute_button->set_text (S_("Mute|M"));
2239 monitor_input_button->set_text (S_("MonitorInput|I"));
2240 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2241 if (monitor_section_button) {
2242 monitor_section_button->set_text (S_("Mon|O"));
2245 if (_route && _route->solo_safe_control()->solo_safe()) {
2246 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2248 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2250 if (!Config->get_solo_control_is_listen_control()) {
2251 solo_button->set_text (S_("Solo|S"));
2253 switch (Config->get_listen_position()) {
2254 case AfterFaderListen:
2255 solo_button->set_text (S_("AfterFader|A"));
2257 case PreFaderListen:
2258 solo_button->set_text (S_("Prefader|P"));
2263 solo_isolated_led->set_text (S_("SoloIso|I"));
2264 solo_safe_led->set_text (S_("SoloLock|L"));
2269 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2271 meter_point_button.set_text ("");
2276 MixerStrip::plugin_selector()
2278 return _mixer.plugin_selector();
2282 MixerStrip::hide_things ()
2284 processor_box.hide_things ();
2288 MixerStrip::input_active_button_press (GdkEventButton*)
2290 /* nothing happens on press */
2295 MixerStrip::input_active_button_release (GdkEventButton* ev)
2297 boost::shared_ptr<MidiTrack> mt = midi_track ();
2303 boost::shared_ptr<RouteList> rl (new RouteList);
2305 rl->push_back (route());
2307 _session->set_exclusive_input_active (rl, !mt->input_active(),
2308 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2314 MixerStrip::midi_input_status_changed ()
2316 if (midi_input_enable_button) {
2317 boost::shared_ptr<MidiTrack> mt = midi_track ();
2319 midi_input_enable_button->set_active (mt->input_active ());
2324 MixerStrip::state_id () const
2326 return string_compose ("strip %1", _route->id().to_s());
2330 MixerStrip::parameter_changed (string p)
2332 if (p == _visibility.get_state_name()) {
2333 /* The user has made changes to the mixer strip visibility, so get
2334 our VisibilityGroup to reflect these changes in our widgets.
2336 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2337 } else if (p == "track-name-number") {
2339 } else if (p == "use-monitor-bus") {
2340 if (monitor_section_button) {
2341 if (mute_button->get_parent()) {
2342 mute_button->get_parent()->remove(*mute_button);
2344 if (monitor_section_button->get_parent()) {
2345 monitor_section_button->get_parent()->remove(*monitor_section_button);
2347 if (Config->get_use_monitor_bus ()) {
2348 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2349 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2350 mute_button->show();
2351 monitor_section_button->show();
2353 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2354 mute_button->show();
2357 } else if (p == "track-name-number") {
2358 update_track_number_visibility();
2362 /** Called to decide whether the solo isolate / solo lock button visibility should
2363 * be overridden from that configured by the user. We do this for the master bus.
2365 * @return optional value that is present if visibility state should be overridden.
2367 boost::optional<bool>
2368 MixerStrip::override_solo_visibility () const
2370 if (_route && _route->is_master ()) {
2371 return boost::optional<bool> (false);
2374 return boost::optional<bool> ();
2378 MixerStrip::add_input_port (DataType t)
2380 _route->input()->add_port ("", this, t);
2384 MixerStrip::add_output_port (DataType t)
2386 _route->output()->add_port ("", this, t);
2390 MixerStrip::route_active_changed ()
2392 reset_strip_style ();
2396 MixerStrip::copy_processors ()
2398 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2402 MixerStrip::cut_processors ()
2404 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2408 MixerStrip::paste_processors ()
2410 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2414 MixerStrip::select_all_processors ()
2416 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2420 MixerStrip::deselect_all_processors ()
2422 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2426 MixerStrip::delete_processors ()
2428 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2432 MixerStrip::toggle_processors ()
2434 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2438 MixerStrip::ab_plugins ()
2440 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2444 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2446 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2449 if (ev->button == 3) {
2450 popup_level_meter_menu (ev);
2458 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2460 using namespace Gtk::Menu_Helpers;
2462 Gtk::Menu* m = manage (new Menu);
2463 MenuList& items = m->items ();
2465 RadioMenuItem::Group group;
2467 _suspend_menu_callbacks = true;
2468 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2469 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2470 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2471 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2472 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2474 if (gpm.meter_channels().n_audio() == 0) {
2475 m->popup (ev->button, ev->time);
2476 _suspend_menu_callbacks = false;
2480 RadioMenuItem::Group tgroup;
2481 items.push_back (SeparatorElem());
2483 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2484 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2485 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2486 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2487 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2488 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2489 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2490 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2491 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2492 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2493 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2496 if (_route->is_master()) {
2499 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2500 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2501 /* non-master bus */
2504 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2511 MeterType cmt = _route->meter_type();
2512 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2514 items.push_back (SeparatorElem());
2515 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2516 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2517 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2518 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2519 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2520 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2522 m->popup (ev->button, ev->time);
2523 _suspend_menu_callbacks = false;
2527 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2528 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2530 using namespace Menu_Helpers;
2532 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2533 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2534 i->set_active (_route->meter_point() == point);
2538 MixerStrip::set_meter_point (MeterPoint p)
2540 if (_suspend_menu_callbacks) return;
2541 _route->set_meter_point (p);
2545 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2546 RadioMenuItem::Group& group, string const & name, MeterType type)
2548 using namespace Menu_Helpers;
2550 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2551 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2552 i->set_active (_route->meter_type() == type);
2556 MixerStrip::set_meter_type (MeterType t)
2558 if (_suspend_menu_callbacks) return;
2563 MixerStrip::update_track_number_visibility ()
2565 DisplaySuspender ds;
2566 bool show_label = _session->config.get_track_name_number();
2568 if (_route && _route->is_master()) {
2573 number_label.show ();
2574 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2575 // except the width of the number label is subtracted from the name-hbox, so we
2576 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2577 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2579 number_label.set_size_request(tnw, -1);
2580 number_label.show ();
2582 number_label.hide ();
2587 MixerStrip::color () const
2589 return route_color ();
2593 MixerStrip::marked_for_display () const
2595 return !_route->presentation_info().hidden();
2599 MixerStrip::set_marked_for_display (bool yn)
2601 return RouteUI::mark_hidden (!yn);