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 , monitor_section_button (0)
101 , midi_input_enable_button (0)
102 , _plugin_insert_cnt (0)
103 , _comment_button (_("Comments"))
104 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
105 , _visibility (X_("mixer-element-visibility"))
106 , control_slave_ui (sess)
111 /* the editor mixer strip: don't destroy it every time
112 the underlying route goes away.
115 self_destruct = false;
119 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
120 : SessionHandlePtr (sess)
123 , _mixer_owned (in_mixer)
124 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
127 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
128 , rec_mon_table (2, 2)
129 , solo_iso_table (1, 2)
130 , mute_solo_table (1, 2)
131 , bottom_button_table (1, 3)
132 , monitor_section_button (0)
133 , midi_input_enable_button (0)
134 , _plugin_insert_cnt (0)
135 , _comment_button (_("Comments"))
136 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
137 , _visibility (X_("mixer-element-visibility"))
138 , control_slave_ui (sess)
147 _entered_mixer_strip= 0;
150 ignore_comment_edit = false;
151 ignore_toggle = false;
155 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
156 longest_label = "longest label";
158 string t = _("Click to toggle the width of this mixer strip.");
160 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
163 width_button.set_icon (ArdourIcon::StripWidth);
164 hide_button.set_tweaks (ArdourButton::Square);
165 set_tooltip (width_button, t);
167 hide_button.set_icon (ArdourIcon::CloseCross);
168 hide_button.set_tweaks (ArdourButton::Square);
169 set_tooltip (&hide_button, _("Hide this mixer strip"));
171 input_button_box.set_spacing(2);
173 input_button.set_text (_("Input"));
174 input_button.set_name ("mixer strip button");
175 input_button_box.pack_start (input_button, true, true);
177 output_button.set_text (_("Output"));
178 output_button.set_name ("mixer strip button");
180 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
182 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
184 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
185 solo_isolated_led->show ();
186 solo_isolated_led->set_no_show_all (true);
187 solo_isolated_led->set_name (X_("solo isolate"));
188 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
189 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
190 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
192 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
193 solo_safe_led->show ();
194 solo_safe_led->set_no_show_all (true);
195 solo_safe_led->set_name (X_("solo safe"));
196 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
197 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
198 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
200 solo_safe_led->set_text (S_("SoloLock|Lock"));
201 solo_isolated_led->set_text (_("Iso"));
203 solo_iso_table.set_homogeneous (true);
204 solo_iso_table.set_spacings (2);
205 if (!ARDOUR::Profile->get_trx()) {
206 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
207 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
209 solo_iso_table.show ();
211 rec_mon_table.set_homogeneous (true);
212 rec_mon_table.set_row_spacings (2);
213 rec_mon_table.set_col_spacings (2);
214 if (ARDOUR::Profile->get_mixbus()) {
215 rec_mon_table.resize (1, 3);
216 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
217 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
218 } else if (!ARDOUR::Profile->get_trx()) {
219 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
220 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
222 rec_mon_table.show ();
224 if (solo_isolated_led) {
225 button_size_group->add_widget (*solo_isolated_led);
228 button_size_group->add_widget (*solo_safe_led);
231 if (!ARDOUR::Profile->get_mixbus()) {
232 if (rec_enable_button) {
233 button_size_group->add_widget (*rec_enable_button);
235 if (monitor_disk_button) {
236 button_size_group->add_widget (*monitor_disk_button);
238 if (monitor_input_button) {
239 button_size_group->add_widget (*monitor_input_button);
243 mute_solo_table.set_homogeneous (true);
244 mute_solo_table.set_spacings (2);
246 bottom_button_table.set_spacings (2);
247 bottom_button_table.set_homogeneous (true);
248 bottom_button_table.attach (group_button, 1, 2, 0, 1);
249 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
251 name_button.set_name ("mixer strip button");
252 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
253 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
255 set_tooltip (&group_button, _("Mix group"));
256 group_button.set_name ("mixer strip button");
258 _comment_button.set_name (X_("mixer strip button"));
259 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
260 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
261 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
263 // TODO implement ArdourKnob::on_size_request properly
264 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
265 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
267 trim_control.set_tooltip_prefix (_("Trim: "));
268 trim_control.set_name ("trim knob");
269 trim_control.set_no_show_all (true);
270 input_button_box.pack_start (trim_control, false, false);
272 global_vpacker.set_border_width (1);
273 global_vpacker.set_spacing (0);
275 width_button.set_name ("mixer strip button");
276 hide_button.set_name ("mixer strip button");
278 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
279 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
281 width_hide_box.set_spacing (2);
282 width_hide_box.pack_start (width_button, false, true);
283 width_hide_box.pack_start (number_label, true, true);
284 width_hide_box.pack_end (hide_button, false, true);
286 number_label.set_text ("-");
287 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
288 number_label.set_no_show_all ();
289 number_label.set_name ("tracknumber label");
290 number_label.set_fixed_colors (0x80808080, 0x80808080);
291 number_label.set_alignment (.5, .5);
292 number_label.set_fallthrough_to_parent (true);
293 number_label.set_tweaks (ArdourButton::OccasionalText);
295 global_vpacker.set_spacing (2);
296 if (!ARDOUR::Profile->get_trx()) {
297 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
298 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
299 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
300 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
301 global_vpacker.pack_start (processor_box, true, true);
303 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
310 if (!ARDOUR::Profile->get_trx()) {
311 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
318 //add a spacer underneath the master bus;
319 //this fills the area that is taken up by the scrollbar on the tracks;
320 //and therefore keeps the faders "even" across the bottom
321 int scrollbar_height = 0;
323 Gtk::Window window (WINDOW_TOPLEVEL);
324 HScrollbar scrollbar;
325 window.add (scrollbar);
326 scrollbar.set_name ("MixerWindow");
327 scrollbar.ensure_style();
328 Gtk::Requisition requisition(scrollbar.size_request ());
329 scrollbar_height = requisition.height;
331 spacer.set_size_request (-1, scrollbar_height);
332 global_vpacker.pack_end (spacer, false, false);
335 global_frame.add (global_vpacker);
336 global_frame.set_shadow_type (Gtk::SHADOW_IN);
337 global_frame.set_name ("BaseFrame");
341 /* force setting of visible selected status */
344 set_selected (false);
349 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
350 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
352 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
353 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
354 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
356 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
357 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
359 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
360 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
361 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
363 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
365 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
367 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
371 /* start off as a passthru strip. we'll correct this, if necessary,
372 in update_diskstream_display().
375 /* start off as a passthru strip. we'll correct this, if necessary,
376 in update_diskstream_display().
379 if (is_midi_track()) {
380 set_name ("MidiTrackStripBase");
382 set_name ("AudioTrackStripBase");
385 add_events (Gdk::BUTTON_RELEASE_MASK|
386 Gdk::ENTER_NOTIFY_MASK|
387 Gdk::LEAVE_NOTIFY_MASK|
389 Gdk::KEY_RELEASE_MASK);
391 set_flags (get_flags() | Gtk::CAN_FOCUS);
393 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
394 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
397 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
398 must be the same as those used in RCOptionEditor so that the configuration changes
399 are recognised when they occur.
401 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
402 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
403 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
404 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
405 _visibility.add (&output_button, X_("Output"), _("Output"), false);
406 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
407 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
409 parameter_changed (X_("mixer-element-visibility"));
410 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
411 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
412 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
414 //watch for mouse enter/exit so we can do some stuff
415 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
416 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
418 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
421 MixerStrip::~MixerStrip ()
423 CatchDeletion (this);
425 if (this ==_entered_mixer_strip)
426 _entered_mixer_strip = NULL;
430 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
432 _entered_mixer_strip = this;
434 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
435 //because the mixerstrip control is a parent that encompasses the strip
436 deselect_all_processors();
442 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
444 //if we have moved outside our strip, but not into a child view, then deselect ourselves
445 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
446 _entered_mixer_strip= 0;
448 //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
449 gpm.gain_display.set_sensitive(false);
451 gpm.gain_display.set_sensitive(true);
453 //if we leave this mixer strip we need to clear out any selections
454 //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
461 MixerStrip::name() const
464 return _route->name();
470 MixerStrip::update_trim_control ()
472 if (route()->trim() && route()->trim()->active() &&
473 route()->n_inputs().n_audio() > 0) {
474 trim_control.show ();
475 trim_control.set_controllable (route()->trim()->gain_control());
477 trim_control.hide ();
478 boost::shared_ptr<Controllable> none;
479 trim_control.set_controllable (none);
484 MixerStrip::set_route (boost::shared_ptr<Route> rt)
486 //the rec/monitor stuff only shows up for tracks.
487 //the show_sends only shows up for buses.
488 //remove them all here, and we may add them back later
489 if (show_sends_button->get_parent()) {
490 rec_mon_table.remove (*show_sends_button);
492 if (rec_enable_button->get_parent()) {
493 rec_mon_table.remove (*rec_enable_button);
495 if (monitor_input_button->get_parent()) {
496 rec_mon_table.remove (*monitor_input_button);
498 if (monitor_disk_button->get_parent()) {
499 rec_mon_table.remove (*monitor_disk_button);
501 if (group_button.get_parent()) {
502 bottom_button_table.remove (group_button);
505 RouteUI::set_route (rt);
507 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
509 /* ProcessorBox needs access to _route so that it can read
512 processor_box.set_route (rt);
514 revert_to_default_display ();
516 /* unpack these from the parent and stuff them into our own
520 if (gpm.peak_display.get_parent()) {
521 gpm.peak_display.get_parent()->remove (gpm.peak_display);
523 if (gpm.gain_display.get_parent()) {
524 gpm.gain_display.get_parent()->remove (gpm.gain_display);
527 gpm.set_type (rt->meter_type());
529 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
530 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
532 if (solo_button->get_parent()) {
533 mute_solo_table.remove (*solo_button);
536 if (mute_button->get_parent()) {
537 mute_solo_table.remove (*mute_button);
540 if (route()->is_master()) {
541 solo_button->hide ();
542 mute_button->show ();
543 rec_mon_table.hide ();
544 solo_iso_table.set_sensitive(false);
545 control_slave_ui.set_sensitive(false);
546 if (monitor_section_button == 0) {
547 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
548 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
550 monitor_section_button = manage (new ArdourButton);
552 monitor_section_button->set_related_action (act);
553 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
554 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
555 monitor_section_button->show();
556 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
558 parameter_changed ("use-monitor-bus");
560 bottom_button_table.attach (group_button, 1, 2, 0, 1);
561 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
562 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
563 mute_button->show ();
564 solo_button->show ();
565 rec_mon_table.show ();
566 solo_iso_table.set_sensitive(true);
567 control_slave_ui.set_sensitive(true);
570 if (_mixer_owned && route()->is_master() ) {
577 monitor_input_button->show ();
578 monitor_disk_button->show ();
580 monitor_input_button->hide();
581 monitor_disk_button->hide ();
584 update_trim_control();
586 if (is_midi_track()) {
587 if (midi_input_enable_button == 0) {
588 midi_input_enable_button = manage (new ArdourButton);
589 midi_input_enable_button->set_name ("midi input button");
590 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
591 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
592 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
593 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
594 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
596 input_button_box.remove (*midi_input_enable_button);
598 /* get current state */
599 midi_input_status_changed ();
600 input_button_box.pack_start (*midi_input_enable_button, false, false);
602 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
604 if (midi_input_enable_button) {
605 /* removal from the container will delete it */
606 input_button_box.remove (*midi_input_enable_button);
607 midi_input_enable_button = 0;
611 if (is_audio_track()) {
612 boost::shared_ptr<AudioTrack> at = audio_track();
613 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
618 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
619 rec_enable_button->show();
621 if (ARDOUR::Profile->get_mixbus()) {
622 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
623 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
624 } else if (ARDOUR::Profile->get_trx()) {
625 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
627 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
628 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
635 if (!_route->is_master()) {
636 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
637 show_sends_button->show();
641 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
643 delete route_ops_menu;
646 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
647 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
648 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
649 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
651 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
653 if (_route->panner_shell()) {
654 update_panner_choices();
655 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
658 if (is_audio_track()) {
659 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
662 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
664 set_stuff_from_route ();
666 /* now force an update of all the various elements */
668 update_mute_display ();
669 update_solo_display ();
672 route_group_changed ();
673 update_track_number_visibility ();
676 panners.setup_pan ();
678 if (has_audio_outputs ()) {
684 update_diskstream_display ();
685 update_input_display ();
686 update_output_display ();
688 add_events (Gdk::BUTTON_RELEASE_MASK);
690 processor_box.show ();
692 if (!route()->is_master() && !route()->is_monitor()) {
693 /* we don't allow master or control routes to be hidden */
698 gpm.reset_peak_display ();
699 gpm.gain_display.show ();
700 gpm.peak_display.show ();
703 width_hide_box.show();
705 global_vpacker.show();
706 mute_solo_table.show();
707 bottom_button_table.show();
709 gpm.meter_point_button.show();
710 input_button_box.show_all();
711 output_button.show();
713 _comment_button.show();
715 gpm.gain_automation_state_button.show();
717 parameter_changed ("mixer-element-visibility");
724 MixerStrip::set_stuff_from_route ()
726 /* if width is not set, it will be set by the MixerUI or editor */
728 string str = gui_property ("strip-width");
730 set_width_enum (Width (string_2_enum (str, _width)), this);
735 MixerStrip::set_width_enum (Width w, void* owner)
737 /* always set the gpm width again, things may be hidden */
740 panners.set_width (w);
742 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
744 _width_owner = owner;
748 if (_width_owner == this) {
749 set_gui_property ("strip-width", enum_2_string (_width));
754 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
759 if (show_sends_button) {
760 show_sends_button->set_text (_("Aux"));
763 gpm.gain_automation_style_button.set_text (
764 gpm.astyle_string(gain_automation->automation_style()));
765 gpm.gain_automation_state_button.set_text (
766 gpm.astate_string(gain_automation->automation_state()));
768 if (_route->panner()) {
769 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
770 panners.astyle_string(_route->panner()->automation_style()));
771 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
772 panners.astate_string(_route->panner()->automation_state()));
776 // panners expect an even number of horiz. pixels
777 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
779 set_size_request (width, -1);
785 if (show_sends_button) {
786 show_sends_button->set_text (_("Snd"));
789 gpm.gain_automation_style_button.set_text (
790 gpm.short_astyle_string(gain_automation->automation_style()));
791 gpm.gain_automation_state_button.set_text (
792 gpm.short_astate_string(gain_automation->automation_state()));
793 gain_meter().setup_meters (); // recalc meter width
795 if (_route->panner()) {
796 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
797 panners.short_astyle_string(_route->panner()->automation_style()));
798 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
799 panners.short_astate_string(_route->panner()->automation_state()));
803 // panners expect an even number of horiz. pixels
804 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
806 set_size_request (width, -1);
811 processor_box.set_width (w);
813 update_input_display ();
814 update_output_display ();
815 setup_comment_button ();
816 route_group_changed ();
822 MixerStrip::set_packed (bool yn)
827 set_gui_property ("visible", true);
829 set_gui_property ("visible", false);
834 struct RouteCompareByName {
835 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
836 return a->name().compare (b->name()) < 0;
841 MixerStrip::output_release (GdkEventButton *ev)
843 switch (ev->button) {
845 edit_output_configuration ();
853 MixerStrip::output_press (GdkEventButton *ev)
855 using namespace Menu_Helpers;
856 if (!_session->engine().connected()) {
857 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
862 MenuList& citems = output_menu.items();
863 switch (ev->button) {
866 return false; //wait for the mouse-up to pop the dialog
870 output_menu.set_name ("ArdourContextMenu");
872 output_menu_bundles.clear ();
874 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
876 citems.push_back (SeparatorElem());
877 uint32_t const n_with_separator = citems.size ();
879 ARDOUR::BundleList current = _route->output()->bundles_connected ();
881 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
883 /* give user bundles first chance at being in the menu */
885 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
886 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
887 maybe_add_bundle_to_output_menu (*i, current);
891 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
892 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
893 maybe_add_bundle_to_output_menu (*i, current);
897 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
898 RouteList copy = *routes;
899 copy.sort (RouteCompareByName ());
900 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
901 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
904 if (citems.size() == n_with_separator) {
905 /* no routes added; remove the separator */
909 if (!ARDOUR::Profile->get_mixbus()) {
910 citems.push_back (SeparatorElem());
912 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
915 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
916 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
922 citems.push_back (SeparatorElem());
923 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
925 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
938 MixerStrip::input_release (GdkEventButton *ev)
940 switch (ev->button) {
943 edit_input_configuration ();
955 MixerStrip::input_press (GdkEventButton *ev)
957 using namespace Menu_Helpers;
959 MenuList& citems = input_menu.items();
960 input_menu.set_name ("ArdourContextMenu");
963 if (!_session->engine().connected()) {
964 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
969 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
972 switch (ev->button) {
975 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
979 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
981 citems.push_back (SeparatorElem());
982 uint32_t const n_with_separator = citems.size ();
984 input_menu_bundles.clear ();
986 ARDOUR::BundleList current = _route->input()->bundles_connected ();
988 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
990 /* give user bundles first chance at being in the menu */
992 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
993 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
994 maybe_add_bundle_to_input_menu (*i, current);
998 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
999 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1000 maybe_add_bundle_to_input_menu (*i, current);
1004 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1005 RouteList copy = *routes;
1006 copy.sort (RouteCompareByName ());
1007 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1008 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1011 if (citems.size() == n_with_separator) {
1012 /* no routes added; remove the separator */
1016 citems.push_back (SeparatorElem());
1017 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1020 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1021 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1026 citems.push_back (SeparatorElem());
1027 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1029 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1041 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1043 if (ignore_toggle) {
1047 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1049 if (std::find (current.begin(), current.end(), c) == current.end()) {
1050 _route->input()->connect_ports_to_bundle (c, true, this);
1052 _route->input()->disconnect_ports_from_bundle (c, this);
1057 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1059 if (ignore_toggle) {
1063 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1065 if (std::find (current.begin(), current.end(), c) == current.end()) {
1066 _route->output()->connect_ports_to_bundle (c, true, this);
1068 _route->output()->disconnect_ports_from_bundle (c, this);
1073 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1075 using namespace Menu_Helpers;
1077 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1081 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1082 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1086 if (i != input_menu_bundles.end()) {
1090 input_menu_bundles.push_back (b);
1092 MenuList& citems = input_menu.items();
1094 std::string n = b->name ();
1095 replace_all (n, "_", " ");
1097 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1101 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1103 using namespace Menu_Helpers;
1105 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1109 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1110 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1114 if (i != output_menu_bundles.end()) {
1118 output_menu_bundles.push_back (b);
1120 MenuList& citems = output_menu.items();
1122 std::string n = b->name ();
1123 replace_all (n, "_", " ");
1125 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1129 MixerStrip::update_diskstream_display ()
1131 if (is_track() && input_selector) {
1132 input_selector->hide_all ();
1135 route_color_changed ();
1139 MixerStrip::connect_to_pan ()
1141 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1143 panstate_connection.disconnect ();
1144 panstyle_connection.disconnect ();
1146 if (!_route->panner()) {
1150 boost::shared_ptr<Pannable> p = _route->pannable ();
1152 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1153 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1155 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1156 * However, that only works a panner was previously set.
1158 * PannerUI must remain subscribed to _panshell->Changed() in case
1159 * we switch the panner eg. AUX-Send and back
1160 * _route->panner_shell()->Changed() vs _panshell->Changed
1162 if (panners._panner == 0) {
1163 panners.panshell_changed ();
1165 update_panner_choices();
1169 MixerStrip::update_panner_choices ()
1171 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1172 if (!_route->panner_shell()) { return; }
1174 uint32_t in = _route->output()->n_ports().n_audio();
1176 if (_route->panner()) {
1177 in = _route->panner()->in().n_audio();
1180 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1184 * Output port labelling
1185 * =====================
1187 * Case 1: Each output has one connection, all connections are to system:playback_%i
1188 * out 1 -> system:playback_1
1189 * out 2 -> system:playback_2
1190 * out 3 -> system:playback_3
1193 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1194 * out 1 -> ardour:track_x/in 1
1195 * out 2 -> ardour:track_x/in 2
1196 * Display as: track_x
1198 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1199 * out 1 -> program x:foo
1200 * out 2 -> program x:foo
1201 * Display as: program x
1203 * Case 4: No connections (Disconnected)
1206 * Default case (unusual routing):
1207 * Display as: *number of connections*
1211 * .-----------------------------------------------.
1213 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1214 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1215 * '-----------------------------------------------'
1216 * .-----------------------------------------------.
1219 * '-----------------------------------------------'
1223 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1227 boost::shared_ptr<IO> io;
1228 boost::shared_ptr<Port> port;
1229 vector<string> port_connections;
1231 uint32_t total_connection_count = 0;
1232 uint32_t io_connection_count = 0;
1233 uint32_t ardour_connection_count = 0;
1234 uint32_t system_connection_count = 0;
1235 uint32_t other_connection_count = 0;
1236 uint32_t typed_connection_count = 0;
1238 ostringstream label;
1240 bool have_label = false;
1241 bool each_io_has_one_connection = true;
1243 string connection_name;
1244 string ardour_track_name;
1245 string other_connection_type;
1246 string system_ports;
1249 ostringstream tooltip;
1250 char * tooltip_cstr;
1252 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1254 * First of all, if the user made only connections to a given type, we should use that one since
1255 * it is very probably what the user expects. If there are several connections types, then show
1256 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1257 * synthesisers. This first heuristic can be expressed with these two rules:
1258 * A) If there are connected audio ports, consider audio as primary type.
1259 * B) Else, if there are connected midi ports, consider midi as primary type.
1261 * If there are no connected ports, then we choose the primary type based on the type of existing
1262 * but unconnected ports. Again:
1263 * C) If there are audio ports, consider audio as primary type.
1264 * D) Else, if there are midi ports, consider midi as primary type. */
1266 DataType dt = DataType::AUDIO;
1270 io = route->input();
1272 io = route->output();
1275 io_count = io->n_ports().n_total();
1276 for (io_index = 0; io_index < io_count; ++io_index) {
1277 port = io->nth (io_index);
1278 if (port->connected()) {
1280 if (port->type() == DataType::AUDIO) {
1281 /* Rule A) applies no matter the remaining ports */
1282 dt = DataType::AUDIO;
1285 if (port->type() == DataType::MIDI) {
1286 /* Rule B) is a good candidate... */
1287 dt = DataType::MIDI;
1288 /* ...but continue the loop to check remaining ports for rule A) */
1294 /* Neither rule A) nor rule B) matched */
1295 if ( io->n_ports().n_audio() > 0 ) {
1297 dt = DataType::AUDIO;
1298 } else if ( io->n_ports().n_midi() > 0 ) {
1300 dt = DataType::MIDI;
1304 if ( dt == DataType::MIDI ) {
1305 tooltip << _("MIDI ");
1309 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1311 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1314 for (io_index = 0; io_index < io_count; ++io_index) {
1315 port = io->nth (io_index);
1317 port_connections.clear ();
1318 port->get_connections(port_connections);
1320 //ignore any port connections that don't match our DataType
1321 if (port->type() != dt) {
1322 if (!port_connections.empty()) {
1323 ++typed_connection_count;
1328 io_connection_count = 0;
1330 if (!port_connections.empty()) {
1331 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1333 string& connection_name (*i);
1335 if (connection_name.find("system:") == 0) {
1336 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1339 if (io_connection_count == 0) {
1340 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1342 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1345 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1348 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1349 if (ardour_track_name.empty()) {
1350 // "ardour:Master/in 1" -> "ardour:Master/"
1351 string::size_type slash = connection_name.find("/");
1352 if (slash != string::npos) {
1353 ardour_track_name = connection_name.substr(0, slash + 1);
1357 if (connection_name.find(ardour_track_name) == 0) {
1358 ++ardour_connection_count;
1360 } else if (!pn.empty()) {
1361 if (system_ports.empty()) {
1364 system_ports += "/" + pn;
1366 if (connection_name.find("system:") == 0) {
1367 ++system_connection_count;
1369 } else if (connection_name.find("system:midi_") == 0) {
1371 // "system:midi_capture_123" -> "123"
1372 system_port = "M " + connection_name.substr(20);
1374 // "system:midi_playback_123" -> "123"
1375 system_port = "M " + connection_name.substr(21);
1378 if (system_ports.empty()) {
1379 system_ports += system_port;
1381 system_ports += "/" + system_port;
1384 ++system_connection_count;
1386 } else if (connection_name.find("system:") == 0) {
1388 // "system:capture_123" -> "123"
1389 system_port = connection_name.substr(15);
1391 // "system:playback_123" -> "123"
1392 system_port = connection_name.substr(16);
1395 if (system_ports.empty()) {
1396 system_ports += system_port;
1398 system_ports += "/" + system_port;
1401 ++system_connection_count;
1403 if (other_connection_type.empty()) {
1404 // "jamin:in 1" -> "jamin:"
1405 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1408 if (connection_name.find(other_connection_type) == 0) {
1409 ++other_connection_count;
1413 ++total_connection_count;
1414 ++io_connection_count;
1418 if (io_connection_count != 1) {
1419 each_io_has_one_connection = false;
1423 if (total_connection_count == 0) {
1424 tooltip << endl << _("Disconnected");
1427 tooltip_cstr = new char[tooltip.str().size() + 1];
1428 strcpy(tooltip_cstr, tooltip.str().c_str());
1431 set_tooltip (&input_button, tooltip_cstr);
1433 set_tooltip (&output_button, tooltip_cstr);
1436 delete [] tooltip_cstr;
1438 if (each_io_has_one_connection) {
1439 if (total_connection_count == ardour_connection_count) {
1440 // all connections are to the same track in ardour
1441 // "ardour:Master/" -> "Master"
1442 string::size_type slash = ardour_track_name.find("/");
1443 if (slash != string::npos) {
1444 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1445 label << ardour_track_name.substr (ppps, slash - ppps);
1449 else if (total_connection_count == system_connection_count) {
1450 // all connections are to system ports
1451 label << system_ports;
1454 else if (total_connection_count == other_connection_count) {
1455 // all connections are to the same external program eg jamin
1456 // "jamin:" -> "jamin"
1457 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1463 if (total_connection_count == 0) {
1467 // Odd configuration
1468 label << "*" << total_connection_count << "*";
1470 if (typed_connection_count > 0) {
1471 label << "\u2295"; // circled plus
1476 input_button.set_text (label.str());
1478 output_button.set_text (label.str());
1483 MixerStrip::update_input_display ()
1485 update_io_button (_route, _width, true);
1486 panners.setup_pan ();
1488 if (has_audio_outputs ()) {
1489 panners.show_all ();
1491 panners.hide_all ();
1497 MixerStrip::update_output_display ()
1499 update_io_button (_route, _width, false);
1500 gpm.setup_meters ();
1501 panners.setup_pan ();
1503 if (has_audio_outputs ()) {
1504 panners.show_all ();
1506 panners.hide_all ();
1511 MixerStrip::fast_update ()
1513 gpm.update_meters ();
1517 MixerStrip::diskstream_changed ()
1519 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1523 MixerStrip::io_changed_proxy ()
1525 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1526 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1530 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1532 boost::shared_ptr<Port> a = wa.lock ();
1533 boost::shared_ptr<Port> b = wb.lock ();
1535 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1536 update_input_display ();
1537 set_width_enum (_width, this);
1540 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1541 update_output_display ();
1542 set_width_enum (_width, this);
1547 MixerStrip::setup_comment_button ()
1549 std::string comment = _route->comment();
1551 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1553 if (comment.empty ()) {
1554 _comment_button.set_name ("generic button");
1555 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1559 _comment_button.set_name ("comment button");
1561 string::size_type pos = comment.find_first_of (" \t\n");
1562 if (pos != string::npos) {
1563 comment = comment.substr (0, pos);
1565 if (comment.empty()) {
1566 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1568 _comment_button.set_text (comment);
1573 MixerStrip::select_route_group (GdkEventButton *ev)
1575 using namespace Menu_Helpers;
1577 if (ev->button == 1) {
1579 if (group_menu == 0) {
1581 PropertyList* plist = new PropertyList();
1583 plist->add (Properties::group_gain, true);
1584 plist->add (Properties::group_mute, true);
1585 plist->add (Properties::group_solo, true);
1587 group_menu = new RouteGroupMenu (_session, plist);
1591 r.push_back (route ());
1592 group_menu->build (r);
1594 RouteGroup *rg = _route->route_group();
1596 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1597 rg ? rg->name() : _("No Group"),
1605 MixerStrip::route_group_changed ()
1607 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1609 RouteGroup *rg = _route->route_group();
1612 group_button.set_text (PBD::short_version (rg->name(), 5));
1616 group_button.set_text (_("Grp"));
1619 group_button.set_text (_("~G"));
1626 MixerStrip::route_color_changed ()
1628 name_button.modify_bg (STATE_NORMAL, color());
1629 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1630 reset_strip_style ();
1634 MixerStrip::show_passthru_color ()
1636 reset_strip_style ();
1641 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1643 boost::shared_ptr<Processor> processor (p.lock ());
1644 if (!processor || !processor->display_to_user()) {
1647 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1649 if (pi && pi->is_channelstrip ()) {
1654 ++_plugin_insert_cnt;
1658 MixerStrip::build_route_ops_menu ()
1660 using namespace Menu_Helpers;
1661 route_ops_menu = new Menu;
1662 route_ops_menu->set_name ("ArdourContextMenu");
1664 MenuList& items = route_ops_menu->items();
1666 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1668 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1670 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1672 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1674 items.push_back (SeparatorElem());
1676 if (!_route->is_master()) {
1677 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1679 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1680 rename_menu_item = &items.back();
1682 items.push_back (SeparatorElem());
1683 items.push_back (CheckMenuElem (_("Active")));
1684 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1685 i->set_active (_route->active());
1686 i->set_sensitive(! _session->transport_rolling());
1687 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1689 if (!Profile->get_mixbus ()) {
1690 items.push_back (SeparatorElem());
1691 items.push_back (CheckMenuElem (_("Strict I/O")));
1692 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1693 i->set_active (_route->strict_io());
1694 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1697 _plugin_insert_cnt = 0;
1698 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1699 if (_plugin_insert_cnt > 0) {
1700 items.push_back (SeparatorElem());
1701 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1704 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1705 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1706 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1707 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1710 items.push_back (SeparatorElem());
1711 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1713 items.push_back (SeparatorElem());
1714 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1715 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1716 denormal_menu_item->set_active (_route->denormal_protection());
1719 /* note that this relies on selection being shared across editor and
1720 mixer (or global to the backend, in the future), which is the only
1721 sane thing for users anyway.
1724 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1726 Selection& selection (PublicEditor::instance().get_selection());
1727 if (!selection.selected (rtav)) {
1728 selection.set (rtav);
1731 if (!_route->is_master()) {
1732 items.push_back (SeparatorElem());
1733 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1736 items.push_back (SeparatorElem());
1737 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1743 MixerStrip::name_button_button_press (GdkEventButton* ev)
1745 if (ev->button == 1 || ev->button == 3) {
1746 list_route_operations ();
1748 /* do not allow rename if the track is record-enabled */
1749 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1750 if (ev->button == 1) {
1751 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1754 route_ops_menu->popup (3, ev->time);
1764 MixerStrip::number_button_button_press (GdkEventButton* ev)
1766 if ( ev->button == 3 ) {
1767 list_route_operations ();
1769 /* do not allow rename if the track is record-enabled */
1770 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1771 route_ops_menu->popup (1, ev->time);
1780 MixerStrip::list_route_operations ()
1782 delete route_ops_menu;
1783 build_route_ops_menu ();
1787 MixerStrip::set_selected (bool yn)
1789 AxisView::set_selected (yn);
1792 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1793 global_frame.set_name ("MixerStripSelectedFrame");
1795 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1796 global_frame.set_name ("MixerStripFrame");
1799 global_frame.queue_draw ();
1802 // processor_box.deselect_all_processors();
1806 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1808 if (what_changed.contains (ARDOUR::Properties::name)) {
1814 MixerStrip::name_changed ()
1818 name_button.set_text (_route->name());
1821 name_button.set_text (PBD::short_version (_route->name(), 5));
1825 set_tooltip (name_button, _route->name());
1827 if (_session->config.get_track_name_number()) {
1828 const int64_t track_number = _route->track_number ();
1829 if (track_number == 0) {
1830 number_label.set_text ("-");
1832 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1835 number_label.set_text ("");
1840 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1842 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1846 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1848 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1852 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1854 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1858 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1860 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1864 MixerStrip::width_button_pressed (GdkEventButton* ev)
1866 if (ev->button != 1) {
1870 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1873 _mixer.set_strip_width (Narrow, true);
1877 _mixer.set_strip_width (Wide, true);
1883 set_width_enum (Narrow, this);
1886 set_width_enum (Wide, this);
1895 MixerStrip::hide_clicked ()
1897 // LAME fix to reset the button status for when it is redisplayed (part 1)
1898 hide_button.set_sensitive(false);
1901 Hiding(); /* EMIT_SIGNAL */
1903 _mixer.hide_strip (this);
1907 hide_button.set_sensitive(true);
1911 MixerStrip::set_embedded (bool yn)
1917 MixerStrip::map_frozen ()
1919 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1921 boost::shared_ptr<AudioTrack> at = audio_track();
1924 switch (at->freeze_state()) {
1925 case AudioTrack::Frozen:
1926 processor_box.set_sensitive (false);
1927 hide_redirect_editors ();
1930 processor_box.set_sensitive (true);
1931 // XXX need some way, maybe, to retoggle redirect editors
1935 processor_box.set_sensitive (true);
1937 RouteUI::map_frozen ();
1941 MixerStrip::hide_redirect_editors ()
1943 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1947 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1949 boost::shared_ptr<Processor> processor (p.lock ());
1954 Gtk::Window* w = processor_box.get_processor_ui (processor);
1962 MixerStrip::reset_strip_style ()
1964 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1966 gpm.set_fader_name ("SendStripBase");
1970 if (is_midi_track()) {
1971 if (_route->active()) {
1972 set_name ("MidiTrackStripBase");
1974 set_name ("MidiTrackStripBaseInactive");
1976 gpm.set_fader_name ("MidiTrackFader");
1977 } else if (is_audio_track()) {
1978 if (_route->active()) {
1979 set_name ("AudioTrackStripBase");
1981 set_name ("AudioTrackStripBaseInactive");
1983 gpm.set_fader_name ("AudioTrackFader");
1985 if (_route->active()) {
1986 set_name ("AudioBusStripBase");
1988 set_name ("AudioBusStripBaseInactive");
1990 gpm.set_fader_name ("AudioBusFader");
1992 /* (no MIDI busses yet) */
1999 MixerStrip::engine_stopped ()
2004 MixerStrip::engine_running ()
2009 MixerStrip::meter_point_string (MeterPoint mp)
2022 case MeterPostFader:
2039 return S_("Meter|In");
2043 return S_("Meter|Pr");
2046 case MeterPostFader:
2047 return S_("Meter|Po");
2051 return S_("Meter|O");
2056 return S_("Meter|C");
2065 /** Called when the monitor-section state */
2067 MixerStrip::monitor_changed ()
2069 assert (monitor_section_button);
2070 if (_session->monitor_active()) {
2071 monitor_section_button->set_name ("master monitor section button active");
2073 monitor_section_button->set_name ("master monitor section button normal");
2077 /** Called when the metering point has changed */
2079 MixerStrip::meter_changed ()
2081 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2082 gpm.setup_meters ();
2083 // reset peak when meter point changes
2084 gpm.reset_peak_display();
2087 /** The bus that we are displaying sends to has changed, or been turned off.
2088 * @param send_to New bus that we are displaying sends to, or 0.
2091 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2093 RouteUI::bus_send_display_changed (send_to);
2096 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2101 revert_to_default_display ();
2104 revert_to_default_display ();
2109 MixerStrip::drop_send ()
2111 boost::shared_ptr<Send> current_send;
2113 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2114 current_send->set_metering (false);
2117 send_gone_connection.disconnect ();
2118 input_button.set_sensitive (true);
2119 output_button.set_sensitive (true);
2120 group_button.set_sensitive (true);
2121 set_invert_sensitive (true);
2122 gpm.meter_point_button.set_sensitive (true);
2123 mute_button->set_sensitive (true);
2124 solo_button->set_sensitive (true);
2125 solo_isolated_led->set_sensitive (true);
2126 solo_safe_led->set_sensitive (true);
2127 monitor_input_button->set_sensitive (true);
2128 monitor_disk_button->set_sensitive (true);
2129 _comment_button.set_sensitive (true);
2130 RouteUI::check_rec_enable_sensitivity ();
2131 set_button_names (); // update solo button visual state
2135 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2137 _current_delivery = d;
2138 DeliveryChanged (_current_delivery);
2142 MixerStrip::show_send (boost::shared_ptr<Send> send)
2148 set_current_delivery (send);
2150 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2151 send->set_metering (true);
2152 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2154 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2155 gain_meter().setup_meters ();
2157 uint32_t const in = _current_delivery->pans_required();
2158 uint32_t const out = _current_delivery->pan_outs();
2160 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2161 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2162 panner_ui().setup_pan ();
2163 panner_ui().set_send_drawing_mode (true);
2164 panner_ui().show_all ();
2166 input_button.set_sensitive (false);
2167 group_button.set_sensitive (false);
2168 set_invert_sensitive (false);
2169 gpm.meter_point_button.set_sensitive (false);
2170 mute_button->set_sensitive (false);
2171 solo_button->set_sensitive (false);
2172 rec_enable_button->set_sensitive (false);
2173 solo_isolated_led->set_sensitive (false);
2174 solo_safe_led->set_sensitive (false);
2175 monitor_input_button->set_sensitive (false);
2176 monitor_disk_button->set_sensitive (false);
2177 _comment_button.set_sensitive (false);
2179 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2180 output_button.set_sensitive (false);
2183 reset_strip_style ();
2187 MixerStrip::revert_to_default_display ()
2191 set_current_delivery (_route->main_outs ());
2193 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2194 gain_meter().setup_meters ();
2196 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2197 update_panner_choices();
2198 panner_ui().setup_pan ();
2199 panner_ui().set_send_drawing_mode (false);
2201 if (has_audio_outputs ()) {
2202 panners.show_all ();
2204 panners.hide_all ();
2207 reset_strip_style ();
2211 MixerStrip::set_button_names ()
2215 mute_button->set_text (_("Mute"));
2216 monitor_input_button->set_text (_("In"));
2217 monitor_disk_button->set_text (_("Disk"));
2218 if (monitor_section_button) {
2219 monitor_section_button->set_text (_("Mon"));
2222 if (_route && _route->solo_safe_control()->solo_safe()) {
2223 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2225 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2227 if (!Config->get_solo_control_is_listen_control()) {
2228 solo_button->set_text (_("Solo"));
2230 switch (Config->get_listen_position()) {
2231 case AfterFaderListen:
2232 solo_button->set_text (_("AFL"));
2234 case PreFaderListen:
2235 solo_button->set_text (_("PFL"));
2239 solo_isolated_led->set_text (_("Iso"));
2240 solo_safe_led->set_text (S_("SoloLock|Lock"));
2244 mute_button->set_text (S_("Mute|M"));
2245 monitor_input_button->set_text (S_("MonitorInput|I"));
2246 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2247 if (monitor_section_button) {
2248 monitor_section_button->set_text (S_("Mon|O"));
2251 if (_route && _route->solo_safe_control()->solo_safe()) {
2252 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2254 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2256 if (!Config->get_solo_control_is_listen_control()) {
2257 solo_button->set_text (S_("Solo|S"));
2259 switch (Config->get_listen_position()) {
2260 case AfterFaderListen:
2261 solo_button->set_text (S_("AfterFader|A"));
2263 case PreFaderListen:
2264 solo_button->set_text (S_("Prefader|P"));
2269 solo_isolated_led->set_text (S_("SoloIso|I"));
2270 solo_safe_led->set_text (S_("SoloLock|L"));
2275 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2277 gpm.meter_point_button.set_text ("");
2282 MixerStrip::plugin_selector()
2284 return _mixer.plugin_selector();
2288 MixerStrip::hide_things ()
2290 processor_box.hide_things ();
2294 MixerStrip::input_active_button_press (GdkEventButton*)
2296 /* nothing happens on press */
2301 MixerStrip::input_active_button_release (GdkEventButton* ev)
2303 boost::shared_ptr<MidiTrack> mt = midi_track ();
2309 boost::shared_ptr<RouteList> rl (new RouteList);
2311 rl->push_back (route());
2313 _session->set_exclusive_input_active (rl, !mt->input_active(),
2314 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2320 MixerStrip::midi_input_status_changed ()
2322 if (midi_input_enable_button) {
2323 boost::shared_ptr<MidiTrack> mt = midi_track ();
2325 midi_input_enable_button->set_active (mt->input_active ());
2330 MixerStrip::state_id () const
2332 return string_compose ("strip %1", _route->id().to_s());
2336 MixerStrip::parameter_changed (string p)
2338 if (p == _visibility.get_state_name()) {
2339 /* The user has made changes to the mixer strip visibility, so get
2340 our VisibilityGroup to reflect these changes in our widgets.
2342 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2343 } else if (p == "track-name-number") {
2345 } else if (p == "use-monitor-bus") {
2346 if (monitor_section_button) {
2347 if (mute_button->get_parent()) {
2348 mute_button->get_parent()->remove(*mute_button);
2350 if (monitor_section_button->get_parent()) {
2351 monitor_section_button->get_parent()->remove(*monitor_section_button);
2353 if (Config->get_use_monitor_bus ()) {
2354 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2355 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2356 mute_button->show();
2357 monitor_section_button->show();
2359 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2360 mute_button->show();
2363 } else if (p == "track-name-number") {
2364 update_track_number_visibility();
2368 /** Called to decide whether the solo isolate / solo lock button visibility should
2369 * be overridden from that configured by the user. We do this for the master bus.
2371 * @return optional value that is present if visibility state should be overridden.
2373 boost::optional<bool>
2374 MixerStrip::override_solo_visibility () const
2376 if (_route && _route->is_master ()) {
2377 return boost::optional<bool> (false);
2380 return boost::optional<bool> ();
2384 MixerStrip::add_input_port (DataType t)
2386 _route->input()->add_port ("", this, t);
2390 MixerStrip::add_output_port (DataType t)
2392 _route->output()->add_port ("", this, t);
2396 MixerStrip::route_active_changed ()
2398 reset_strip_style ();
2402 MixerStrip::copy_processors ()
2404 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2408 MixerStrip::cut_processors ()
2410 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2414 MixerStrip::paste_processors ()
2416 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2420 MixerStrip::select_all_processors ()
2422 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2426 MixerStrip::deselect_all_processors ()
2428 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2432 MixerStrip::delete_processors ()
2434 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2438 MixerStrip::toggle_processors ()
2440 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2444 MixerStrip::ab_plugins ()
2446 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2450 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2452 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2455 if (ev->button == 3) {
2456 popup_level_meter_menu (ev);
2464 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2466 using namespace Gtk::Menu_Helpers;
2468 Gtk::Menu* m = manage (new Menu);
2469 MenuList& items = m->items ();
2471 RadioMenuItem::Group group;
2473 _suspend_menu_callbacks = true;
2474 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2475 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2476 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2477 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2478 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2480 if (gpm.meter_channels().n_audio() == 0) {
2481 m->popup (ev->button, ev->time);
2482 _suspend_menu_callbacks = false;
2486 RadioMenuItem::Group tgroup;
2487 items.push_back (SeparatorElem());
2489 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2490 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2491 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2492 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2493 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2494 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2495 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2496 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2497 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2498 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2499 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2502 if (_route->is_master()) {
2505 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2506 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2507 /* non-master bus */
2510 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2517 MeterType cmt = _route->meter_type();
2518 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2520 items.push_back (SeparatorElem());
2521 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2522 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2523 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2524 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2525 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2526 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2528 m->popup (ev->button, ev->time);
2529 _suspend_menu_callbacks = false;
2533 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2534 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2536 using namespace Menu_Helpers;
2538 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2539 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2540 i->set_active (_route->meter_point() == point);
2544 MixerStrip::set_meter_point (MeterPoint p)
2546 if (_suspend_menu_callbacks) return;
2547 _route->set_meter_point (p);
2551 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2552 RadioMenuItem::Group& group, string const & name, MeterType type)
2554 using namespace Menu_Helpers;
2556 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2557 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2558 i->set_active (_route->meter_type() == type);
2562 MixerStrip::set_meter_type (MeterType t)
2564 if (_suspend_menu_callbacks) return;
2569 MixerStrip::update_track_number_visibility ()
2571 DisplaySuspender ds;
2572 bool show_label = _session->config.get_track_name_number();
2574 if (_route && _route->is_master()) {
2579 number_label.show ();
2580 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2581 // except the width of the number label is subtracted from the name-hbox, so we
2582 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2583 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2585 number_label.set_size_request(tnw, -1);
2586 number_label.show ();
2588 number_label.hide ();
2593 MixerStrip::color () const
2595 return route_color ();
2599 MixerStrip::marked_for_display () const
2601 return !_route->presentation_info().hidden();
2605 MixerStrip::set_marked_for_display (bool yn)
2607 return RouteUI::mark_hidden (!yn);