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);
356 name_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_release), false);
358 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
362 /* start off as a passthru strip. we'll correct this, if necessary,
363 in update_diskstream_display().
366 /* start off as a passthru strip. we'll correct this, if necessary,
367 in update_diskstream_display().
370 if (is_midi_track()) {
371 set_name ("MidiTrackStripBase");
373 set_name ("AudioTrackStripBase");
376 add_events (Gdk::BUTTON_RELEASE_MASK|
377 Gdk::ENTER_NOTIFY_MASK|
378 Gdk::LEAVE_NOTIFY_MASK|
380 Gdk::KEY_RELEASE_MASK);
382 set_flags (get_flags() | Gtk::CAN_FOCUS);
384 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
385 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
388 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
389 must be the same as those used in RCOptionEditor so that the configuration changes
390 are recognised when they occur.
392 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
393 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
394 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
395 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
396 _visibility.add (&output_button, X_("Output"), _("Output"), false);
397 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
398 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
400 parameter_changed (X_("mixer-element-visibility"));
401 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
402 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
403 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
405 //watch for mouse enter/exit so we can do some stuff
406 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
407 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
409 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
412 MixerStrip::~MixerStrip ()
414 CatchDeletion (this);
416 if (this ==_entered_mixer_strip)
417 _entered_mixer_strip = NULL;
421 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
423 _entered_mixer_strip = this;
425 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
426 //because the mixerstrip control is a parent that encompasses the strip
427 deselect_all_processors();
433 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
435 //if we have moved outside our strip, but not into a child view, then deselect ourselves
436 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
437 _entered_mixer_strip= 0;
439 //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
440 gpm.gain_display.set_sensitive(false);
442 gpm.gain_display.set_sensitive(true);
444 //if we leave this mixer strip we need to clear out any selections
445 //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
452 MixerStrip::name() const
455 return _route->name();
461 MixerStrip::set_route (boost::shared_ptr<Route> rt)
463 //the rec/monitor stuff only shows up for tracks.
464 //the show_sends only shows up for buses.
465 //remove them all here, and we may add them back later
466 if (show_sends_button->get_parent()) {
467 rec_mon_table.remove (*show_sends_button);
469 if (rec_enable_button->get_parent()) {
470 rec_mon_table.remove (*rec_enable_button);
472 if (monitor_input_button->get_parent()) {
473 rec_mon_table.remove (*monitor_input_button);
475 if (monitor_disk_button->get_parent()) {
476 rec_mon_table.remove (*monitor_disk_button);
478 if (group_button.get_parent()) {
479 bottom_button_table.remove (group_button);
482 RouteUI::set_route (rt);
484 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
486 /* ProcessorBox needs access to _route so that it can read
489 processor_box.set_route (rt);
491 revert_to_default_display ();
493 /* unpack these from the parent and stuff them into our own
497 if (gpm.peak_display.get_parent()) {
498 gpm.peak_display.get_parent()->remove (gpm.peak_display);
500 if (gpm.gain_display.get_parent()) {
501 gpm.gain_display.get_parent()->remove (gpm.gain_display);
504 gpm.set_type (rt->meter_type());
506 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
507 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
509 if (solo_button->get_parent()) {
510 mute_solo_table.remove (*solo_button);
513 if (mute_button->get_parent()) {
514 mute_solo_table.remove (*mute_button);
517 if (route()->is_master()) {
518 solo_button->hide ();
519 mute_button->show ();
520 rec_mon_table.hide ();
521 if (solo_iso_table.get_parent()) {
522 solo_iso_table.get_parent()->remove(solo_iso_table);
524 if (monitor_section_button == 0) {
525 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
526 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
528 monitor_section_button = manage (new ArdourButton);
530 monitor_section_button->set_related_action (act);
531 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
532 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
533 monitor_section_button->show();
534 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
536 parameter_changed ("use-monitor-bus");
538 bottom_button_table.attach (group_button, 1, 2, 0, 1);
539 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
540 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
541 mute_button->show ();
542 solo_button->show ();
543 rec_mon_table.show ();
546 if (_mixer_owned && route()->is_master() ) {
548 HScrollbar scrollbar;
549 Gtk::Requisition requisition(scrollbar.size_request ());
550 int scrollbar_height = requisition.height;
552 spacer = manage (new EventBox);
553 spacer->set_size_request (-1, scrollbar_height+2);
554 global_vpacker.pack_start (*spacer, false, false);
559 monitor_input_button->show ();
560 monitor_disk_button->show ();
562 monitor_input_button->hide();
563 monitor_disk_button->hide ();
566 if (route()->trim() && route()->trim()->active()) {
567 trim_control.show ();
568 trim_control.set_controllable (route()->trim()->gain_control());
570 trim_control.hide ();
571 boost::shared_ptr<Controllable> none;
572 trim_control.set_controllable (none);
575 if (is_midi_track()) {
576 if (midi_input_enable_button == 0) {
577 midi_input_enable_button = manage (new ArdourButton);
578 midi_input_enable_button->set_name ("midi input button");
579 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
580 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
581 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
582 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
583 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
585 input_button_box.remove (*midi_input_enable_button);
587 /* get current state */
588 midi_input_status_changed ();
589 input_button_box.pack_start (*midi_input_enable_button, false, false);
591 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
593 if (midi_input_enable_button) {
594 /* removal from the container will delete it */
595 input_button_box.remove (*midi_input_enable_button);
596 midi_input_enable_button = 0;
600 if (is_audio_track()) {
601 boost::shared_ptr<AudioTrack> at = audio_track();
602 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
607 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
608 rec_enable_button->show();
610 if (ARDOUR::Profile->get_mixbus()) {
611 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
612 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
613 } else if (ARDOUR::Profile->get_trx()) {
614 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
616 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
617 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
624 if (!_route->is_master()) {
625 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
626 show_sends_button->show();
630 meter_point_button.set_text (meter_point_string (_route->meter_point()));
632 delete route_ops_menu;
635 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
636 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
637 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
638 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
640 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
642 if (_route->panner_shell()) {
643 update_panner_choices();
644 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
647 if (is_audio_track()) {
648 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
651 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
653 set_stuff_from_route ();
655 /* now force an update of all the various elements */
657 update_mute_display ();
658 update_solo_display ();
661 route_group_changed ();
662 update_track_number_visibility ();
665 panners.setup_pan ();
667 if (has_audio_outputs ()) {
673 update_diskstream_display ();
674 update_input_display ();
675 update_output_display ();
677 add_events (Gdk::BUTTON_RELEASE_MASK);
679 processor_box.show ();
681 if (!route()->is_master() && !route()->is_monitor()) {
682 /* we don't allow master or control routes to be hidden */
687 gpm.reset_peak_display ();
688 gpm.gain_display.show ();
689 gpm.peak_display.show ();
692 width_hide_box.show();
694 global_vpacker.show();
695 mute_solo_table.show();
696 bottom_button_table.show();
698 meter_point_button.show();
699 input_button_box.show_all();
700 output_button.show();
702 _comment_button.show();
704 gpm.gain_automation_state_button.show();
706 parameter_changed ("mixer-element-visibility");
713 MixerStrip::set_stuff_from_route ()
715 /* if width is not set, it will be set by the MixerUI or editor */
717 string str = gui_property ("strip-width");
719 set_width_enum (Width (string_2_enum (str, _width)), this);
724 MixerStrip::set_width_enum (Width w, void* owner)
726 /* always set the gpm width again, things may be hidden */
729 panners.set_width (w);
731 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
733 _width_owner = owner;
737 if (_width_owner == this) {
738 set_gui_property ("strip-width", enum_2_string (_width));
743 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
748 if (show_sends_button) {
749 show_sends_button->set_text (_("Aux"));
752 gpm.gain_automation_style_button.set_text (
753 gpm.astyle_string(gain_automation->automation_style()));
754 gpm.gain_automation_state_button.set_text (
755 gpm.astate_string(gain_automation->automation_state()));
757 if (_route->panner()) {
758 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
759 panners.astyle_string(_route->panner()->automation_style()));
760 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
761 panners.astate_string(_route->panner()->automation_state()));
765 // panners expect an even number of horiz. pixels
766 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
768 set_size_request (width, -1);
774 if (show_sends_button) {
775 show_sends_button->set_text (_("Snd"));
778 gpm.gain_automation_style_button.set_text (
779 gpm.short_astyle_string(gain_automation->automation_style()));
780 gpm.gain_automation_state_button.set_text (
781 gpm.short_astate_string(gain_automation->automation_state()));
782 gain_meter().setup_meters (); // recalc meter width
784 if (_route->panner()) {
785 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
786 panners.short_astyle_string(_route->panner()->automation_style()));
787 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
788 panners.short_astate_string(_route->panner()->automation_state()));
792 // panners expect an even number of horiz. pixels
793 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
795 set_size_request (width, -1);
800 processor_box.set_width (w);
802 update_input_display ();
803 update_output_display ();
804 setup_comment_button ();
805 route_group_changed ();
811 MixerStrip::set_packed (bool yn)
816 set_gui_property ("visible", true);
818 set_gui_property ("visible", false);
823 struct RouteCompareByName {
824 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
825 return a->name().compare (b->name()) < 0;
830 MixerStrip::output_release (GdkEventButton *ev)
832 switch (ev->button) {
834 edit_output_configuration ();
842 MixerStrip::output_press (GdkEventButton *ev)
844 using namespace Menu_Helpers;
845 if (!_session->engine().connected()) {
846 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
851 MenuList& citems = output_menu.items();
852 switch (ev->button) {
855 return false; //wait for the mouse-up to pop the dialog
859 output_menu.set_name ("ArdourContextMenu");
861 output_menu_bundles.clear ();
863 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
865 citems.push_back (SeparatorElem());
866 uint32_t const n_with_separator = citems.size ();
868 ARDOUR::BundleList current = _route->output()->bundles_connected ();
870 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
872 /* give user bundles first chance at being in the menu */
874 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
875 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
876 maybe_add_bundle_to_output_menu (*i, current);
880 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
881 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
882 maybe_add_bundle_to_output_menu (*i, current);
886 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
887 RouteList copy = *routes;
888 copy.sort (RouteCompareByName ());
889 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
890 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
893 if (citems.size() == n_with_separator) {
894 /* no routes added; remove the separator */
898 if (!ARDOUR::Profile->get_mixbus()) {
899 citems.push_back (SeparatorElem());
901 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
904 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
905 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
911 citems.push_back (SeparatorElem());
912 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
914 output_menu.popup (1, ev->time);
925 MixerStrip::input_release (GdkEventButton *ev)
927 switch (ev->button) {
930 edit_input_configuration ();
942 MixerStrip::input_press (GdkEventButton *ev)
944 using namespace Menu_Helpers;
946 MenuList& citems = input_menu.items();
947 input_menu.set_name ("ArdourContextMenu");
950 if (!_session->engine().connected()) {
951 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
956 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
959 switch (ev->button) {
962 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
966 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
968 citems.push_back (SeparatorElem());
969 uint32_t const n_with_separator = citems.size ();
971 input_menu_bundles.clear ();
973 ARDOUR::BundleList current = _route->input()->bundles_connected ();
975 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
977 /* give user bundles first chance at being in the menu */
979 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
980 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
981 maybe_add_bundle_to_input_menu (*i, current);
985 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
986 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
987 maybe_add_bundle_to_input_menu (*i, current);
991 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
992 RouteList copy = *routes;
993 copy.sort (RouteCompareByName ());
994 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
995 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
998 if (citems.size() == n_with_separator) {
999 /* no routes added; remove the separator */
1003 citems.push_back (SeparatorElem());
1004 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1007 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1008 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1013 citems.push_back (SeparatorElem());
1014 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1016 input_menu.popup (1, ev->time);
1027 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1029 if (ignore_toggle) {
1033 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1035 if (std::find (current.begin(), current.end(), c) == current.end()) {
1036 _route->input()->connect_ports_to_bundle (c, true, this);
1038 _route->input()->disconnect_ports_from_bundle (c, this);
1043 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1045 if (ignore_toggle) {
1049 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1051 if (std::find (current.begin(), current.end(), c) == current.end()) {
1052 _route->output()->connect_ports_to_bundle (c, true, this);
1054 _route->output()->disconnect_ports_from_bundle (c, this);
1059 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1061 using namespace Menu_Helpers;
1063 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1067 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1068 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1072 if (i != input_menu_bundles.end()) {
1076 input_menu_bundles.push_back (b);
1078 MenuList& citems = input_menu.items();
1080 std::string n = b->name ();
1081 replace_all (n, "_", " ");
1083 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1087 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1089 using namespace Menu_Helpers;
1091 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1095 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1096 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1100 if (i != output_menu_bundles.end()) {
1104 output_menu_bundles.push_back (b);
1106 MenuList& citems = output_menu.items();
1108 std::string n = b->name ();
1109 replace_all (n, "_", " ");
1111 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1115 MixerStrip::update_diskstream_display ()
1117 if (is_track() && input_selector) {
1118 input_selector->hide_all ();
1121 route_color_changed ();
1125 MixerStrip::connect_to_pan ()
1127 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1129 panstate_connection.disconnect ();
1130 panstyle_connection.disconnect ();
1132 if (!_route->panner()) {
1136 boost::shared_ptr<Pannable> p = _route->pannable ();
1138 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1139 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1141 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1142 * However, that only works a panner was previously set.
1144 * PannerUI must remain subscribed to _panshell->Changed() in case
1145 * we switch the panner eg. AUX-Send and back
1146 * _route->panner_shell()->Changed() vs _panshell->Changed
1148 if (panners._panner == 0) {
1149 panners.panshell_changed ();
1151 update_panner_choices();
1155 MixerStrip::update_panner_choices ()
1157 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1158 if (!_route->panner_shell()) { return; }
1160 uint32_t in = _route->output()->n_ports().n_audio();
1162 if (_route->panner()) {
1163 in = _route->panner()->in().n_audio();
1166 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1170 * Output port labelling
1171 * =====================
1173 * Case 1: Each output has one connection, all connections are to system:playback_%i
1174 * out 1 -> system:playback_1
1175 * out 2 -> system:playback_2
1176 * out 3 -> system:playback_3
1179 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1180 * out 1 -> ardour:track_x/in 1
1181 * out 2 -> ardour:track_x/in 2
1182 * Display as: track_x
1184 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1185 * out 1 -> program x:foo
1186 * out 2 -> program x:foo
1187 * Display as: program x
1189 * Case 4: No connections (Disconnected)
1192 * Default case (unusual routing):
1193 * Display as: *number of connections*
1197 * .-----------------------------------------------.
1199 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1200 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1201 * '-----------------------------------------------'
1202 * .-----------------------------------------------.
1205 * '-----------------------------------------------'
1209 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1213 boost::shared_ptr<IO> io;
1214 boost::shared_ptr<Port> port;
1215 vector<string> port_connections;
1217 uint32_t total_connection_count = 0;
1218 uint32_t io_connection_count = 0;
1219 uint32_t ardour_connection_count = 0;
1220 uint32_t system_connection_count = 0;
1221 uint32_t other_connection_count = 0;
1222 uint32_t typed_connection_count = 0;
1224 ostringstream label;
1226 bool have_label = false;
1227 bool each_io_has_one_connection = true;
1229 string connection_name;
1230 string ardour_track_name;
1231 string other_connection_type;
1232 string system_ports;
1235 ostringstream tooltip;
1236 char * tooltip_cstr;
1238 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1240 * First of all, if the user made only connections to a given type, we should use that one since
1241 * it is very probably what the user expects. If there are several connections types, then show
1242 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1243 * synthesisers. This first heuristic can be expressed with these two rules:
1244 * A) If there are connected audio ports, consider audio as primary type.
1245 * B) Else, if there are connected midi ports, consider midi as primary type.
1247 * If there are no connected ports, then we choose the primary type based on the type of existing
1248 * but unconnected ports. Again:
1249 * C) If there are audio ports, consider audio as primary type.
1250 * D) Else, if there are midi ports, consider midi as primary type. */
1252 DataType dt = DataType::AUDIO;
1256 io = route->input();
1258 io = route->output();
1261 io_count = io->n_ports().n_total();
1262 for (io_index = 0; io_index < io_count; ++io_index) {
1263 port = io->nth (io_index);
1264 if (port->connected()) {
1266 if (port->type() == DataType::AUDIO) {
1267 /* Rule A) applies no matter the remaining ports */
1268 dt = DataType::AUDIO;
1271 if (port->type() == DataType::MIDI) {
1272 /* Rule B) is a good candidate... */
1273 dt = DataType::MIDI;
1274 /* ...but continue the loop to check remaining ports for rule A) */
1280 /* Neither rule A) nor rule B) matched */
1281 if ( io->n_ports().n_audio() > 0 ) {
1283 dt = DataType::AUDIO;
1284 } else if ( io->n_ports().n_midi() > 0 ) {
1286 dt = DataType::MIDI;
1290 if ( dt == DataType::MIDI ) {
1291 tooltip << _("MIDI ");
1295 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1297 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1300 for (io_index = 0; io_index < io_count; ++io_index) {
1301 port = io->nth (io_index);
1303 port_connections.clear ();
1304 port->get_connections(port_connections);
1306 //ignore any port connections that don't match our DataType
1307 if (port->type() != dt) {
1308 if (!port_connections.empty()) {
1309 ++typed_connection_count;
1314 io_connection_count = 0;
1316 if (!port_connections.empty()) {
1317 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1319 string& connection_name (*i);
1321 if (connection_name.find("system:") == 0) {
1322 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1325 if (io_connection_count == 0) {
1326 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1328 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1331 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1334 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1335 if (ardour_track_name.empty()) {
1336 // "ardour:Master/in 1" -> "ardour:Master/"
1337 string::size_type slash = connection_name.find("/");
1338 if (slash != string::npos) {
1339 ardour_track_name = connection_name.substr(0, slash + 1);
1343 if (connection_name.find(ardour_track_name) == 0) {
1344 ++ardour_connection_count;
1346 } else if (!pn.empty()) {
1347 if (system_ports.empty()) {
1350 system_ports += "/" + pn;
1352 if (connection_name.find("system:") == 0) {
1353 ++system_connection_count;
1355 } else if (connection_name.find("system:midi_") == 0) {
1357 // "system:midi_capture_123" -> "123"
1358 system_port = "M " + connection_name.substr(20);
1360 // "system:midi_playback_123" -> "123"
1361 system_port = "M " + connection_name.substr(21);
1364 if (system_ports.empty()) {
1365 system_ports += system_port;
1367 system_ports += "/" + system_port;
1370 ++system_connection_count;
1372 } else if (connection_name.find("system:") == 0) {
1374 // "system:capture_123" -> "123"
1375 system_port = connection_name.substr(15);
1377 // "system:playback_123" -> "123"
1378 system_port = connection_name.substr(16);
1381 if (system_ports.empty()) {
1382 system_ports += system_port;
1384 system_ports += "/" + system_port;
1387 ++system_connection_count;
1389 if (other_connection_type.empty()) {
1390 // "jamin:in 1" -> "jamin:"
1391 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1394 if (connection_name.find(other_connection_type) == 0) {
1395 ++other_connection_count;
1399 ++total_connection_count;
1400 ++io_connection_count;
1404 if (io_connection_count != 1) {
1405 each_io_has_one_connection = false;
1409 if (total_connection_count == 0) {
1410 tooltip << endl << _("Disconnected");
1413 tooltip_cstr = new char[tooltip.str().size() + 1];
1414 strcpy(tooltip_cstr, tooltip.str().c_str());
1417 set_tooltip (&input_button, tooltip_cstr);
1419 set_tooltip (&output_button, tooltip_cstr);
1422 delete [] tooltip_cstr;
1424 if (each_io_has_one_connection) {
1425 if (total_connection_count == ardour_connection_count) {
1426 // all connections are to the same track in ardour
1427 // "ardour:Master/" -> "Master"
1428 string::size_type slash = ardour_track_name.find("/");
1429 if (slash != string::npos) {
1430 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1431 label << ardour_track_name.substr (ppps, slash - ppps);
1435 else if (total_connection_count == system_connection_count) {
1436 // all connections are to system ports
1437 label << system_ports;
1440 else if (total_connection_count == other_connection_count) {
1441 // all connections are to the same external program eg jamin
1442 // "jamin:" -> "jamin"
1443 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1449 if (total_connection_count == 0) {
1453 // Odd configuration
1454 label << "*" << total_connection_count << "*";
1456 if (typed_connection_count > 0) {
1457 label << "\u2295"; // circled plus
1462 input_button.set_text (label.str());
1464 output_button.set_text (label.str());
1469 MixerStrip::update_input_display ()
1471 update_io_button (_route, _width, true);
1472 panners.setup_pan ();
1474 if (has_audio_outputs ()) {
1475 panners.show_all ();
1477 panners.hide_all ();
1483 MixerStrip::update_output_display ()
1485 update_io_button (_route, _width, false);
1486 gpm.setup_meters ();
1487 panners.setup_pan ();
1489 if (has_audio_outputs ()) {
1490 panners.show_all ();
1492 panners.hide_all ();
1497 MixerStrip::fast_update ()
1499 gpm.update_meters ();
1503 MixerStrip::diskstream_changed ()
1505 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1509 MixerStrip::io_changed_proxy ()
1511 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1515 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1517 boost::shared_ptr<Port> a = wa.lock ();
1518 boost::shared_ptr<Port> b = wb.lock ();
1520 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1521 update_input_display ();
1522 set_width_enum (_width, this);
1525 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1526 update_output_display ();
1527 set_width_enum (_width, this);
1532 MixerStrip::setup_comment_button ()
1534 std::string comment = _route->comment();
1536 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1538 if (comment.empty ()) {
1539 _comment_button.set_name ("generic button");
1540 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1544 _comment_button.set_name ("comment button");
1546 string::size_type pos = comment.find_first_of (" \t\n");
1547 if (pos != string::npos) {
1548 comment = comment.substr (0, pos);
1550 if (comment.empty()) {
1551 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1553 _comment_button.set_text (comment);
1558 MixerStrip::select_route_group (GdkEventButton *ev)
1560 using namespace Menu_Helpers;
1562 if (ev->button == 1) {
1564 if (group_menu == 0) {
1566 PropertyList* plist = new PropertyList();
1568 plist->add (Properties::group_gain, true);
1569 plist->add (Properties::group_mute, true);
1570 plist->add (Properties::group_solo, true);
1572 group_menu = new RouteGroupMenu (_session, plist);
1576 r.push_back (route ());
1577 group_menu->build (r);
1578 group_menu->menu()->popup (1, ev->time);
1585 MixerStrip::route_group_changed ()
1587 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1589 RouteGroup *rg = _route->route_group();
1592 group_button.set_text (PBD::short_version (rg->name(), 5));
1596 group_button.set_text (_("Grp"));
1599 group_button.set_text (_("~G"));
1606 MixerStrip::route_color_changed ()
1608 name_button.modify_bg (STATE_NORMAL, color());
1609 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1610 reset_strip_style ();
1614 MixerStrip::show_passthru_color ()
1616 reset_strip_style ();
1621 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1623 boost::shared_ptr<Processor> processor (p.lock ());
1624 if (!processor || !processor->display_to_user()) {
1627 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1628 ++_plugin_insert_cnt;
1632 MixerStrip::build_route_ops_menu ()
1634 using namespace Menu_Helpers;
1635 route_ops_menu = new Menu;
1636 route_ops_menu->set_name ("ArdourContextMenu");
1638 MenuList& items = route_ops_menu->items();
1640 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1642 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1644 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1646 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1648 items.push_back (SeparatorElem());
1650 if (!_route->is_master()) {
1651 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1653 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1654 rename_menu_item = &items.back();
1656 items.push_back (SeparatorElem());
1657 items.push_back (CheckMenuElem (_("Active")));
1658 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1659 i->set_active (_route->active());
1660 i->set_sensitive(! _session->transport_rolling());
1661 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1663 if (!Profile->get_mixbus ()) {
1664 items.push_back (SeparatorElem());
1665 items.push_back (CheckMenuElem (_("Strict I/O")));
1666 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1667 i->set_active (_route->strict_io());
1668 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1671 _plugin_insert_cnt = 0;
1672 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1673 if (_plugin_insert_cnt > 0) {
1674 items.push_back (SeparatorElem());
1675 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1678 items.push_back (SeparatorElem());
1679 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1681 items.push_back (SeparatorElem());
1682 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1683 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1684 denormal_menu_item->set_active (_route->denormal_protection());
1687 /* note that this relies on selection being shared across editor and
1688 mixer (or global to the backend, in the future), which is the only
1689 sane thing for users anyway.
1692 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1694 Selection& selection (PublicEditor::instance().get_selection());
1695 if (!selection.selected (rtav)) {
1696 selection.set (rtav);
1699 if (!_route->is_master()) {
1700 items.push_back (SeparatorElem());
1701 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1704 items.push_back (SeparatorElem());
1705 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1711 MixerStrip::name_button_button_press (GdkEventButton* ev)
1713 if (ev->button == 3) {
1714 list_route_operations ();
1716 /* do not allow rename if the track is record-enabled */
1717 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1718 route_ops_menu->popup (1, ev->time);
1727 MixerStrip::name_button_button_release (GdkEventButton* ev)
1729 if (ev->button == 1) {
1730 list_route_operations ();
1732 /* do not allow rename if the track is record-enabled */
1733 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1734 route_ops_menu->popup (1, ev->time);
1741 MixerStrip::number_button_button_press (GdkEventButton* ev)
1743 if ( ev->button == 3 ) {
1744 list_route_operations ();
1746 /* do not allow rename if the track is record-enabled */
1747 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1748 route_ops_menu->popup (1, ev->time);
1757 MixerStrip::list_route_operations ()
1759 delete route_ops_menu;
1760 build_route_ops_menu ();
1764 MixerStrip::set_selected (bool yn)
1766 AxisView::set_selected (yn);
1769 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1770 global_frame.set_name ("MixerStripSelectedFrame");
1772 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1773 global_frame.set_name ("MixerStripFrame");
1776 global_frame.queue_draw ();
1779 // processor_box.deselect_all_processors();
1783 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1785 if (what_changed.contains (ARDOUR::Properties::name)) {
1791 MixerStrip::name_changed ()
1795 name_button.set_text (_route->name());
1798 name_button.set_text (PBD::short_version (_route->name(), 5));
1802 set_tooltip (name_button, _route->name());
1804 if (_session->config.get_track_name_number()) {
1805 const int64_t track_number = _route->track_number ();
1806 if (track_number == 0) {
1807 number_label.set_text ("-");
1809 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1812 number_label.set_text ("");
1817 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1819 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1823 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1825 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1829 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1831 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1835 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1837 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1841 MixerStrip::width_button_pressed (GdkEventButton* ev)
1843 if (ev->button != 1) {
1847 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1850 _mixer.set_strip_width (Narrow, true);
1854 _mixer.set_strip_width (Wide, true);
1860 set_width_enum (Narrow, this);
1863 set_width_enum (Wide, this);
1872 MixerStrip::hide_clicked ()
1874 // LAME fix to reset the button status for when it is redisplayed (part 1)
1875 hide_button.set_sensitive(false);
1878 Hiding(); /* EMIT_SIGNAL */
1880 _mixer.hide_strip (this);
1884 hide_button.set_sensitive(true);
1888 MixerStrip::set_embedded (bool yn)
1894 MixerStrip::map_frozen ()
1896 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1898 boost::shared_ptr<AudioTrack> at = audio_track();
1901 switch (at->freeze_state()) {
1902 case AudioTrack::Frozen:
1903 processor_box.set_sensitive (false);
1904 hide_redirect_editors ();
1907 processor_box.set_sensitive (true);
1908 // XXX need some way, maybe, to retoggle redirect editors
1912 processor_box.set_sensitive (true);
1914 RouteUI::map_frozen ();
1918 MixerStrip::hide_redirect_editors ()
1920 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1924 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1926 boost::shared_ptr<Processor> processor (p.lock ());
1931 Gtk::Window* w = processor_box.get_processor_ui (processor);
1939 MixerStrip::reset_strip_style ()
1941 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1943 gpm.set_fader_name ("SendStripBase");
1947 if (is_midi_track()) {
1948 if (_route->active()) {
1949 set_name ("MidiTrackStripBase");
1951 set_name ("MidiTrackStripBaseInactive");
1953 gpm.set_fader_name ("MidiTrackFader");
1954 } else if (is_audio_track()) {
1955 if (_route->active()) {
1956 set_name ("AudioTrackStripBase");
1958 set_name ("AudioTrackStripBaseInactive");
1960 gpm.set_fader_name ("AudioTrackFader");
1962 if (_route->active()) {
1963 set_name ("AudioBusStripBase");
1965 set_name ("AudioBusStripBaseInactive");
1967 gpm.set_fader_name ("AudioBusFader");
1969 /* (no MIDI busses yet) */
1976 MixerStrip::engine_stopped ()
1981 MixerStrip::engine_running ()
1986 MixerStrip::meter_point_string (MeterPoint mp)
1999 case MeterPostFader:
2016 return S_("Meter|In");
2020 return S_("Meter|Pr");
2023 case MeterPostFader:
2024 return S_("Meter|Po");
2028 return S_("Meter|O");
2033 return S_("Meter|C");
2042 /** Called when the monitor-section state */
2044 MixerStrip::monitor_changed ()
2046 assert (monitor_section_button);
2047 if (_session->monitor_active()) {
2048 monitor_section_button->set_name ("master monitor section button active");
2050 monitor_section_button->set_name ("master monitor section button normal");
2054 /** Called when the metering point has changed */
2056 MixerStrip::meter_changed ()
2058 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2059 gpm.setup_meters ();
2060 // reset peak when meter point changes
2061 gpm.reset_peak_display();
2064 /** The bus that we are displaying sends to has changed, or been turned off.
2065 * @param send_to New bus that we are displaying sends to, or 0.
2068 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2070 RouteUI::bus_send_display_changed (send_to);
2073 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2078 revert_to_default_display ();
2081 revert_to_default_display ();
2086 MixerStrip::drop_send ()
2088 boost::shared_ptr<Send> current_send;
2090 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2091 current_send->set_metering (false);
2094 send_gone_connection.disconnect ();
2095 input_button.set_sensitive (true);
2096 output_button.set_sensitive (true);
2097 group_button.set_sensitive (true);
2098 set_invert_sensitive (true);
2099 meter_point_button.set_sensitive (true);
2100 mute_button->set_sensitive (true);
2101 solo_button->set_sensitive (true);
2102 solo_isolated_led->set_sensitive (true);
2103 solo_safe_led->set_sensitive (true);
2104 monitor_input_button->set_sensitive (true);
2105 monitor_disk_button->set_sensitive (true);
2106 _comment_button.set_sensitive (true);
2107 RouteUI::check_rec_enable_sensitivity ();
2108 set_button_names (); // update solo button visual state
2112 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2114 _current_delivery = d;
2115 DeliveryChanged (_current_delivery);
2119 MixerStrip::show_send (boost::shared_ptr<Send> send)
2125 set_current_delivery (send);
2127 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2128 send->set_metering (true);
2129 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2131 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2132 gain_meter().setup_meters ();
2134 uint32_t const in = _current_delivery->pans_required();
2135 uint32_t const out = _current_delivery->pan_outs();
2137 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2138 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2139 panner_ui().setup_pan ();
2140 panner_ui().set_send_drawing_mode (true);
2141 panner_ui().show_all ();
2143 input_button.set_sensitive (false);
2144 group_button.set_sensitive (false);
2145 set_invert_sensitive (false);
2146 meter_point_button.set_sensitive (false);
2147 mute_button->set_sensitive (false);
2148 solo_button->set_sensitive (false);
2149 rec_enable_button->set_sensitive (false);
2150 solo_isolated_led->set_sensitive (false);
2151 solo_safe_led->set_sensitive (false);
2152 monitor_input_button->set_sensitive (false);
2153 monitor_disk_button->set_sensitive (false);
2154 _comment_button.set_sensitive (false);
2156 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2157 output_button.set_sensitive (false);
2160 reset_strip_style ();
2164 MixerStrip::revert_to_default_display ()
2168 set_current_delivery (_route->main_outs ());
2170 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2171 gain_meter().setup_meters ();
2173 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2174 update_panner_choices();
2175 panner_ui().setup_pan ();
2176 panner_ui().set_send_drawing_mode (false);
2178 if (has_audio_outputs ()) {
2179 panners.show_all ();
2181 panners.hide_all ();
2184 reset_strip_style ();
2188 MixerStrip::set_button_names ()
2192 mute_button->set_text (_("Mute"));
2193 monitor_input_button->set_text (_("In"));
2194 monitor_disk_button->set_text (_("Disk"));
2195 if (monitor_section_button) {
2196 monitor_section_button->set_text (_("Mon"));
2199 if (_route && _route->solo_safe_control()->solo_safe()) {
2200 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2202 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2204 if (!Config->get_solo_control_is_listen_control()) {
2205 solo_button->set_text (_("Solo"));
2207 switch (Config->get_listen_position()) {
2208 case AfterFaderListen:
2209 solo_button->set_text (_("AFL"));
2211 case PreFaderListen:
2212 solo_button->set_text (_("PFL"));
2216 solo_isolated_led->set_text (_("Iso"));
2217 solo_safe_led->set_text (S_("SoloLock|Lock"));
2221 mute_button->set_text (S_("Mute|M"));
2222 monitor_input_button->set_text (S_("MonitorInput|I"));
2223 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2224 if (monitor_section_button) {
2225 monitor_section_button->set_text (S_("Mon|O"));
2228 if (_route && _route->solo_safe_control()->solo_safe()) {
2229 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2231 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2233 if (!Config->get_solo_control_is_listen_control()) {
2234 solo_button->set_text (S_("Solo|S"));
2236 switch (Config->get_listen_position()) {
2237 case AfterFaderListen:
2238 solo_button->set_text (S_("AfterFader|A"));
2240 case PreFaderListen:
2241 solo_button->set_text (S_("Prefader|P"));
2246 solo_isolated_led->set_text (S_("SoloIso|I"));
2247 solo_safe_led->set_text (S_("SoloLock|L"));
2252 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2254 meter_point_button.set_text ("");
2259 MixerStrip::plugin_selector()
2261 return _mixer.plugin_selector();
2265 MixerStrip::hide_things ()
2267 processor_box.hide_things ();
2271 MixerStrip::input_active_button_press (GdkEventButton*)
2273 /* nothing happens on press */
2278 MixerStrip::input_active_button_release (GdkEventButton* ev)
2280 boost::shared_ptr<MidiTrack> mt = midi_track ();
2286 boost::shared_ptr<RouteList> rl (new RouteList);
2288 rl->push_back (route());
2290 _session->set_exclusive_input_active (rl, !mt->input_active(),
2291 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2297 MixerStrip::midi_input_status_changed ()
2299 if (midi_input_enable_button) {
2300 boost::shared_ptr<MidiTrack> mt = midi_track ();
2302 midi_input_enable_button->set_active (mt->input_active ());
2307 MixerStrip::state_id () const
2309 return string_compose ("strip %1", _route->id().to_s());
2313 MixerStrip::parameter_changed (string p)
2315 if (p == _visibility.get_state_name()) {
2316 /* The user has made changes to the mixer strip visibility, so get
2317 our VisibilityGroup to reflect these changes in our widgets.
2319 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2320 } else if (p == "track-name-number") {
2322 } else if (p == "use-monitor-bus") {
2323 if (monitor_section_button) {
2324 if (mute_button->get_parent()) {
2325 mute_button->get_parent()->remove(*mute_button);
2327 if (monitor_section_button->get_parent()) {
2328 monitor_section_button->get_parent()->remove(*monitor_section_button);
2330 if (Config->get_use_monitor_bus ()) {
2331 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2332 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2333 mute_button->show();
2334 monitor_section_button->show();
2336 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2337 mute_button->show();
2340 } else if (p == "track-name-number") {
2341 update_track_number_visibility();
2345 /** Called to decide whether the solo isolate / solo lock button visibility should
2346 * be overridden from that configured by the user. We do this for the master bus.
2348 * @return optional value that is present if visibility state should be overridden.
2350 boost::optional<bool>
2351 MixerStrip::override_solo_visibility () const
2353 if (_route && _route->is_master ()) {
2354 return boost::optional<bool> (false);
2357 return boost::optional<bool> ();
2361 MixerStrip::add_input_port (DataType t)
2363 _route->input()->add_port ("", this, t);
2367 MixerStrip::add_output_port (DataType t)
2369 _route->output()->add_port ("", this, t);
2373 MixerStrip::route_active_changed ()
2375 reset_strip_style ();
2379 MixerStrip::copy_processors ()
2381 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2385 MixerStrip::cut_processors ()
2387 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2391 MixerStrip::paste_processors ()
2393 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2397 MixerStrip::select_all_processors ()
2399 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2403 MixerStrip::deselect_all_processors ()
2405 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2409 MixerStrip::delete_processors ()
2411 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2415 MixerStrip::toggle_processors ()
2417 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2421 MixerStrip::ab_plugins ()
2423 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2427 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2429 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2432 if (ev->button == 3) {
2433 popup_level_meter_menu (ev);
2441 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2443 using namespace Gtk::Menu_Helpers;
2445 Gtk::Menu* m = manage (new Menu);
2446 MenuList& items = m->items ();
2448 RadioMenuItem::Group group;
2450 _suspend_menu_callbacks = true;
2451 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2452 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2453 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2454 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2455 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2457 if (gpm.meter_channels().n_audio() == 0) {
2458 m->popup (ev->button, ev->time);
2459 _suspend_menu_callbacks = false;
2463 RadioMenuItem::Group tgroup;
2464 items.push_back (SeparatorElem());
2466 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2467 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2468 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2469 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2470 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2471 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2472 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2473 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2474 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2475 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2476 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2479 if (_route->is_master()) {
2482 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2483 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2484 /* non-master bus */
2487 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2494 MeterType cmt = _route->meter_type();
2495 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2497 items.push_back (SeparatorElem());
2498 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2499 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2500 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2501 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2502 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2503 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2505 m->popup (ev->button, ev->time);
2506 _suspend_menu_callbacks = false;
2510 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2511 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2513 using namespace Menu_Helpers;
2515 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2516 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2517 i->set_active (_route->meter_point() == point);
2521 MixerStrip::set_meter_point (MeterPoint p)
2523 if (_suspend_menu_callbacks) return;
2524 _route->set_meter_point (p);
2528 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2529 RadioMenuItem::Group& group, string const & name, MeterType type)
2531 using namespace Menu_Helpers;
2533 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2534 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2535 i->set_active (_route->meter_type() == type);
2539 MixerStrip::set_meter_type (MeterType t)
2541 if (_suspend_menu_callbacks) return;
2546 MixerStrip::update_track_number_visibility ()
2548 DisplaySuspender ds;
2549 bool show_label = _session->config.get_track_name_number();
2551 if (_route && _route->is_master()) {
2556 number_label.show ();
2557 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2558 // except the width of the number label is subtracted from the name-hbox, so we
2559 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2560 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2562 number_label.set_size_request(tnw, -1);
2563 number_label.show ();
2565 number_label.hide ();
2570 MixerStrip::color () const
2572 return route_color ();
2576 MixerStrip::marked_for_display () const
2578 return !_route->presentation_info().hidden();
2582 MixerStrip::set_marked_for_display (bool yn)
2584 return RouteUI::mark_hidden (!yn);