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 "enums_convert.h"
61 #include "mixer_strip.h"
64 #include "ardour_button.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"
73 #include "ui_config.h"
77 using namespace ARDOUR;
78 using namespace ARDOUR_UI_UTILS;
81 using namespace Gtkmm2ext;
83 using namespace ArdourMeter;
85 MixerStrip* MixerStrip::_entered_mixer_strip;
86 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
88 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
89 : SessionHandlePtr (sess)
92 , _mixer_owned (in_mixer)
93 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
96 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
97 , rec_mon_table (2, 2)
98 , solo_iso_table (1, 2)
99 , mute_solo_table (1, 2)
100 , bottom_button_table (1, 3)
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 , monitor_section_button (0)
134 , midi_input_enable_button (0)
135 , _plugin_insert_cnt (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;
156 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
157 longest_label = "longest label";
159 string t = _("Click to toggle the width of this mixer strip.");
161 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
164 width_button.set_icon (ArdourIcon::StripWidth);
165 hide_button.set_tweaks (ArdourButton::Square);
166 set_tooltip (width_button, t);
168 hide_button.set_icon (ArdourIcon::CloseCross);
169 hide_button.set_tweaks (ArdourButton::Square);
170 set_tooltip (&hide_button, _("Hide this mixer strip"));
172 input_button_box.set_spacing(2);
174 input_button.set_text (_("Input"));
175 input_button.set_name ("mixer strip button");
176 input_button_box.pack_start (input_button, true, true);
178 output_button.set_text (_("Output"));
179 output_button.set_name ("mixer strip button");
181 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
183 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
185 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
186 solo_isolated_led->show ();
187 solo_isolated_led->set_no_show_all (true);
188 solo_isolated_led->set_name (X_("solo isolate"));
189 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
190 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
191 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
193 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
194 solo_safe_led->show ();
195 solo_safe_led->set_no_show_all (true);
196 solo_safe_led->set_name (X_("solo safe"));
197 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
198 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
199 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
201 solo_safe_led->set_text (S_("SoloLock|Lock"));
202 solo_isolated_led->set_text (_("Iso"));
204 solo_iso_table.set_homogeneous (true);
205 solo_iso_table.set_spacings (2);
206 if (!ARDOUR::Profile->get_trx()) {
207 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
208 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
210 solo_iso_table.show ();
212 rec_mon_table.set_homogeneous (true);
213 rec_mon_table.set_row_spacings (2);
214 rec_mon_table.set_col_spacings (2);
215 if (ARDOUR::Profile->get_mixbus()) {
216 rec_mon_table.resize (1, 3);
217 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
218 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
219 } else if (!ARDOUR::Profile->get_trx()) {
220 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
221 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
223 rec_mon_table.show ();
225 if (solo_isolated_led) {
226 button_size_group->add_widget (*solo_isolated_led);
229 button_size_group->add_widget (*solo_safe_led);
232 if (!ARDOUR::Profile->get_mixbus()) {
233 if (rec_enable_button) {
234 button_size_group->add_widget (*rec_enable_button);
236 if (monitor_disk_button) {
237 button_size_group->add_widget (*monitor_disk_button);
239 if (monitor_input_button) {
240 button_size_group->add_widget (*monitor_input_button);
244 mute_solo_table.set_homogeneous (true);
245 mute_solo_table.set_spacings (2);
247 bottom_button_table.set_spacings (2);
248 bottom_button_table.set_homogeneous (true);
249 bottom_button_table.attach (group_button, 1, 2, 0, 1);
250 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
252 name_button.set_name ("mixer strip button");
253 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
254 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
256 set_tooltip (&group_button, _("Mix group"));
257 group_button.set_name ("mixer strip button");
259 _comment_button.set_name (X_("mixer strip button"));
260 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
262 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
264 // TODO implement ArdourKnob::on_size_request properly
265 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
266 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
268 trim_control.set_tooltip_prefix (_("Trim: "));
269 trim_control.set_name ("trim knob");
270 trim_control.set_no_show_all (true);
271 input_button_box.pack_start (trim_control, false, false);
273 global_vpacker.set_border_width (1);
274 global_vpacker.set_spacing (0);
276 width_button.set_name ("mixer strip button");
277 hide_button.set_name ("mixer strip button");
279 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
280 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
282 width_hide_box.set_spacing (2);
283 width_hide_box.pack_start (width_button, false, true);
284 width_hide_box.pack_start (number_label, true, true);
285 width_hide_box.pack_end (hide_button, false, true);
287 number_label.set_text ("-");
288 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
289 number_label.set_no_show_all ();
290 number_label.set_name ("tracknumber label");
291 number_label.set_fixed_colors (0x80808080, 0x80808080);
292 number_label.set_alignment (.5, .5);
293 number_label.set_fallthrough_to_parent (true);
294 number_label.set_tweaks (ArdourButton::OccasionalText);
296 global_vpacker.set_spacing (2);
297 if (!ARDOUR::Profile->get_trx()) {
298 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
299 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
300 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
301 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
302 global_vpacker.pack_start (processor_box, true, true);
304 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
311 if (!ARDOUR::Profile->get_trx()) {
312 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
319 //add a spacer underneath the master bus;
320 //this fills the area that is taken up by the scrollbar on the tracks;
321 //and therefore keeps the faders "even" across the bottom
322 int scrollbar_height = 0;
324 Gtk::Window window (WINDOW_TOPLEVEL);
325 HScrollbar scrollbar;
326 window.add (scrollbar);
327 scrollbar.set_name ("MixerWindow");
328 scrollbar.ensure_style();
329 Gtk::Requisition requisition(scrollbar.size_request ());
330 scrollbar_height = requisition.height;
332 spacer.set_size_request (-1, scrollbar_height);
333 global_vpacker.pack_end (spacer, false, false);
336 global_frame.add (global_vpacker);
337 global_frame.set_shadow_type (Gtk::SHADOW_IN);
338 global_frame.set_name ("BaseFrame");
342 /* force setting of visible selected status */
345 set_selected (false);
350 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
351 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
353 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
354 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
355 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
357 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
358 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
360 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
361 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
362 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
364 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
366 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
368 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
372 /* start off as a passthru strip. we'll correct this, if necessary,
373 in update_diskstream_display().
376 /* start off as a passthru strip. we'll correct this, if necessary,
377 in update_diskstream_display().
380 if (is_midi_track()) {
381 set_name ("MidiTrackStripBase");
383 set_name ("AudioTrackStripBase");
386 add_events (Gdk::BUTTON_RELEASE_MASK|
387 Gdk::ENTER_NOTIFY_MASK|
388 Gdk::LEAVE_NOTIFY_MASK|
390 Gdk::KEY_RELEASE_MASK);
392 set_flags (get_flags() | Gtk::CAN_FOCUS);
394 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
395 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
398 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
399 must be the same as those used in RCOptionEditor so that the configuration changes
400 are recognised when they occur.
402 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
403 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
404 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
405 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
406 _visibility.add (&output_button, X_("Output"), _("Output"), false);
407 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
408 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
410 parameter_changed (X_("mixer-element-visibility"));
411 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
412 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
413 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
415 //watch for mouse enter/exit so we can do some stuff
416 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
417 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
419 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
422 MixerStrip::~MixerStrip ()
424 CatchDeletion (this);
426 if (this ==_entered_mixer_strip)
427 _entered_mixer_strip = NULL;
431 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
433 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
435 sl->assign(vca, false);
439 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
441 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
447 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
449 _entered_mixer_strip = this;
451 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
452 //because the mixerstrip control is a parent that encompasses the strip
453 deselect_all_processors();
459 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
461 //if we have moved outside our strip, but not into a child view, then deselect ourselves
462 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
463 _entered_mixer_strip= 0;
465 //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
466 gpm.gain_display.set_sensitive(false);
468 gpm.gain_display.set_sensitive(true);
470 //if we leave this mixer strip we need to clear out any selections
471 //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
478 MixerStrip::name() const
481 return _route->name();
487 MixerStrip::update_trim_control ()
489 if (route()->trim() && route()->trim()->active() &&
490 route()->n_inputs().n_audio() > 0) {
491 trim_control.show ();
492 trim_control.set_controllable (route()->trim()->gain_control());
494 trim_control.hide ();
495 boost::shared_ptr<Controllable> none;
496 trim_control.set_controllable (none);
501 MixerStrip::set_route (boost::shared_ptr<Route> rt)
503 //the rec/monitor stuff only shows up for tracks.
504 //the show_sends only shows up for buses.
505 //remove them all here, and we may add them back later
506 if (show_sends_button->get_parent()) {
507 rec_mon_table.remove (*show_sends_button);
509 if (rec_enable_button->get_parent()) {
510 rec_mon_table.remove (*rec_enable_button);
512 if (monitor_input_button->get_parent()) {
513 rec_mon_table.remove (*monitor_input_button);
515 if (monitor_disk_button->get_parent()) {
516 rec_mon_table.remove (*monitor_disk_button);
518 if (group_button.get_parent()) {
519 bottom_button_table.remove (group_button);
522 RouteUI::set_route (rt);
524 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
526 /* ProcessorBox needs access to _route so that it can read
529 processor_box.set_route (rt);
531 revert_to_default_display ();
533 /* unpack these from the parent and stuff them into our own
537 if (gpm.peak_display.get_parent()) {
538 gpm.peak_display.get_parent()->remove (gpm.peak_display);
540 if (gpm.gain_display.get_parent()) {
541 gpm.gain_display.get_parent()->remove (gpm.gain_display);
544 gpm.set_type (rt->meter_type());
546 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
547 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
549 if (solo_button->get_parent()) {
550 mute_solo_table.remove (*solo_button);
553 if (mute_button->get_parent()) {
554 mute_solo_table.remove (*mute_button);
557 if (route()->is_master()) {
558 solo_button->hide ();
559 mute_button->show ();
560 rec_mon_table.hide ();
561 solo_iso_table.set_sensitive(false);
562 control_slave_ui.set_sensitive(false);
563 if (monitor_section_button == 0) {
564 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
565 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
567 monitor_section_button = manage (new ArdourButton);
569 monitor_section_button->set_related_action (act);
570 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
571 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
572 monitor_section_button->show();
573 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
575 parameter_changed ("use-monitor-bus");
577 bottom_button_table.attach (group_button, 1, 2, 0, 1);
578 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
579 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
580 mute_button->show ();
581 solo_button->show ();
582 rec_mon_table.show ();
583 solo_iso_table.set_sensitive(true);
584 control_slave_ui.set_sensitive(true);
587 if (_mixer_owned && route()->is_master() ) {
594 monitor_input_button->show ();
595 monitor_disk_button->show ();
597 monitor_input_button->hide();
598 monitor_disk_button->hide ();
601 update_trim_control();
603 if (is_midi_track()) {
604 if (midi_input_enable_button == 0) {
605 midi_input_enable_button = manage (new ArdourButton);
606 midi_input_enable_button->set_name ("midi input button");
607 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
608 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
609 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
610 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
611 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
613 input_button_box.remove (*midi_input_enable_button);
615 /* get current state */
616 midi_input_status_changed ();
617 input_button_box.pack_start (*midi_input_enable_button, false, false);
619 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
621 if (midi_input_enable_button) {
622 /* removal from the container will delete it */
623 input_button_box.remove (*midi_input_enable_button);
624 midi_input_enable_button = 0;
628 if (is_audio_track()) {
629 boost::shared_ptr<AudioTrack> at = audio_track();
630 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
635 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
636 rec_enable_button->show();
638 if (ARDOUR::Profile->get_mixbus()) {
639 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
640 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
641 } else if (ARDOUR::Profile->get_trx()) {
642 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
644 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
645 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
652 if (!_route->is_master()) {
653 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
654 show_sends_button->show();
658 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
660 delete route_ops_menu;
663 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
664 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
665 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
666 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
668 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
670 if (_route->panner_shell()) {
671 update_panner_choices();
672 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
675 if (is_audio_track()) {
676 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
679 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
681 set_stuff_from_route ();
683 /* now force an update of all the various elements */
685 update_mute_display ();
686 update_solo_display ();
689 route_group_changed ();
690 update_track_number_visibility ();
693 panners.setup_pan ();
695 if (has_audio_outputs ()) {
701 update_diskstream_display ();
702 update_input_display ();
703 update_output_display ();
705 add_events (Gdk::BUTTON_RELEASE_MASK);
707 processor_box.show ();
709 if (!route()->is_master() && !route()->is_monitor()) {
710 /* we don't allow master or control routes to be hidden */
715 gpm.reset_peak_display ();
716 gpm.gain_display.show ();
717 gpm.peak_display.show ();
720 width_hide_box.show();
722 global_vpacker.show();
723 mute_solo_table.show();
724 bottom_button_table.show();
726 gpm.meter_point_button.show();
727 input_button_box.show_all();
728 output_button.show();
730 _comment_button.show();
732 gpm.gain_automation_state_button.show();
734 parameter_changed ("mixer-element-visibility");
741 MixerStrip::set_stuff_from_route ()
743 /* if width is not set, it will be set by the MixerUI or editor */
746 if (get_gui_property ("strip-width", width)) {
747 set_width_enum (width, this);
752 MixerStrip::set_width_enum (Width w, void* owner)
754 /* always set the gpm width again, things may be hidden */
757 panners.set_width (w);
759 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
761 _width_owner = owner;
765 if (_width_owner == this) {
766 set_gui_property ("strip-width", _width);
771 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
776 if (show_sends_button) {
777 show_sends_button->set_text (_("Aux"));
780 gpm.gain_automation_state_button.set_text (
781 gpm.astate_string(gain_automation->automation_state()));
783 if (_route->panner()) {
784 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
785 panners.astate_string(_route->panner()->automation_state()));
789 // panners expect an even number of horiz. pixels
790 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
792 set_size_request (width, -1);
798 if (show_sends_button) {
799 show_sends_button->set_text (_("Snd"));
802 gpm.gain_automation_state_button.set_text (
803 gpm.short_astate_string(gain_automation->automation_state()));
804 gain_meter().setup_meters (); // recalc meter width
806 if (_route->panner()) {
807 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
808 panners.short_astate_string(_route->panner()->automation_state()));
812 // panners expect an even number of horiz. pixels
813 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
815 set_size_request (width, -1);
820 processor_box.set_width (w);
822 update_input_display ();
823 update_output_display ();
824 setup_comment_button ();
825 route_group_changed ();
831 MixerStrip::set_packed (bool yn)
834 set_gui_property ("visible", _packed);
838 struct RouteCompareByName {
839 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
840 return a->name().compare (b->name()) < 0;
845 MixerStrip::output_release (GdkEventButton *ev)
847 switch (ev->button) {
849 edit_output_configuration ();
857 MixerStrip::output_press (GdkEventButton *ev)
859 using namespace Menu_Helpers;
860 if (!_session->engine().connected()) {
861 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
866 MenuList& citems = output_menu.items();
867 switch (ev->button) {
870 return false; //wait for the mouse-up to pop the dialog
874 output_menu.set_name ("ArdourContextMenu");
876 output_menu_bundles.clear ();
878 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
880 citems.push_back (SeparatorElem());
881 uint32_t const n_with_separator = citems.size ();
883 ARDOUR::BundleList current = _route->output()->bundles_connected ();
885 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
887 /* give user bundles first chance at being in the menu */
889 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
890 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
891 maybe_add_bundle_to_output_menu (*i, current);
895 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
896 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
897 maybe_add_bundle_to_output_menu (*i, current);
901 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
902 RouteList copy = *routes;
903 copy.sort (RouteCompareByName ());
904 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
905 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
908 if (citems.size() == n_with_separator) {
909 /* no routes added; remove the separator */
913 if (!ARDOUR::Profile->get_mixbus()) {
914 citems.push_back (SeparatorElem());
916 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
919 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
920 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
926 citems.push_back (SeparatorElem());
927 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
929 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
942 MixerStrip::input_release (GdkEventButton *ev)
944 switch (ev->button) {
947 edit_input_configuration ();
959 MixerStrip::input_press (GdkEventButton *ev)
961 using namespace Menu_Helpers;
963 MenuList& citems = input_menu.items();
964 input_menu.set_name ("ArdourContextMenu");
967 if (!_session->engine().connected()) {
968 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
973 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
976 switch (ev->button) {
979 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
983 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
985 citems.push_back (SeparatorElem());
986 uint32_t const n_with_separator = citems.size ();
988 input_menu_bundles.clear ();
990 ARDOUR::BundleList current = _route->input()->bundles_connected ();
992 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
994 /* give user bundles first chance at being in the menu */
996 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
997 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
998 maybe_add_bundle_to_input_menu (*i, current);
1002 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1003 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1004 maybe_add_bundle_to_input_menu (*i, current);
1008 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1009 RouteList copy = *routes;
1010 copy.sort (RouteCompareByName ());
1011 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1012 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1015 if (citems.size() == n_with_separator) {
1016 /* no routes added; remove the separator */
1020 citems.push_back (SeparatorElem());
1021 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1024 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1025 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1030 citems.push_back (SeparatorElem());
1031 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1033 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1045 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1047 if (ignore_toggle) {
1051 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1053 if (std::find (current.begin(), current.end(), c) == current.end()) {
1054 _route->input()->connect_ports_to_bundle (c, true, this);
1056 _route->input()->disconnect_ports_from_bundle (c, this);
1061 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1063 if (ignore_toggle) {
1067 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1069 if (std::find (current.begin(), current.end(), c) == current.end()) {
1070 _route->output()->connect_ports_to_bundle (c, true, this);
1072 _route->output()->disconnect_ports_from_bundle (c, this);
1077 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1079 using namespace Menu_Helpers;
1081 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1085 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1086 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1090 if (i != input_menu_bundles.end()) {
1094 input_menu_bundles.push_back (b);
1096 MenuList& citems = input_menu.items();
1098 std::string n = b->name ();
1099 replace_all (n, "_", " ");
1101 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1105 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1107 using namespace Menu_Helpers;
1109 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1113 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1114 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1118 if (i != output_menu_bundles.end()) {
1122 output_menu_bundles.push_back (b);
1124 MenuList& citems = output_menu.items();
1126 std::string n = b->name ();
1127 replace_all (n, "_", " ");
1129 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1133 MixerStrip::update_diskstream_display ()
1135 if (is_track() && input_selector) {
1136 input_selector->hide_all ();
1139 route_color_changed ();
1143 MixerStrip::connect_to_pan ()
1145 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1147 panstate_connection.disconnect ();
1148 panstyle_connection.disconnect ();
1150 if (!_route->panner()) {
1154 boost::shared_ptr<Pannable> p = _route->pannable ();
1156 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1158 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1159 * However, that only works a panner was previously set.
1161 * PannerUI must remain subscribed to _panshell->Changed() in case
1162 * we switch the panner eg. AUX-Send and back
1163 * _route->panner_shell()->Changed() vs _panshell->Changed
1165 if (panners._panner == 0) {
1166 panners.panshell_changed ();
1168 update_panner_choices();
1172 MixerStrip::update_panner_choices ()
1174 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1175 if (!_route->panner_shell()) { return; }
1177 uint32_t in = _route->output()->n_ports().n_audio();
1179 if (_route->panner()) {
1180 in = _route->panner()->in().n_audio();
1183 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1187 * Output port labelling
1188 * =====================
1190 * Case 1: Each output has one connection, all connections are to system:playback_%i
1191 * out 1 -> system:playback_1
1192 * out 2 -> system:playback_2
1193 * out 3 -> system:playback_3
1196 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1197 * out 1 -> ardour:track_x/in 1
1198 * out 2 -> ardour:track_x/in 2
1199 * Display as: track_x
1201 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1202 * out 1 -> program x:foo
1203 * out 2 -> program x:foo
1204 * Display as: program x
1206 * Case 4: No connections (Disconnected)
1209 * Default case (unusual routing):
1210 * Display as: *number of connections*
1214 * .-----------------------------------------------.
1216 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1217 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1218 * '-----------------------------------------------'
1219 * .-----------------------------------------------.
1222 * '-----------------------------------------------'
1226 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1230 boost::shared_ptr<IO> io;
1231 boost::shared_ptr<Port> port;
1232 vector<string> port_connections;
1234 uint32_t total_connection_count = 0;
1235 uint32_t io_connection_count = 0;
1236 uint32_t ardour_connection_count = 0;
1237 uint32_t system_connection_count = 0;
1238 uint32_t other_connection_count = 0;
1239 uint32_t typed_connection_count = 0;
1241 ostringstream label;
1243 bool have_label = false;
1244 bool each_io_has_one_connection = true;
1246 string connection_name;
1247 string ardour_track_name;
1248 string other_connection_type;
1249 string system_ports;
1252 ostringstream tooltip;
1253 char * tooltip_cstr;
1255 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1257 * First of all, if the user made only connections to a given type, we should use that one since
1258 * it is very probably what the user expects. If there are several connections types, then show
1259 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1260 * synthesisers. This first heuristic can be expressed with these two rules:
1261 * A) If there are connected audio ports, consider audio as primary type.
1262 * B) Else, if there are connected midi ports, consider midi as primary type.
1264 * If there are no connected ports, then we choose the primary type based on the type of existing
1265 * but unconnected ports. Again:
1266 * C) If there are audio ports, consider audio as primary type.
1267 * D) Else, if there are midi ports, consider midi as primary type. */
1269 DataType dt = DataType::AUDIO;
1273 io = route->input();
1275 io = route->output();
1278 io_count = io->n_ports().n_total();
1279 for (io_index = 0; io_index < io_count; ++io_index) {
1280 port = io->nth (io_index);
1281 if (port->connected()) {
1283 if (port->type() == DataType::AUDIO) {
1284 /* Rule A) applies no matter the remaining ports */
1285 dt = DataType::AUDIO;
1288 if (port->type() == DataType::MIDI) {
1289 /* Rule B) is a good candidate... */
1290 dt = DataType::MIDI;
1291 /* ...but continue the loop to check remaining ports for rule A) */
1297 /* Neither rule A) nor rule B) matched */
1298 if ( io->n_ports().n_audio() > 0 ) {
1300 dt = DataType::AUDIO;
1301 } else if ( io->n_ports().n_midi() > 0 ) {
1303 dt = DataType::MIDI;
1307 if ( dt == DataType::MIDI ) {
1308 tooltip << _("MIDI ");
1312 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1314 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1317 for (io_index = 0; io_index < io_count; ++io_index) {
1318 port = io->nth (io_index);
1320 port_connections.clear ();
1321 port->get_connections(port_connections);
1323 //ignore any port connections that don't match our DataType
1324 if (port->type() != dt) {
1325 if (!port_connections.empty()) {
1326 ++typed_connection_count;
1331 io_connection_count = 0;
1333 if (!port_connections.empty()) {
1334 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1336 string& connection_name (*i);
1338 if (connection_name.find("system:") == 0) {
1339 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1342 if (io_connection_count == 0) {
1343 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1345 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1348 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1351 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1352 if (ardour_track_name.empty()) {
1353 // "ardour:Master/in 1" -> "ardour:Master/"
1354 string::size_type slash = connection_name.find("/");
1355 if (slash != string::npos) {
1356 ardour_track_name = connection_name.substr(0, slash + 1);
1360 if (connection_name.find(ardour_track_name) == 0) {
1361 ++ardour_connection_count;
1363 } else if (!pn.empty()) {
1364 if (system_ports.empty()) {
1367 system_ports += "/" + pn;
1369 if (connection_name.find("system:") == 0) {
1370 ++system_connection_count;
1372 } else if (connection_name.find("system:midi_") == 0) {
1374 // "system:midi_capture_123" -> "123"
1375 system_port = "M " + connection_name.substr(20);
1377 // "system:midi_playback_123" -> "123"
1378 system_port = "M " + connection_name.substr(21);
1381 if (system_ports.empty()) {
1382 system_ports += system_port;
1384 system_ports += "/" + system_port;
1387 ++system_connection_count;
1389 } else if (connection_name.find("system:") == 0) {
1391 // "system:capture_123" -> "123"
1392 system_port = connection_name.substr(15);
1394 // "system:playback_123" -> "123"
1395 system_port = connection_name.substr(16);
1398 if (system_ports.empty()) {
1399 system_ports += system_port;
1401 system_ports += "/" + system_port;
1404 ++system_connection_count;
1406 if (other_connection_type.empty()) {
1407 // "jamin:in 1" -> "jamin:"
1408 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1411 if (connection_name.find(other_connection_type) == 0) {
1412 ++other_connection_count;
1416 ++total_connection_count;
1417 ++io_connection_count;
1421 if (io_connection_count != 1) {
1422 each_io_has_one_connection = false;
1426 if (total_connection_count == 0) {
1427 tooltip << endl << _("Disconnected");
1430 tooltip_cstr = new char[tooltip.str().size() + 1];
1431 strcpy(tooltip_cstr, tooltip.str().c_str());
1434 set_tooltip (&input_button, tooltip_cstr);
1436 set_tooltip (&output_button, tooltip_cstr);
1439 delete [] tooltip_cstr;
1441 if (each_io_has_one_connection) {
1442 if (total_connection_count == ardour_connection_count) {
1443 // all connections are to the same track in ardour
1444 // "ardour:Master/" -> "Master"
1445 string::size_type slash = ardour_track_name.find("/");
1446 if (slash != string::npos) {
1447 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1448 label << ardour_track_name.substr (ppps, slash - ppps);
1452 else if (total_connection_count == system_connection_count) {
1453 // all connections are to system ports
1454 label << system_ports;
1457 else if (total_connection_count == other_connection_count) {
1458 // all connections are to the same external program eg jamin
1459 // "jamin:" -> "jamin"
1460 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1466 if (total_connection_count == 0) {
1470 // Odd configuration
1471 label << "*" << total_connection_count << "*";
1473 if (typed_connection_count > 0) {
1474 label << "\u2295"; // circled plus
1479 input_button.set_text (label.str());
1481 output_button.set_text (label.str());
1486 MixerStrip::update_input_display ()
1488 update_io_button (_route, _width, true);
1489 panners.setup_pan ();
1491 if (has_audio_outputs ()) {
1492 panners.show_all ();
1494 panners.hide_all ();
1500 MixerStrip::update_output_display ()
1502 update_io_button (_route, _width, false);
1503 gpm.setup_meters ();
1504 panners.setup_pan ();
1506 if (has_audio_outputs ()) {
1507 panners.show_all ();
1509 panners.hide_all ();
1514 MixerStrip::fast_update ()
1516 gpm.update_meters ();
1520 MixerStrip::diskstream_changed ()
1522 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1526 MixerStrip::io_changed_proxy ()
1528 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1529 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1533 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1535 boost::shared_ptr<Port> a = wa.lock ();
1536 boost::shared_ptr<Port> b = wb.lock ();
1538 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1539 update_input_display ();
1540 set_width_enum (_width, this);
1543 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1544 update_output_display ();
1545 set_width_enum (_width, this);
1550 MixerStrip::setup_comment_button ()
1552 std::string comment = _route->comment();
1554 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1556 if (comment.empty ()) {
1557 _comment_button.set_name ("generic button");
1558 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1562 _comment_button.set_name ("comment button");
1564 string::size_type pos = comment.find_first_of (" \t\n");
1565 if (pos != string::npos) {
1566 comment = comment.substr (0, pos);
1568 if (comment.empty()) {
1569 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1571 _comment_button.set_text (comment);
1576 MixerStrip::select_route_group (GdkEventButton *ev)
1578 using namespace Menu_Helpers;
1580 if (ev->button == 1) {
1582 if (group_menu == 0) {
1584 PropertyList* plist = new PropertyList();
1586 plist->add (Properties::group_gain, true);
1587 plist->add (Properties::group_mute, true);
1588 plist->add (Properties::group_solo, true);
1590 group_menu = new RouteGroupMenu (_session, plist);
1594 r.push_back (route ());
1595 group_menu->build (r);
1597 RouteGroup *rg = _route->route_group();
1599 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1600 rg ? rg->name() : _("No Group"),
1608 MixerStrip::route_group_changed ()
1610 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1612 RouteGroup *rg = _route->route_group();
1615 group_button.set_text (PBD::short_version (rg->name(), 5));
1619 group_button.set_text (_("Grp"));
1622 group_button.set_text (_("~G"));
1629 MixerStrip::route_color_changed ()
1631 name_button.modify_bg (STATE_NORMAL, color());
1632 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1633 reset_strip_style ();
1637 MixerStrip::show_passthru_color ()
1639 reset_strip_style ();
1644 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1646 boost::shared_ptr<Processor> processor (p.lock ());
1647 if (!processor || !processor->display_to_user()) {
1650 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1652 if (pi && pi->is_channelstrip ()) {
1657 ++_plugin_insert_cnt;
1661 MixerStrip::build_route_ops_menu ()
1663 using namespace Menu_Helpers;
1664 route_ops_menu = new Menu;
1665 route_ops_menu->set_name ("ArdourContextMenu");
1667 MenuList& items = route_ops_menu->items();
1669 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1671 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1673 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1675 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1677 if (!Profile->get_mixbus()) {
1678 items.push_back (SeparatorElem());
1681 if (!_route->is_master()
1683 && !_route->mixbus()
1686 if (Profile->get_mixbus()) {
1687 items.push_back (SeparatorElem());
1689 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1692 if (!Profile->get_mixbus()) {
1693 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1694 /* do not allow rename if the track is record-enabled */
1695 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1698 items.push_back (SeparatorElem());
1699 items.push_back (CheckMenuElem (_("Active")));
1700 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1701 i->set_active (_route->active());
1702 i->set_sensitive(! _session->transport_rolling());
1703 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1705 if (!Profile->get_mixbus ()) {
1706 items.push_back (SeparatorElem());
1707 items.push_back (CheckMenuElem (_("Strict I/O")));
1708 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1709 i->set_active (_route->strict_io());
1710 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1713 _plugin_insert_cnt = 0;
1714 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1715 if (_plugin_insert_cnt > 0) {
1716 items.push_back (SeparatorElem());
1717 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1720 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1721 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1722 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1723 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1726 items.push_back (SeparatorElem());
1727 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1729 items.push_back (SeparatorElem());
1730 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1731 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1732 denormal_menu_item->set_active (_route->denormal_protection());
1735 /* note that this relies on selection being shared across editor and
1736 mixer (or global to the backend, in the future), which is the only
1737 sane thing for users anyway.
1740 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1742 Selection& selection (PublicEditor::instance().get_selection());
1743 if (!selection.selected (rtav)) {
1744 selection.set (rtav);
1747 if (!_route->is_master()) {
1748 items.push_back (SeparatorElem());
1749 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1752 items.push_back (SeparatorElem());
1753 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1759 MixerStrip::name_button_button_press (GdkEventButton* ev)
1761 if (ev->button == 1 || ev->button == 3) {
1762 list_route_operations ();
1764 if (ev->button == 1) {
1765 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1768 route_ops_menu->popup (3, ev->time);
1778 MixerStrip::number_button_button_press (GdkEventButton* ev)
1780 if ( ev->button == 3 ) {
1781 list_route_operations ();
1783 route_ops_menu->popup (1, ev->time);
1792 MixerStrip::list_route_operations ()
1794 delete route_ops_menu;
1795 build_route_ops_menu ();
1799 MixerStrip::set_selected (bool yn)
1801 AxisView::set_selected (yn);
1804 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1805 global_frame.set_name ("MixerStripSelectedFrame");
1807 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1808 global_frame.set_name ("MixerStripFrame");
1811 global_frame.queue_draw ();
1814 // processor_box.deselect_all_processors();
1818 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1820 if (what_changed.contains (ARDOUR::Properties::name)) {
1826 MixerStrip::name_changed ()
1830 name_button.set_text (_route->name());
1833 name_button.set_text (PBD::short_version (_route->name(), 5));
1837 set_tooltip (name_button, _route->name());
1839 if (_session->config.get_track_name_number()) {
1840 const int64_t track_number = _route->track_number ();
1841 if (track_number == 0) {
1842 number_label.set_text ("-");
1844 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1847 number_label.set_text ("");
1852 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1854 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1858 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1860 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1864 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1866 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1870 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1872 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1876 MixerStrip::width_button_pressed (GdkEventButton* ev)
1878 if (ev->button != 1) {
1882 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1885 _mixer.set_strip_width (Narrow, true);
1889 _mixer.set_strip_width (Wide, true);
1895 set_width_enum (Narrow, this);
1898 set_width_enum (Wide, this);
1907 MixerStrip::hide_clicked ()
1909 // LAME fix to reset the button status for when it is redisplayed (part 1)
1910 hide_button.set_sensitive(false);
1913 Hiding(); /* EMIT_SIGNAL */
1915 _mixer.hide_strip (this);
1919 hide_button.set_sensitive(true);
1923 MixerStrip::set_embedded (bool yn)
1929 MixerStrip::map_frozen ()
1931 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1933 boost::shared_ptr<AudioTrack> at = audio_track();
1936 switch (at->freeze_state()) {
1937 case AudioTrack::Frozen:
1938 processor_box.set_sensitive (false);
1939 hide_redirect_editors ();
1942 processor_box.set_sensitive (true);
1943 // XXX need some way, maybe, to retoggle redirect editors
1947 processor_box.set_sensitive (true);
1949 RouteUI::map_frozen ();
1953 MixerStrip::hide_redirect_editors ()
1955 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1959 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1961 boost::shared_ptr<Processor> processor (p.lock ());
1966 Gtk::Window* w = processor_box.get_processor_ui (processor);
1974 MixerStrip::reset_strip_style ()
1976 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1978 gpm.set_fader_name ("SendStripBase");
1982 if (is_midi_track()) {
1983 if (_route->active()) {
1984 set_name ("MidiTrackStripBase");
1986 set_name ("MidiTrackStripBaseInactive");
1988 gpm.set_fader_name ("MidiTrackFader");
1989 } else if (is_audio_track()) {
1990 if (_route->active()) {
1991 set_name ("AudioTrackStripBase");
1993 set_name ("AudioTrackStripBaseInactive");
1995 gpm.set_fader_name ("AudioTrackFader");
1997 if (_route->active()) {
1998 set_name ("AudioBusStripBase");
2000 set_name ("AudioBusStripBaseInactive");
2002 gpm.set_fader_name ("AudioBusFader");
2004 /* (no MIDI busses yet) */
2011 MixerStrip::engine_stopped ()
2016 MixerStrip::engine_running ()
2021 MixerStrip::meter_point_string (MeterPoint mp)
2034 case MeterPostFader:
2051 return S_("Meter|In");
2055 return S_("Meter|Pr");
2058 case MeterPostFader:
2059 return S_("Meter|Po");
2063 return S_("Meter|O");
2068 return S_("Meter|C");
2077 /** Called when the monitor-section state */
2079 MixerStrip::monitor_changed ()
2081 assert (monitor_section_button);
2082 if (_session->monitor_active()) {
2083 monitor_section_button->set_name ("master monitor section button active");
2085 monitor_section_button->set_name ("master monitor section button normal");
2089 /** Called when the metering point has changed */
2091 MixerStrip::meter_changed ()
2093 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2094 gpm.setup_meters ();
2095 // reset peak when meter point changes
2096 gpm.reset_peak_display();
2099 /** The bus that we are displaying sends to has changed, or been turned off.
2100 * @param send_to New bus that we are displaying sends to, or 0.
2103 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2105 RouteUI::bus_send_display_changed (send_to);
2108 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2113 revert_to_default_display ();
2116 revert_to_default_display ();
2121 MixerStrip::drop_send ()
2123 boost::shared_ptr<Send> current_send;
2125 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2126 current_send->set_metering (false);
2129 send_gone_connection.disconnect ();
2130 input_button.set_sensitive (true);
2131 output_button.set_sensitive (true);
2132 group_button.set_sensitive (true);
2133 set_invert_sensitive (true);
2134 gpm.meter_point_button.set_sensitive (true);
2135 mute_button->set_sensitive (true);
2136 solo_button->set_sensitive (true);
2137 solo_isolated_led->set_sensitive (true);
2138 solo_safe_led->set_sensitive (true);
2139 monitor_input_button->set_sensitive (true);
2140 monitor_disk_button->set_sensitive (true);
2141 _comment_button.set_sensitive (true);
2142 RouteUI::check_rec_enable_sensitivity ();
2143 set_button_names (); // update solo button visual state
2147 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2149 _current_delivery = d;
2150 DeliveryChanged (_current_delivery);
2154 MixerStrip::show_send (boost::shared_ptr<Send> send)
2160 set_current_delivery (send);
2162 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2163 send->set_metering (true);
2164 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2166 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2167 gain_meter().setup_meters ();
2169 uint32_t const in = _current_delivery->pans_required();
2170 uint32_t const out = _current_delivery->pan_outs();
2172 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2173 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2174 panner_ui().setup_pan ();
2175 panner_ui().set_send_drawing_mode (true);
2176 panner_ui().show_all ();
2178 input_button.set_sensitive (false);
2179 group_button.set_sensitive (false);
2180 set_invert_sensitive (false);
2181 gpm.meter_point_button.set_sensitive (false);
2182 mute_button->set_sensitive (false);
2183 solo_button->set_sensitive (false);
2184 rec_enable_button->set_sensitive (false);
2185 solo_isolated_led->set_sensitive (false);
2186 solo_safe_led->set_sensitive (false);
2187 monitor_input_button->set_sensitive (false);
2188 monitor_disk_button->set_sensitive (false);
2189 _comment_button.set_sensitive (false);
2191 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2192 output_button.set_sensitive (false);
2195 reset_strip_style ();
2199 MixerStrip::revert_to_default_display ()
2203 set_current_delivery (_route->main_outs ());
2205 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2206 gain_meter().setup_meters ();
2208 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2209 update_panner_choices();
2210 panner_ui().setup_pan ();
2211 panner_ui().set_send_drawing_mode (false);
2213 if (has_audio_outputs ()) {
2214 panners.show_all ();
2216 panners.hide_all ();
2219 reset_strip_style ();
2223 MixerStrip::set_button_names ()
2227 mute_button->set_text (_("Mute"));
2228 monitor_input_button->set_text (_("In"));
2229 monitor_disk_button->set_text (_("Disk"));
2230 if (monitor_section_button) {
2231 monitor_section_button->set_text (_("Mon"));
2234 if (_route && _route->solo_safe_control()->solo_safe()) {
2235 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2237 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2239 if (!Config->get_solo_control_is_listen_control()) {
2240 solo_button->set_text (_("Solo"));
2242 switch (Config->get_listen_position()) {
2243 case AfterFaderListen:
2244 solo_button->set_text (_("AFL"));
2246 case PreFaderListen:
2247 solo_button->set_text (_("PFL"));
2251 solo_isolated_led->set_text (_("Iso"));
2252 solo_safe_led->set_text (S_("SoloLock|Lock"));
2256 mute_button->set_text (S_("Mute|M"));
2257 monitor_input_button->set_text (S_("MonitorInput|I"));
2258 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2259 if (monitor_section_button) {
2260 monitor_section_button->set_text (S_("Mon|O"));
2263 if (_route && _route->solo_safe_control()->solo_safe()) {
2264 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2266 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2268 if (!Config->get_solo_control_is_listen_control()) {
2269 solo_button->set_text (S_("Solo|S"));
2271 switch (Config->get_listen_position()) {
2272 case AfterFaderListen:
2273 solo_button->set_text (S_("AfterFader|A"));
2275 case PreFaderListen:
2276 solo_button->set_text (S_("Prefader|P"));
2281 solo_isolated_led->set_text (S_("SoloIso|I"));
2282 solo_safe_led->set_text (S_("SoloLock|L"));
2287 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2289 gpm.meter_point_button.set_text ("");
2294 MixerStrip::plugin_selector()
2296 return _mixer.plugin_selector();
2300 MixerStrip::hide_things ()
2302 processor_box.hide_things ();
2306 MixerStrip::input_active_button_press (GdkEventButton*)
2308 /* nothing happens on press */
2313 MixerStrip::input_active_button_release (GdkEventButton* ev)
2315 boost::shared_ptr<MidiTrack> mt = midi_track ();
2321 boost::shared_ptr<RouteList> rl (new RouteList);
2323 rl->push_back (route());
2325 _session->set_exclusive_input_active (rl, !mt->input_active(),
2326 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2332 MixerStrip::midi_input_status_changed ()
2334 if (midi_input_enable_button) {
2335 boost::shared_ptr<MidiTrack> mt = midi_track ();
2337 midi_input_enable_button->set_active (mt->input_active ());
2342 MixerStrip::state_id () const
2344 return string_compose ("strip %1", _route->id().to_s());
2348 MixerStrip::parameter_changed (string p)
2350 if (p == _visibility.get_state_name()) {
2351 /* The user has made changes to the mixer strip visibility, so get
2352 our VisibilityGroup to reflect these changes in our widgets.
2354 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2355 } else if (p == "track-name-number") {
2357 } else if (p == "use-monitor-bus") {
2358 if (monitor_section_button) {
2359 if (mute_button->get_parent()) {
2360 mute_button->get_parent()->remove(*mute_button);
2362 if (monitor_section_button->get_parent()) {
2363 monitor_section_button->get_parent()->remove(*monitor_section_button);
2365 if (Config->get_use_monitor_bus ()) {
2366 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2367 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2368 mute_button->show();
2369 monitor_section_button->show();
2371 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2372 mute_button->show();
2375 } else if (p == "track-name-number") {
2376 update_track_number_visibility();
2380 /** Called to decide whether the solo isolate / solo lock button visibility should
2381 * be overridden from that configured by the user. We do this for the master bus.
2383 * @return optional value that is present if visibility state should be overridden.
2385 boost::optional<bool>
2386 MixerStrip::override_solo_visibility () const
2388 if (_route && _route->is_master ()) {
2389 return boost::optional<bool> (false);
2392 return boost::optional<bool> ();
2396 MixerStrip::add_input_port (DataType t)
2398 _route->input()->add_port ("", this, t);
2402 MixerStrip::add_output_port (DataType t)
2404 _route->output()->add_port ("", this, t);
2408 MixerStrip::route_active_changed ()
2410 reset_strip_style ();
2414 MixerStrip::copy_processors ()
2416 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2420 MixerStrip::cut_processors ()
2422 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2426 MixerStrip::paste_processors ()
2428 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2432 MixerStrip::select_all_processors ()
2434 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2438 MixerStrip::deselect_all_processors ()
2440 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2444 MixerStrip::delete_processors ()
2446 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2450 MixerStrip::toggle_processors ()
2452 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2456 MixerStrip::ab_plugins ()
2458 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2462 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2464 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2467 if (ev->button == 3) {
2468 popup_level_meter_menu (ev);
2476 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2478 using namespace Gtk::Menu_Helpers;
2480 Gtk::Menu* m = manage (new Menu);
2481 MenuList& items = m->items ();
2483 RadioMenuItem::Group group;
2485 _suspend_menu_callbacks = true;
2486 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2487 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2488 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2489 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2490 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2492 if (gpm.meter_channels().n_audio() == 0) {
2493 m->popup (ev->button, ev->time);
2494 _suspend_menu_callbacks = false;
2498 RadioMenuItem::Group tgroup;
2499 items.push_back (SeparatorElem());
2501 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2502 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2503 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2504 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2505 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2506 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2507 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2508 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2509 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2510 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2511 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2514 if (_route->is_master()) {
2517 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2518 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2519 /* non-master bus */
2522 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2529 MeterType cmt = _route->meter_type();
2530 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2532 items.push_back (SeparatorElem());
2533 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2534 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2535 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2536 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2537 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2538 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2540 m->popup (ev->button, ev->time);
2541 _suspend_menu_callbacks = false;
2545 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2546 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2548 using namespace Menu_Helpers;
2550 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2551 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2552 i->set_active (_route->meter_point() == point);
2556 MixerStrip::set_meter_point (MeterPoint p)
2558 if (_suspend_menu_callbacks) return;
2559 _route->set_meter_point (p);
2563 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2564 RadioMenuItem::Group& group, string const & name, MeterType type)
2566 using namespace Menu_Helpers;
2568 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2569 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2570 i->set_active (_route->meter_type() == type);
2574 MixerStrip::set_meter_type (MeterType t)
2576 if (_suspend_menu_callbacks) return;
2581 MixerStrip::update_track_number_visibility ()
2583 DisplaySuspender ds;
2584 bool show_label = _session->config.get_track_name_number();
2586 if (_route && _route->is_master()) {
2591 number_label.show ();
2592 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2593 // except the width of the number label is subtracted from the name-hbox, so we
2594 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2595 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2597 number_label.set_size_request(tnw, -1);
2598 number_label.show ();
2600 number_label.hide ();
2605 MixerStrip::color () const
2607 return route_color ();
2611 MixerStrip::marked_for_display () const
2613 return !_route->presentation_info().hidden();
2617 MixerStrip::set_marked_for_display (bool yn)
2619 return RouteUI::mark_hidden (!yn);