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/menu_elems.h"
32 #include "gtkmm2ext/utils.h"
33 #include "gtkmm2ext/choice.h"
34 #include "gtkmm2ext/doi.h"
36 #include "widgets/tooltips.h"
38 #include "ardour/amp.h"
39 #include "ardour/audio_track.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/internal_send.h"
42 #include "ardour/io.h"
43 #include "ardour/meter.h"
44 #include "ardour/midi_track.h"
45 #include "ardour/pannable.h"
46 #include "ardour/panner.h"
47 #include "ardour/panner_shell.h"
48 #include "ardour/panner_manager.h"
49 #include "ardour/port.h"
50 #include "ardour/profile.h"
51 #include "ardour/route.h"
52 #include "ardour/route_group.h"
53 #include "ardour/send.h"
54 #include "ardour/session.h"
55 #include "ardour/types.h"
56 #include "ardour/user_bundle.h"
57 #include "ardour/vca.h"
58 #include "ardour/vca_manager.h"
60 #include "ardour_window.h"
61 #include "enums_convert.h"
62 #include "mixer_strip.h"
65 #include "public_editor.h"
67 #include "io_selector.h"
69 #include "gui_thread.h"
70 #include "route_group_menu.h"
71 #include "meter_patterns.h"
72 #include "ui_config.h"
76 using namespace ARDOUR;
77 using namespace ArdourWidgets;
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::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
432 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
438 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
440 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
446 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
448 _entered_mixer_strip = this;
450 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
451 //because the mixerstrip control is a parent that encompasses the strip
452 deselect_all_processors();
458 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
460 //if we have moved outside our strip, but not into a child view, then deselect ourselves
461 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
462 _entered_mixer_strip= 0;
464 //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
465 gpm.gain_display.set_sensitive(false);
467 gpm.gain_display.set_sensitive(true);
469 //if we leave this mixer strip we need to clear out any selections
470 //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
477 MixerStrip::name() const
480 return _route->name();
486 MixerStrip::update_trim_control ()
488 if (route()->trim() && route()->trim()->active() &&
489 route()->n_inputs().n_audio() > 0) {
490 trim_control.show ();
491 trim_control.set_controllable (route()->trim()->gain_control());
493 trim_control.hide ();
494 boost::shared_ptr<Controllable> none;
495 trim_control.set_controllable (none);
500 MixerStrip::set_route (boost::shared_ptr<Route> rt)
502 //the rec/monitor stuff only shows up for tracks.
503 //the show_sends only shows up for buses.
504 //remove them all here, and we may add them back later
505 if (show_sends_button->get_parent()) {
506 rec_mon_table.remove (*show_sends_button);
508 if (rec_enable_button->get_parent()) {
509 rec_mon_table.remove (*rec_enable_button);
511 if (monitor_input_button->get_parent()) {
512 rec_mon_table.remove (*monitor_input_button);
514 if (monitor_disk_button->get_parent()) {
515 rec_mon_table.remove (*monitor_disk_button);
517 if (group_button.get_parent()) {
518 bottom_button_table.remove (group_button);
521 RouteUI::set_route (rt);
523 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
525 /* ProcessorBox needs access to _route so that it can read
528 processor_box.set_route (rt);
530 revert_to_default_display ();
532 /* unpack these from the parent and stuff them into our own
536 if (gpm.peak_display.get_parent()) {
537 gpm.peak_display.get_parent()->remove (gpm.peak_display);
539 if (gpm.gain_display.get_parent()) {
540 gpm.gain_display.get_parent()->remove (gpm.gain_display);
543 gpm.set_type (rt->meter_type());
545 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
546 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
548 if (solo_button->get_parent()) {
549 mute_solo_table.remove (*solo_button);
552 if (mute_button->get_parent()) {
553 mute_solo_table.remove (*mute_button);
556 if (route()->is_master()) {
557 solo_button->hide ();
558 mute_button->show ();
559 rec_mon_table.hide ();
560 solo_iso_table.set_sensitive(false);
561 control_slave_ui.set_sensitive(false);
562 if (monitor_section_button == 0) {
563 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
564 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
566 monitor_section_button = manage (new ArdourButton);
568 monitor_section_button->set_related_action (act);
569 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
570 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
571 monitor_section_button->show();
572 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
574 parameter_changed ("use-monitor-bus");
576 bottom_button_table.attach (group_button, 1, 2, 0, 1);
577 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
578 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
579 mute_button->show ();
580 solo_button->show ();
581 rec_mon_table.show ();
582 solo_iso_table.set_sensitive(true);
583 control_slave_ui.set_sensitive(true);
586 if (_mixer_owned && route()->is_master() ) {
593 monitor_input_button->show ();
594 monitor_disk_button->show ();
596 monitor_input_button->hide();
597 monitor_disk_button->hide ();
600 update_trim_control();
602 if (is_midi_track()) {
603 if (midi_input_enable_button == 0) {
604 midi_input_enable_button = manage (new ArdourButton);
605 midi_input_enable_button->set_name ("midi input button");
606 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
607 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
608 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
609 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
610 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
612 input_button_box.remove (*midi_input_enable_button);
614 /* get current state */
615 midi_input_status_changed ();
616 input_button_box.pack_start (*midi_input_enable_button, false, false);
618 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
620 if (midi_input_enable_button) {
621 /* removal from the container will delete it */
622 input_button_box.remove (*midi_input_enable_button);
623 midi_input_enable_button = 0;
627 if (is_audio_track()) {
628 boost::shared_ptr<AudioTrack> at = audio_track();
629 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
634 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
635 rec_enable_button->show();
637 if (ARDOUR::Profile->get_mixbus()) {
638 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
639 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
640 } else if (ARDOUR::Profile->get_trx()) {
641 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
643 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
644 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
651 if (!_route->is_master()) {
652 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
653 show_sends_button->show();
657 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
659 delete route_ops_menu;
662 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
663 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
664 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
665 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
667 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
669 if (_route->panner_shell()) {
670 update_panner_choices();
671 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
674 if (is_audio_track()) {
675 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
678 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
680 set_stuff_from_route ();
682 /* now force an update of all the various elements */
684 update_mute_display ();
685 update_solo_display ();
688 route_group_changed ();
689 update_track_number_visibility ();
692 panners.setup_pan ();
694 if (has_audio_outputs ()) {
700 update_diskstream_display ();
701 update_input_display ();
702 update_output_display ();
704 add_events (Gdk::BUTTON_RELEASE_MASK);
706 processor_box.show ();
708 if (!route()->is_master() && !route()->is_monitor()) {
709 /* we don't allow master or control routes to be hidden */
714 gpm.reset_peak_display ();
715 gpm.gain_display.show ();
716 gpm.peak_display.show ();
719 width_hide_box.show();
721 global_vpacker.show();
722 mute_solo_table.show();
723 bottom_button_table.show();
725 gpm.meter_point_button.show();
726 input_button_box.show_all();
727 output_button.show();
729 _comment_button.show();
731 gpm.gain_automation_state_button.show();
733 parameter_changed ("mixer-element-visibility");
740 MixerStrip::set_stuff_from_route ()
742 /* if width is not set, it will be set by the MixerUI or editor */
745 if (get_gui_property ("strip-width", width)) {
746 set_width_enum (width, this);
751 MixerStrip::set_width_enum (Width w, void* owner)
753 /* always set the gpm width again, things may be hidden */
756 panners.set_width (w);
758 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
760 _width_owner = owner;
764 if (_width_owner == this) {
765 set_gui_property ("strip-width", _width);
770 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
775 if (show_sends_button) {
776 show_sends_button->set_text (_("Aux"));
779 gpm.gain_automation_state_button.set_text (
780 gpm.astate_string(gain_automation->automation_state()));
782 if (_route->panner()) {
783 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
784 panners.astate_string(_route->panner()->automation_state()));
788 // panners expect an even number of horiz. pixels
789 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
791 set_size_request (width, -1);
797 if (show_sends_button) {
798 show_sends_button->set_text (_("Snd"));
801 gpm.gain_automation_state_button.set_text (
802 gpm.short_astate_string(gain_automation->automation_state()));
803 gain_meter().setup_meters (); // recalc meter width
805 if (_route->panner()) {
806 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
807 panners.short_astate_string(_route->panner()->automation_state()));
811 // panners expect an even number of horiz. pixels
812 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
814 set_size_request (width, -1);
819 processor_box.set_width (w);
821 update_input_display ();
822 update_output_display ();
823 setup_comment_button ();
824 route_group_changed ();
830 MixerStrip::set_packed (bool yn)
833 set_gui_property ("visible", _packed);
837 struct RouteCompareByName {
838 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
839 return a->name().compare (b->name()) < 0;
844 MixerStrip::output_release (GdkEventButton *ev)
846 switch (ev->button) {
848 edit_output_configuration ();
856 MixerStrip::output_press (GdkEventButton *ev)
858 using namespace Menu_Helpers;
859 if (!_session->engine().connected()) {
860 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
865 MenuList& citems = output_menu.items();
866 switch (ev->button) {
869 return false; //wait for the mouse-up to pop the dialog
873 output_menu.set_name ("ArdourContextMenu");
875 output_menu_bundles.clear ();
877 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
879 citems.push_back (SeparatorElem());
880 uint32_t const n_with_separator = citems.size ();
882 ARDOUR::BundleList current = _route->output()->bundles_connected ();
884 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
886 /* give user bundles first chance at being in the menu */
888 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
889 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
890 maybe_add_bundle_to_output_menu (*i, current);
894 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
895 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
896 maybe_add_bundle_to_output_menu (*i, current);
900 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
901 RouteList copy = *routes;
902 copy.sort (RouteCompareByName ());
903 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
904 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
907 if (citems.size() == n_with_separator) {
908 /* no routes added; remove the separator */
912 if (!ARDOUR::Profile->get_mixbus()) {
913 citems.push_back (SeparatorElem());
915 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
918 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
919 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
925 citems.push_back (SeparatorElem());
926 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
928 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
941 MixerStrip::input_release (GdkEventButton *ev)
943 switch (ev->button) {
946 edit_input_configuration ();
958 MixerStrip::input_press (GdkEventButton *ev)
960 using namespace Menu_Helpers;
962 MenuList& citems = input_menu.items();
963 input_menu.set_name ("ArdourContextMenu");
966 if (!_session->engine().connected()) {
967 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
972 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
975 switch (ev->button) {
978 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
982 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
984 citems.push_back (SeparatorElem());
985 uint32_t const n_with_separator = citems.size ();
987 input_menu_bundles.clear ();
989 ARDOUR::BundleList current = _route->input()->bundles_connected ();
991 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
993 /* give user bundles first chance at being in the menu */
995 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
996 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
997 maybe_add_bundle_to_input_menu (*i, current);
1001 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1002 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1003 maybe_add_bundle_to_input_menu (*i, current);
1007 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1008 RouteList copy = *routes;
1009 copy.sort (RouteCompareByName ());
1010 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1011 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1014 if (citems.size() == n_with_separator) {
1015 /* no routes added; remove the separator */
1019 citems.push_back (SeparatorElem());
1020 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1023 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1024 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1029 citems.push_back (SeparatorElem());
1030 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1032 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1044 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1046 if (ignore_toggle) {
1050 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1052 if (std::find (current.begin(), current.end(), c) == current.end()) {
1053 _route->input()->connect_ports_to_bundle (c, true, this);
1055 _route->input()->disconnect_ports_from_bundle (c, this);
1060 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1062 if (ignore_toggle) {
1066 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1068 if (std::find (current.begin(), current.end(), c) == current.end()) {
1069 _route->output()->connect_ports_to_bundle (c, true, this);
1071 _route->output()->disconnect_ports_from_bundle (c, this);
1076 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1078 using namespace Menu_Helpers;
1080 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1084 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1085 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1089 if (i != input_menu_bundles.end()) {
1093 input_menu_bundles.push_back (b);
1095 MenuList& citems = input_menu.items();
1096 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1100 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1102 using namespace Menu_Helpers;
1104 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1108 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1109 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1113 if (i != output_menu_bundles.end()) {
1117 output_menu_bundles.push_back (b);
1119 MenuList& citems = output_menu.items();
1120 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1124 MixerStrip::update_diskstream_display ()
1126 if (is_track() && input_selector) {
1127 input_selector->hide_all ();
1130 route_color_changed ();
1134 MixerStrip::connect_to_pan ()
1136 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1138 panstate_connection.disconnect ();
1139 panstyle_connection.disconnect ();
1141 if (!_route->panner()) {
1145 boost::shared_ptr<Pannable> p = _route->pannable ();
1147 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1149 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1150 * However, that only works a panner was previously set.
1152 * PannerUI must remain subscribed to _panshell->Changed() in case
1153 * we switch the panner eg. AUX-Send and back
1154 * _route->panner_shell()->Changed() vs _panshell->Changed
1156 if (panners._panner == 0) {
1157 panners.panshell_changed ();
1159 update_panner_choices();
1163 MixerStrip::update_panner_choices ()
1165 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1166 if (!_route->panner_shell()) { return; }
1168 uint32_t in = _route->output()->n_ports().n_audio();
1170 if (_route->panner()) {
1171 in = _route->panner()->in().n_audio();
1174 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1178 * Output port labelling
1179 * =====================
1181 * Case 1: Each output has one connection, all connections are to system:playback_%i
1182 * out 1 -> system:playback_1
1183 * out 2 -> system:playback_2
1184 * out 3 -> system:playback_3
1187 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1188 * out 1 -> ardour:track_x/in 1
1189 * out 2 -> ardour:track_x/in 2
1190 * Display as: track_x
1192 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1193 * out 1 -> program x:foo
1194 * out 2 -> program x:foo
1195 * Display as: program x
1197 * Case 4: No connections (Disconnected)
1200 * Default case (unusual routing):
1201 * Display as: *number of connections*
1205 * .-----------------------------------------------.
1207 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1208 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1209 * '-----------------------------------------------'
1210 * .-----------------------------------------------.
1213 * '-----------------------------------------------'
1217 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1221 boost::shared_ptr<IO> io;
1222 boost::shared_ptr<Port> port;
1223 vector<string> port_connections;
1225 uint32_t total_connection_count = 0;
1226 uint32_t io_connection_count = 0;
1227 uint32_t ardour_connection_count = 0;
1228 uint32_t system_connection_count = 0;
1229 uint32_t other_connection_count = 0;
1230 uint32_t typed_connection_count = 0;
1232 ostringstream label;
1234 bool have_label = false;
1235 bool each_io_has_one_connection = true;
1237 string connection_name;
1238 string ardour_track_name;
1239 string other_connection_type;
1240 string system_ports;
1243 ostringstream tooltip;
1244 char * tooltip_cstr;
1246 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1248 * First of all, if the user made only connections to a given type, we should use that one since
1249 * it is very probably what the user expects. If there are several connections types, then show
1250 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1251 * synthesisers. This first heuristic can be expressed with these two rules:
1252 * A) If there are connected audio ports, consider audio as primary type.
1253 * B) Else, if there are connected midi ports, consider midi as primary type.
1255 * If there are no connected ports, then we choose the primary type based on the type of existing
1256 * but unconnected ports. Again:
1257 * C) If there are audio ports, consider audio as primary type.
1258 * D) Else, if there are midi ports, consider midi as primary type. */
1260 DataType dt = DataType::AUDIO;
1264 io = route->input();
1266 io = route->output();
1269 io_count = io->n_ports().n_total();
1270 for (io_index = 0; io_index < io_count; ++io_index) {
1271 port = io->nth (io_index);
1272 if (port->connected()) {
1274 if (port->type() == DataType::AUDIO) {
1275 /* Rule A) applies no matter the remaining ports */
1276 dt = DataType::AUDIO;
1279 if (port->type() == DataType::MIDI) {
1280 /* Rule B) is a good candidate... */
1281 dt = DataType::MIDI;
1282 /* ...but continue the loop to check remaining ports for rule A) */
1288 /* Neither rule A) nor rule B) matched */
1289 if ( io->n_ports().n_audio() > 0 ) {
1291 dt = DataType::AUDIO;
1292 } else if ( io->n_ports().n_midi() > 0 ) {
1294 dt = DataType::MIDI;
1298 if ( dt == DataType::MIDI ) {
1299 tooltip << _("MIDI ");
1303 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1305 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1308 for (io_index = 0; io_index < io_count; ++io_index) {
1309 port = io->nth (io_index);
1311 port_connections.clear ();
1312 port->get_connections(port_connections);
1314 //ignore any port connections that don't match our DataType
1315 if (port->type() != dt) {
1316 if (!port_connections.empty()) {
1317 ++typed_connection_count;
1322 io_connection_count = 0;
1324 if (!port_connections.empty()) {
1325 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1327 string& connection_name (*i);
1329 if (connection_name.find("system:") == 0) {
1330 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1333 if (io_connection_count == 0) {
1334 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1336 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1339 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1342 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1343 if (ardour_track_name.empty()) {
1344 // "ardour:Master/in 1" -> "ardour:Master/"
1345 string::size_type slash = connection_name.find("/");
1346 if (slash != string::npos) {
1347 ardour_track_name = connection_name.substr(0, slash + 1);
1351 if (connection_name.find(ardour_track_name) == 0) {
1352 ++ardour_connection_count;
1354 } else if (!pn.empty()) {
1355 if (system_ports.empty()) {
1358 system_ports += "/" + pn;
1360 if (connection_name.find("system:") == 0) {
1361 ++system_connection_count;
1363 } else if (connection_name.find("system:midi_") == 0) {
1365 // "system:midi_capture_123" -> "123"
1366 system_port = "M " + connection_name.substr(20);
1368 // "system:midi_playback_123" -> "123"
1369 system_port = "M " + connection_name.substr(21);
1372 if (system_ports.empty()) {
1373 system_ports += system_port;
1375 system_ports += "/" + system_port;
1378 ++system_connection_count;
1380 } else if (connection_name.find("system:") == 0) {
1382 // "system:capture_123" -> "123"
1383 system_port = connection_name.substr(15);
1385 // "system:playback_123" -> "123"
1386 system_port = connection_name.substr(16);
1389 if (system_ports.empty()) {
1390 system_ports += system_port;
1392 system_ports += "/" + system_port;
1395 ++system_connection_count;
1397 if (other_connection_type.empty()) {
1398 // "jamin:in 1" -> "jamin:"
1399 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1402 if (connection_name.find(other_connection_type) == 0) {
1403 ++other_connection_count;
1407 ++total_connection_count;
1408 ++io_connection_count;
1412 if (io_connection_count != 1) {
1413 each_io_has_one_connection = false;
1417 if (total_connection_count == 0) {
1418 tooltip << endl << _("Disconnected");
1421 tooltip_cstr = new char[tooltip.str().size() + 1];
1422 strcpy(tooltip_cstr, tooltip.str().c_str());
1425 set_tooltip (&input_button, tooltip_cstr);
1427 set_tooltip (&output_button, tooltip_cstr);
1430 delete [] tooltip_cstr;
1432 if (each_io_has_one_connection) {
1433 if (total_connection_count == ardour_connection_count) {
1434 // all connections are to the same track in ardour
1435 // "ardour:Master/" -> "Master"
1436 string::size_type slash = ardour_track_name.find("/");
1437 if (slash != string::npos) {
1438 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1439 label << ardour_track_name.substr (ppps, slash - ppps);
1443 else if (total_connection_count == system_connection_count) {
1444 // all connections are to system ports
1445 label << system_ports;
1448 else if (total_connection_count == other_connection_count) {
1449 // all connections are to the same external program eg jamin
1450 // "jamin:" -> "jamin"
1451 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1457 if (total_connection_count == 0) {
1461 // Odd configuration
1462 label << "*" << total_connection_count << "*";
1464 if (typed_connection_count > 0) {
1465 label << "\u2295"; // circled plus
1470 input_button.set_text (label.str());
1472 output_button.set_text (label.str());
1477 MixerStrip::update_input_display ()
1479 update_io_button (_route, _width, true);
1480 panners.setup_pan ();
1482 if (has_audio_outputs ()) {
1483 panners.show_all ();
1485 panners.hide_all ();
1491 MixerStrip::update_output_display ()
1493 update_io_button (_route, _width, false);
1494 gpm.setup_meters ();
1495 panners.setup_pan ();
1497 if (has_audio_outputs ()) {
1498 panners.show_all ();
1500 panners.hide_all ();
1505 MixerStrip::fast_update ()
1507 gpm.update_meters ();
1511 MixerStrip::diskstream_changed ()
1513 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1517 MixerStrip::io_changed_proxy ()
1519 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1520 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1524 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1526 boost::shared_ptr<Port> a = wa.lock ();
1527 boost::shared_ptr<Port> b = wb.lock ();
1529 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1530 update_input_display ();
1531 set_width_enum (_width, this);
1534 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1535 update_output_display ();
1536 set_width_enum (_width, this);
1541 MixerStrip::setup_comment_button ()
1543 std::string comment = _route->comment();
1545 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1547 if (comment.empty ()) {
1548 _comment_button.set_name ("generic button");
1549 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1553 _comment_button.set_name ("comment button");
1555 string::size_type pos = comment.find_first_of (" \t\n");
1556 if (pos != string::npos) {
1557 comment = comment.substr (0, pos);
1559 if (comment.empty()) {
1560 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1562 _comment_button.set_text (comment);
1567 MixerStrip::select_route_group (GdkEventButton *ev)
1569 using namespace Menu_Helpers;
1571 if (ev->button == 1) {
1573 if (group_menu == 0) {
1575 PropertyList* plist = new PropertyList();
1577 plist->add (Properties::group_gain, true);
1578 plist->add (Properties::group_mute, true);
1579 plist->add (Properties::group_solo, true);
1581 group_menu = new RouteGroupMenu (_session, plist);
1585 r.push_back (route ());
1586 group_menu->build (r);
1588 RouteGroup *rg = _route->route_group();
1590 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1591 rg ? rg->name() : _("No Group"),
1599 MixerStrip::route_group_changed ()
1601 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1603 RouteGroup *rg = _route->route_group();
1606 group_button.set_text (PBD::short_version (rg->name(), 5));
1610 group_button.set_text (_("Grp"));
1613 group_button.set_text (_("~G"));
1620 MixerStrip::route_color_changed ()
1622 using namespace ARDOUR_UI_UTILS;
1623 name_button.modify_bg (STATE_NORMAL, color());
1624 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1625 reset_strip_style ();
1629 MixerStrip::show_passthru_color ()
1631 reset_strip_style ();
1636 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1638 boost::shared_ptr<Processor> processor (p.lock ());
1639 if (!processor || !processor->display_to_user()) {
1642 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1644 if (pi && pi->is_channelstrip ()) {
1649 ++_plugin_insert_cnt;
1653 MixerStrip::build_route_ops_menu ()
1655 using namespace Menu_Helpers;
1656 route_ops_menu = new Menu;
1657 route_ops_menu->set_name ("ArdourContextMenu");
1659 MenuList& items = route_ops_menu->items();
1661 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1663 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1665 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1667 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1669 if (!Profile->get_mixbus()) {
1670 items.push_back (SeparatorElem());
1673 if (!_route->is_master()
1675 && !_route->mixbus()
1678 if (Profile->get_mixbus()) {
1679 items.push_back (SeparatorElem());
1681 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1684 if (!Profile->get_mixbus()) {
1685 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1686 /* do not allow rename if the track is record-enabled */
1687 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1690 items.push_back (SeparatorElem());
1691 items.push_back (CheckMenuElem (_("Active")));
1692 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1693 i->set_active (_route->active());
1694 i->set_sensitive(! _session->transport_rolling());
1695 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1697 if (!Profile->get_mixbus ()) {
1698 items.push_back (SeparatorElem());
1699 items.push_back (CheckMenuElem (_("Strict I/O")));
1700 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1701 i->set_active (_route->strict_io());
1702 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1705 _plugin_insert_cnt = 0;
1706 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1707 if (_plugin_insert_cnt > 0) {
1708 items.push_back (SeparatorElem());
1709 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1712 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1713 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1714 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1715 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1718 items.push_back (SeparatorElem());
1719 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1721 items.push_back (SeparatorElem());
1722 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1723 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1724 denormal_menu_item->set_active (_route->denormal_protection());
1727 /* note that this relies on selection being shared across editor and
1728 mixer (or global to the backend, in the future), which is the only
1729 sane thing for users anyway.
1732 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1734 Selection& selection (PublicEditor::instance().get_selection());
1735 if (!selection.selected (rtav)) {
1736 selection.set (rtav);
1739 if (!_route->is_master()) {
1740 items.push_back (SeparatorElem());
1741 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1744 items.push_back (SeparatorElem());
1745 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1751 MixerStrip::name_button_button_press (GdkEventButton* ev)
1753 if (ev->button == 1 || ev->button == 3) {
1754 list_route_operations ();
1756 if (ev->button == 1) {
1757 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1760 route_ops_menu->popup (3, ev->time);
1770 MixerStrip::number_button_button_press (GdkEventButton* ev)
1772 if ( ev->button == 3 ) {
1773 list_route_operations ();
1775 route_ops_menu->popup (1, ev->time);
1784 MixerStrip::list_route_operations ()
1786 delete route_ops_menu;
1787 build_route_ops_menu ();
1791 MixerStrip::set_selected (bool yn)
1793 AxisView::set_selected (yn);
1796 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1797 global_frame.set_name ("MixerStripSelectedFrame");
1799 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1800 global_frame.set_name ("MixerStripFrame");
1803 global_frame.queue_draw ();
1806 // processor_box.deselect_all_processors();
1810 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1812 if (what_changed.contains (ARDOUR::Properties::name)) {
1818 MixerStrip::name_changed ()
1822 name_button.set_text (_route->name());
1825 name_button.set_text (PBD::short_version (_route->name(), 5));
1829 set_tooltip (name_button, _route->name());
1831 if (_session->config.get_track_name_number()) {
1832 const int64_t track_number = _route->track_number ();
1833 if (track_number == 0) {
1834 number_label.set_text ("-");
1836 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1839 number_label.set_text ("");
1844 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1846 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1850 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1852 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1856 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1858 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1862 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1864 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1868 MixerStrip::width_button_pressed (GdkEventButton* ev)
1870 if (ev->button != 1) {
1874 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1877 _mixer.set_strip_width (Narrow, true);
1881 _mixer.set_strip_width (Wide, true);
1887 set_width_enum (Narrow, this);
1890 set_width_enum (Wide, this);
1899 MixerStrip::hide_clicked ()
1901 // LAME fix to reset the button status for when it is redisplayed (part 1)
1902 hide_button.set_sensitive(false);
1905 Hiding(); /* EMIT_SIGNAL */
1907 _mixer.hide_strip (this);
1911 hide_button.set_sensitive(true);
1915 MixerStrip::set_embedded (bool yn)
1921 MixerStrip::map_frozen ()
1923 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1925 boost::shared_ptr<AudioTrack> at = audio_track();
1928 switch (at->freeze_state()) {
1929 case AudioTrack::Frozen:
1930 processor_box.set_sensitive (false);
1931 hide_redirect_editors ();
1934 processor_box.set_sensitive (true);
1935 // XXX need some way, maybe, to retoggle redirect editors
1939 processor_box.set_sensitive (true);
1941 RouteUI::map_frozen ();
1945 MixerStrip::hide_redirect_editors ()
1947 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1951 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1953 boost::shared_ptr<Processor> processor (p.lock ());
1958 Gtk::Window* w = processor_box.get_processor_ui (processor);
1966 MixerStrip::reset_strip_style ()
1968 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1970 gpm.set_fader_name ("SendStripBase");
1974 if (is_midi_track()) {
1975 if (_route->active()) {
1976 set_name ("MidiTrackStripBase");
1978 set_name ("MidiTrackStripBaseInactive");
1980 gpm.set_fader_name ("MidiTrackFader");
1981 } else if (is_audio_track()) {
1982 if (_route->active()) {
1983 set_name ("AudioTrackStripBase");
1985 set_name ("AudioTrackStripBaseInactive");
1987 gpm.set_fader_name ("AudioTrackFader");
1989 if (_route->active()) {
1990 set_name ("AudioBusStripBase");
1992 set_name ("AudioBusStripBaseInactive");
1994 gpm.set_fader_name ("AudioBusFader");
1996 /* (no MIDI busses yet) */
2003 MixerStrip::engine_stopped ()
2008 MixerStrip::engine_running ()
2013 MixerStrip::meter_point_string (MeterPoint mp)
2026 case MeterPostFader:
2043 return S_("Meter|In");
2047 return S_("Meter|Pr");
2050 case MeterPostFader:
2051 return S_("Meter|Po");
2055 return S_("Meter|O");
2060 return S_("Meter|C");
2069 /** Called when the monitor-section state */
2071 MixerStrip::monitor_changed ()
2073 assert (monitor_section_button);
2074 if (_session->monitor_active()) {
2075 monitor_section_button->set_name ("master monitor section button active");
2077 monitor_section_button->set_name ("master monitor section button normal");
2081 /** Called when the metering point has changed */
2083 MixerStrip::meter_changed ()
2085 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2086 gpm.setup_meters ();
2087 // reset peak when meter point changes
2088 gpm.reset_peak_display();
2091 /** The bus that we are displaying sends to has changed, or been turned off.
2092 * @param send_to New bus that we are displaying sends to, or 0.
2095 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2097 RouteUI::bus_send_display_changed (send_to);
2100 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2105 revert_to_default_display ();
2108 revert_to_default_display ();
2113 MixerStrip::drop_send ()
2115 boost::shared_ptr<Send> current_send;
2117 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2118 current_send->set_metering (false);
2121 send_gone_connection.disconnect ();
2122 input_button.set_sensitive (true);
2123 output_button.set_sensitive (true);
2124 group_button.set_sensitive (true);
2125 set_invert_sensitive (true);
2126 gpm.meter_point_button.set_sensitive (true);
2127 mute_button->set_sensitive (true);
2128 solo_button->set_sensitive (true);
2129 solo_isolated_led->set_sensitive (true);
2130 solo_safe_led->set_sensitive (true);
2131 monitor_input_button->set_sensitive (true);
2132 monitor_disk_button->set_sensitive (true);
2133 _comment_button.set_sensitive (true);
2134 RouteUI::check_rec_enable_sensitivity ();
2135 set_button_names (); // update solo button visual state
2139 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2141 _current_delivery = d;
2142 DeliveryChanged (_current_delivery);
2146 MixerStrip::show_send (boost::shared_ptr<Send> send)
2152 set_current_delivery (send);
2154 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2155 send->set_metering (true);
2156 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2158 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2159 gain_meter().setup_meters ();
2161 uint32_t const in = _current_delivery->pans_required();
2162 uint32_t const out = _current_delivery->pan_outs();
2164 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2165 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2166 panner_ui().setup_pan ();
2167 panner_ui().set_send_drawing_mode (true);
2168 panner_ui().show_all ();
2170 input_button.set_sensitive (false);
2171 group_button.set_sensitive (false);
2172 set_invert_sensitive (false);
2173 gpm.meter_point_button.set_sensitive (false);
2174 mute_button->set_sensitive (false);
2175 solo_button->set_sensitive (false);
2176 rec_enable_button->set_sensitive (false);
2177 solo_isolated_led->set_sensitive (false);
2178 solo_safe_led->set_sensitive (false);
2179 monitor_input_button->set_sensitive (false);
2180 monitor_disk_button->set_sensitive (false);
2181 _comment_button.set_sensitive (false);
2183 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2184 output_button.set_sensitive (false);
2187 reset_strip_style ();
2191 MixerStrip::revert_to_default_display ()
2195 set_current_delivery (_route->main_outs ());
2197 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2198 gain_meter().setup_meters ();
2200 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2201 update_panner_choices();
2202 panner_ui().setup_pan ();
2203 panner_ui().set_send_drawing_mode (false);
2205 if (has_audio_outputs ()) {
2206 panners.show_all ();
2208 panners.hide_all ();
2211 reset_strip_style ();
2215 MixerStrip::set_button_names ()
2219 mute_button->set_text (_("Mute"));
2220 monitor_input_button->set_text (_("In"));
2221 monitor_disk_button->set_text (_("Disk"));
2222 if (monitor_section_button) {
2223 monitor_section_button->set_text (_("Mon"));
2226 if (_route && _route->solo_safe_control()->solo_safe()) {
2227 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2229 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2231 if (!Config->get_solo_control_is_listen_control()) {
2232 solo_button->set_text (_("Solo"));
2234 switch (Config->get_listen_position()) {
2235 case AfterFaderListen:
2236 solo_button->set_text (_("AFL"));
2238 case PreFaderListen:
2239 solo_button->set_text (_("PFL"));
2243 solo_isolated_led->set_text (_("Iso"));
2244 solo_safe_led->set_text (S_("SoloLock|Lock"));
2248 mute_button->set_text (S_("Mute|M"));
2249 monitor_input_button->set_text (S_("MonitorInput|I"));
2250 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2251 if (monitor_section_button) {
2252 monitor_section_button->set_text (S_("Mon|O"));
2255 if (_route && _route->solo_safe_control()->solo_safe()) {
2256 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2258 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2260 if (!Config->get_solo_control_is_listen_control()) {
2261 solo_button->set_text (S_("Solo|S"));
2263 switch (Config->get_listen_position()) {
2264 case AfterFaderListen:
2265 solo_button->set_text (S_("AfterFader|A"));
2267 case PreFaderListen:
2268 solo_button->set_text (S_("Prefader|P"));
2273 solo_isolated_led->set_text (S_("SoloIso|I"));
2274 solo_safe_led->set_text (S_("SoloLock|L"));
2279 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2281 gpm.meter_point_button.set_text ("");
2286 MixerStrip::plugin_selector()
2288 return _mixer.plugin_selector();
2292 MixerStrip::hide_things ()
2294 processor_box.hide_things ();
2298 MixerStrip::input_active_button_press (GdkEventButton*)
2300 /* nothing happens on press */
2305 MixerStrip::input_active_button_release (GdkEventButton* ev)
2307 boost::shared_ptr<MidiTrack> mt = midi_track ();
2313 boost::shared_ptr<RouteList> rl (new RouteList);
2315 rl->push_back (route());
2317 _session->set_exclusive_input_active (rl, !mt->input_active(),
2318 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2324 MixerStrip::midi_input_status_changed ()
2326 if (midi_input_enable_button) {
2327 boost::shared_ptr<MidiTrack> mt = midi_track ();
2329 midi_input_enable_button->set_active (mt->input_active ());
2334 MixerStrip::state_id () const
2336 return string_compose ("strip %1", _route->id().to_s());
2340 MixerStrip::parameter_changed (string p)
2342 if (p == _visibility.get_state_name()) {
2343 /* The user has made changes to the mixer strip visibility, so get
2344 our VisibilityGroup to reflect these changes in our widgets.
2346 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2347 } else if (p == "track-name-number") {
2349 } else if (p == "use-monitor-bus") {
2350 if (monitor_section_button) {
2351 if (mute_button->get_parent()) {
2352 mute_button->get_parent()->remove(*mute_button);
2354 if (monitor_section_button->get_parent()) {
2355 monitor_section_button->get_parent()->remove(*monitor_section_button);
2357 if (Config->get_use_monitor_bus ()) {
2358 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2359 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2360 mute_button->show();
2361 monitor_section_button->show();
2363 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2364 mute_button->show();
2367 } else if (p == "track-name-number") {
2368 update_track_number_visibility();
2372 /** Called to decide whether the solo isolate / solo lock button visibility should
2373 * be overridden from that configured by the user. We do this for the master bus.
2375 * @return optional value that is present if visibility state should be overridden.
2377 boost::optional<bool>
2378 MixerStrip::override_solo_visibility () const
2380 if (_route && _route->is_master ()) {
2381 return boost::optional<bool> (false);
2384 return boost::optional<bool> ();
2388 MixerStrip::add_input_port (DataType t)
2390 _route->input()->add_port ("", this, t);
2394 MixerStrip::add_output_port (DataType t)
2396 _route->output()->add_port ("", this, t);
2400 MixerStrip::route_active_changed ()
2402 reset_strip_style ();
2406 MixerStrip::copy_processors ()
2408 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2412 MixerStrip::cut_processors ()
2414 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2418 MixerStrip::paste_processors ()
2420 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2424 MixerStrip::select_all_processors ()
2426 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2430 MixerStrip::deselect_all_processors ()
2432 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2436 MixerStrip::delete_processors ()
2438 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2442 MixerStrip::toggle_processors ()
2444 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2448 MixerStrip::ab_plugins ()
2450 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2454 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2456 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2459 if (ev->button == 3) {
2460 popup_level_meter_menu (ev);
2468 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2470 using namespace Gtk::Menu_Helpers;
2472 Gtk::Menu* m = manage (new Menu);
2473 MenuList& items = m->items ();
2475 RadioMenuItem::Group group;
2477 _suspend_menu_callbacks = true;
2478 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2479 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2480 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2481 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2482 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2484 if (gpm.meter_channels().n_audio() == 0) {
2485 m->popup (ev->button, ev->time);
2486 _suspend_menu_callbacks = false;
2490 RadioMenuItem::Group tgroup;
2491 items.push_back (SeparatorElem());
2493 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2494 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2495 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2496 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2497 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2498 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2499 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2500 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2501 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2502 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2503 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2506 if (_route->is_master()) {
2509 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2510 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2511 /* non-master bus */
2514 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2521 MeterType cmt = _route->meter_type();
2522 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2524 items.push_back (SeparatorElem());
2525 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2526 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2527 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2528 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2529 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2530 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2532 m->popup (ev->button, ev->time);
2533 _suspend_menu_callbacks = false;
2537 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2538 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2540 using namespace Menu_Helpers;
2542 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2543 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2544 i->set_active (_route->meter_point() == point);
2548 MixerStrip::set_meter_point (MeterPoint p)
2550 if (_suspend_menu_callbacks) return;
2551 _route->set_meter_point (p);
2555 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2556 RadioMenuItem::Group& group, string const & name, MeterType type)
2558 using namespace Menu_Helpers;
2560 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2561 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2562 i->set_active (_route->meter_type() == type);
2566 MixerStrip::set_meter_type (MeterType t)
2568 if (_suspend_menu_callbacks) return;
2573 MixerStrip::update_track_number_visibility ()
2575 DisplaySuspender ds;
2576 bool show_label = _session->config.get_track_name_number();
2578 if (_route && _route->is_master()) {
2583 number_label.show ();
2584 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2585 // except the width of the number label is subtracted from the name-hbox, so we
2586 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2587 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2589 number_label.set_size_request(tnw, -1);
2590 number_label.show ();
2592 number_label.hide ();
2597 MixerStrip::color () const
2599 return route_color ();
2603 MixerStrip::marked_for_display () const
2605 return !_route->presentation_info().hidden();
2609 MixerStrip::set_marked_for_display (bool yn)
2611 return RouteUI::mark_hidden (!yn);