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>
36 #include "gtkmm2ext/menu_elems.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 "ardour_button.h"
66 #include "public_editor.h"
68 #include "io_selector.h"
70 #include "gui_thread.h"
71 #include "route_group_menu.h"
72 #include "meter_patterns.h"
74 #include "ui_config.h"
78 using namespace ARDOUR;
79 using namespace ARDOUR_UI_UTILS;
82 using namespace Gtkmm2ext;
84 using namespace ArdourMeter;
86 MixerStrip* MixerStrip::_entered_mixer_strip;
87 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
89 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
90 : SessionHandlePtr (sess)
93 , _mixer_owned (in_mixer)
94 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
97 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
98 , rec_mon_table (2, 2)
99 , solo_iso_table (1, 2)
100 , mute_solo_table (1, 2)
101 , bottom_button_table (1, 3)
102 , monitor_section_button (0)
103 , midi_input_enable_button (0)
104 , _plugin_insert_cnt (0)
105 , _comment_button (_("Comments"))
106 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
107 , _visibility (X_("mixer-element-visibility"))
108 , control_slave_ui (sess)
113 /* the editor mixer strip: don't destroy it every time
114 the underlying route goes away.
117 self_destruct = false;
121 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
122 : SessionHandlePtr (sess)
125 , _mixer_owned (in_mixer)
126 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
129 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
130 , rec_mon_table (2, 2)
131 , solo_iso_table (1, 2)
132 , mute_solo_table (1, 2)
133 , bottom_button_table (1, 3)
134 , monitor_section_button (0)
135 , midi_input_enable_button (0)
136 , _plugin_insert_cnt (0)
137 , _comment_button (_("Comments"))
138 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
139 , _visibility (X_("mixer-element-visibility"))
140 , control_slave_ui (sess)
149 _entered_mixer_strip= 0;
152 ignore_comment_edit = false;
153 ignore_toggle = false;
157 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
158 longest_label = "longest label";
160 string t = _("Click to toggle the width of this mixer strip.");
162 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
165 width_button.set_icon (ArdourIcon::StripWidth);
166 hide_button.set_tweaks (ArdourButton::Square);
167 set_tooltip (width_button, t);
169 hide_button.set_icon (ArdourIcon::CloseCross);
170 hide_button.set_tweaks (ArdourButton::Square);
171 set_tooltip (&hide_button, _("Hide this mixer strip"));
173 input_button_box.set_spacing(2);
175 input_button.set_text (_("Input"));
176 input_button.set_name ("mixer strip button");
177 input_button_box.pack_start (input_button, true, true);
179 output_button.set_text (_("Output"));
180 output_button.set_name ("mixer strip button");
182 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
184 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
186 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
187 solo_isolated_led->show ();
188 solo_isolated_led->set_no_show_all (true);
189 solo_isolated_led->set_name (X_("solo isolate"));
190 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
191 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
192 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
194 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
195 solo_safe_led->show ();
196 solo_safe_led->set_no_show_all (true);
197 solo_safe_led->set_name (X_("solo safe"));
198 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
199 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
200 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
202 solo_safe_led->set_text (S_("SoloLock|Lock"));
203 solo_isolated_led->set_text (_("Iso"));
205 solo_iso_table.set_homogeneous (true);
206 solo_iso_table.set_spacings (2);
207 if (!ARDOUR::Profile->get_trx()) {
208 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
209 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
211 solo_iso_table.show ();
213 rec_mon_table.set_homogeneous (true);
214 rec_mon_table.set_row_spacings (2);
215 rec_mon_table.set_col_spacings (2);
216 if (ARDOUR::Profile->get_mixbus()) {
217 rec_mon_table.resize (1, 3);
218 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
219 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
220 } else if (!ARDOUR::Profile->get_trx()) {
221 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
222 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
224 rec_mon_table.show ();
226 if (solo_isolated_led) {
227 button_size_group->add_widget (*solo_isolated_led);
230 button_size_group->add_widget (*solo_safe_led);
233 if (!ARDOUR::Profile->get_mixbus()) {
234 if (rec_enable_button) {
235 button_size_group->add_widget (*rec_enable_button);
237 if (monitor_disk_button) {
238 button_size_group->add_widget (*monitor_disk_button);
240 if (monitor_input_button) {
241 button_size_group->add_widget (*monitor_input_button);
245 mute_solo_table.set_homogeneous (true);
246 mute_solo_table.set_spacings (2);
248 bottom_button_table.set_spacings (2);
249 bottom_button_table.set_homogeneous (true);
250 bottom_button_table.attach (group_button, 1, 2, 0, 1);
251 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
253 name_button.set_name ("mixer strip button");
254 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
255 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
257 set_tooltip (&group_button, _("Mix group"));
258 group_button.set_name ("mixer strip button");
260 _comment_button.set_name (X_("mixer strip button"));
261 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
262 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
263 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
265 // TODO implement ArdourKnob::on_size_request properly
266 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
267 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
269 trim_control.set_tooltip_prefix (_("Trim: "));
270 trim_control.set_name ("trim knob");
271 trim_control.set_no_show_all (true);
272 input_button_box.pack_start (trim_control, false, false);
274 global_vpacker.set_border_width (1);
275 global_vpacker.set_spacing (0);
277 width_button.set_name ("mixer strip button");
278 hide_button.set_name ("mixer strip button");
280 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
281 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
283 width_hide_box.set_spacing (2);
284 width_hide_box.pack_start (width_button, false, true);
285 width_hide_box.pack_start (number_label, true, true);
286 width_hide_box.pack_end (hide_button, false, true);
288 number_label.set_text ("-");
289 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
290 number_label.set_no_show_all ();
291 number_label.set_name ("tracknumber label");
292 number_label.set_fixed_colors (0x80808080, 0x80808080);
293 number_label.set_alignment (.5, .5);
294 number_label.set_fallthrough_to_parent (true);
295 number_label.set_tweaks (ArdourButton::OccasionalText);
297 global_vpacker.set_spacing (2);
298 if (!ARDOUR::Profile->get_trx()) {
299 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
300 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
301 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
302 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
303 global_vpacker.pack_start (processor_box, true, true);
305 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
312 if (!ARDOUR::Profile->get_trx()) {
313 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
320 //add a spacer underneath the master bus;
321 //this fills the area that is taken up by the scrollbar on the tracks;
322 //and therefore keeps the faders "even" across the bottom
323 int scrollbar_height = 0;
325 Gtk::Window window (WINDOW_TOPLEVEL);
326 HScrollbar scrollbar;
327 window.add (scrollbar);
328 scrollbar.set_name ("MixerWindow");
329 scrollbar.ensure_style();
330 Gtk::Requisition requisition(scrollbar.size_request ());
331 scrollbar_height = requisition.height;
333 spacer.set_size_request (-1, scrollbar_height);
334 global_vpacker.pack_end (spacer, false, false);
337 global_frame.add (global_vpacker);
338 global_frame.set_shadow_type (Gtk::SHADOW_IN);
339 global_frame.set_name ("BaseFrame");
343 /* force setting of visible selected status */
346 set_selected (false);
351 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
352 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
354 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
355 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
356 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
358 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
359 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
361 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
362 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
363 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
365 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
367 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
369 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
373 /* start off as a passthru strip. we'll correct this, if necessary,
374 in update_diskstream_display().
377 /* start off as a passthru strip. we'll correct this, if necessary,
378 in update_diskstream_display().
381 if (is_midi_track()) {
382 set_name ("MidiTrackStripBase");
384 set_name ("AudioTrackStripBase");
387 add_events (Gdk::BUTTON_RELEASE_MASK|
388 Gdk::ENTER_NOTIFY_MASK|
389 Gdk::LEAVE_NOTIFY_MASK|
391 Gdk::KEY_RELEASE_MASK);
393 set_flags (get_flags() | Gtk::CAN_FOCUS);
395 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
396 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
399 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
400 must be the same as those used in RCOptionEditor so that the configuration changes
401 are recognised when they occur.
403 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
404 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
405 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
406 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
407 _visibility.add (&output_button, X_("Output"), _("Output"), false);
408 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
409 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
411 parameter_changed (X_("mixer-element-visibility"));
412 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
413 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
414 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
416 //watch for mouse enter/exit so we can do some stuff
417 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
418 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
420 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
423 MixerStrip::~MixerStrip ()
425 CatchDeletion (this);
427 if (this ==_entered_mixer_strip)
428 _entered_mixer_strip = NULL;
432 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
434 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
440 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
442 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
448 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
450 _entered_mixer_strip = this;
452 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
453 //because the mixerstrip control is a parent that encompasses the strip
454 deselect_all_processors();
460 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
462 //if we have moved outside our strip, but not into a child view, then deselect ourselves
463 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
464 _entered_mixer_strip= 0;
466 //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
467 gpm.gain_display.set_sensitive(false);
469 gpm.gain_display.set_sensitive(true);
471 //if we leave this mixer strip we need to clear out any selections
472 //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
479 MixerStrip::name() const
482 return _route->name();
488 MixerStrip::update_trim_control ()
490 if (route()->trim() && route()->trim()->active() &&
491 route()->n_inputs().n_audio() > 0) {
492 trim_control.show ();
493 trim_control.set_controllable (route()->trim()->gain_control());
495 trim_control.hide ();
496 boost::shared_ptr<Controllable> none;
497 trim_control.set_controllable (none);
502 MixerStrip::set_route (boost::shared_ptr<Route> rt)
504 //the rec/monitor stuff only shows up for tracks.
505 //the show_sends only shows up for buses.
506 //remove them all here, and we may add them back later
507 if (show_sends_button->get_parent()) {
508 rec_mon_table.remove (*show_sends_button);
510 if (rec_enable_button->get_parent()) {
511 rec_mon_table.remove (*rec_enable_button);
513 if (monitor_input_button->get_parent()) {
514 rec_mon_table.remove (*monitor_input_button);
516 if (monitor_disk_button->get_parent()) {
517 rec_mon_table.remove (*monitor_disk_button);
519 if (group_button.get_parent()) {
520 bottom_button_table.remove (group_button);
523 RouteUI::set_route (rt);
525 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
527 /* ProcessorBox needs access to _route so that it can read
530 processor_box.set_route (rt);
532 revert_to_default_display ();
534 /* unpack these from the parent and stuff them into our own
538 if (gpm.peak_display.get_parent()) {
539 gpm.peak_display.get_parent()->remove (gpm.peak_display);
541 if (gpm.gain_display.get_parent()) {
542 gpm.gain_display.get_parent()->remove (gpm.gain_display);
545 gpm.set_type (rt->meter_type());
547 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
548 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
550 if (solo_button->get_parent()) {
551 mute_solo_table.remove (*solo_button);
554 if (mute_button->get_parent()) {
555 mute_solo_table.remove (*mute_button);
558 if (route()->is_master()) {
559 solo_button->hide ();
560 mute_button->show ();
561 rec_mon_table.hide ();
562 solo_iso_table.set_sensitive(false);
563 control_slave_ui.set_sensitive(false);
564 if (monitor_section_button == 0) {
565 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
566 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
568 monitor_section_button = manage (new ArdourButton);
570 monitor_section_button->set_related_action (act);
571 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
572 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
573 monitor_section_button->show();
574 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
576 parameter_changed ("use-monitor-bus");
578 bottom_button_table.attach (group_button, 1, 2, 0, 1);
579 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
580 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
581 mute_button->show ();
582 solo_button->show ();
583 rec_mon_table.show ();
584 solo_iso_table.set_sensitive(true);
585 control_slave_ui.set_sensitive(true);
588 if (_mixer_owned && route()->is_master() ) {
595 monitor_input_button->show ();
596 monitor_disk_button->show ();
598 monitor_input_button->hide();
599 monitor_disk_button->hide ();
602 update_trim_control();
604 if (is_midi_track()) {
605 if (midi_input_enable_button == 0) {
606 midi_input_enable_button = manage (new ArdourButton);
607 midi_input_enable_button->set_name ("midi input button");
608 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
609 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
610 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
611 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
612 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
614 input_button_box.remove (*midi_input_enable_button);
616 /* get current state */
617 midi_input_status_changed ();
618 input_button_box.pack_start (*midi_input_enable_button, false, false);
620 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
622 if (midi_input_enable_button) {
623 /* removal from the container will delete it */
624 input_button_box.remove (*midi_input_enable_button);
625 midi_input_enable_button = 0;
629 if (is_audio_track()) {
630 boost::shared_ptr<AudioTrack> at = audio_track();
631 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
636 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
637 rec_enable_button->show();
639 if (ARDOUR::Profile->get_mixbus()) {
640 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
641 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
642 } else if (ARDOUR::Profile->get_trx()) {
643 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
645 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
646 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
653 if (!_route->is_master()) {
654 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
655 show_sends_button->show();
659 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
661 delete route_ops_menu;
664 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
665 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
666 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
667 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
669 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
671 if (_route->panner_shell()) {
672 update_panner_choices();
673 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
676 if (is_audio_track()) {
677 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
680 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
682 set_stuff_from_route ();
684 /* now force an update of all the various elements */
686 update_mute_display ();
687 update_solo_display ();
690 route_group_changed ();
691 update_track_number_visibility ();
694 panners.setup_pan ();
696 if (has_audio_outputs ()) {
702 update_diskstream_display ();
703 update_input_display ();
704 update_output_display ();
706 add_events (Gdk::BUTTON_RELEASE_MASK);
708 processor_box.show ();
710 if (!route()->is_master() && !route()->is_monitor()) {
711 /* we don't allow master or control routes to be hidden */
716 gpm.reset_peak_display ();
717 gpm.gain_display.show ();
718 gpm.peak_display.show ();
721 width_hide_box.show();
723 global_vpacker.show();
724 mute_solo_table.show();
725 bottom_button_table.show();
727 gpm.meter_point_button.show();
728 input_button_box.show_all();
729 output_button.show();
731 _comment_button.show();
733 gpm.gain_automation_state_button.show();
735 parameter_changed ("mixer-element-visibility");
742 MixerStrip::set_stuff_from_route ()
744 /* if width is not set, it will be set by the MixerUI or editor */
747 if (get_gui_property ("strip-width", width)) {
748 set_width_enum (width, this);
753 MixerStrip::set_width_enum (Width w, void* owner)
755 /* always set the gpm width again, things may be hidden */
758 panners.set_width (w);
760 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
762 _width_owner = owner;
766 if (_width_owner == this) {
767 set_gui_property ("strip-width", _width);
772 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
777 if (show_sends_button) {
778 show_sends_button->set_text (_("Aux"));
781 gpm.gain_automation_state_button.set_text (
782 gpm.astate_string(gain_automation->automation_state()));
784 if (_route->panner()) {
785 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
786 panners.astate_string(_route->panner()->automation_state()));
790 // panners expect an even number of horiz. pixels
791 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
793 set_size_request (width, -1);
799 if (show_sends_button) {
800 show_sends_button->set_text (_("Snd"));
803 gpm.gain_automation_state_button.set_text (
804 gpm.short_astate_string(gain_automation->automation_state()));
805 gain_meter().setup_meters (); // recalc meter width
807 if (_route->panner()) {
808 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
809 panners.short_astate_string(_route->panner()->automation_state()));
813 // panners expect an even number of horiz. pixels
814 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
816 set_size_request (width, -1);
821 processor_box.set_width (w);
823 update_input_display ();
824 update_output_display ();
825 setup_comment_button ();
826 route_group_changed ();
832 MixerStrip::set_packed (bool yn)
835 set_gui_property ("visible", _packed);
839 struct RouteCompareByName {
840 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
841 return a->name().compare (b->name()) < 0;
846 MixerStrip::output_release (GdkEventButton *ev)
848 switch (ev->button) {
850 edit_output_configuration ();
858 MixerStrip::output_press (GdkEventButton *ev)
860 using namespace Menu_Helpers;
861 if (!_session->engine().connected()) {
862 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
867 MenuList& citems = output_menu.items();
868 switch (ev->button) {
871 return false; //wait for the mouse-up to pop the dialog
875 output_menu.set_name ("ArdourContextMenu");
877 output_menu_bundles.clear ();
879 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
881 citems.push_back (SeparatorElem());
882 uint32_t const n_with_separator = citems.size ();
884 ARDOUR::BundleList current = _route->output()->bundles_connected ();
886 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
888 /* give user bundles first chance at being in the menu */
890 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
891 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
892 maybe_add_bundle_to_output_menu (*i, current);
896 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
897 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
898 maybe_add_bundle_to_output_menu (*i, current);
902 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
903 RouteList copy = *routes;
904 copy.sort (RouteCompareByName ());
905 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
906 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
909 if (citems.size() == n_with_separator) {
910 /* no routes added; remove the separator */
914 if (!ARDOUR::Profile->get_mixbus()) {
915 citems.push_back (SeparatorElem());
917 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
920 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
921 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
927 citems.push_back (SeparatorElem());
928 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
930 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
943 MixerStrip::input_release (GdkEventButton *ev)
945 switch (ev->button) {
948 edit_input_configuration ();
960 MixerStrip::input_press (GdkEventButton *ev)
962 using namespace Menu_Helpers;
964 MenuList& citems = input_menu.items();
965 input_menu.set_name ("ArdourContextMenu");
968 if (!_session->engine().connected()) {
969 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
974 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
977 switch (ev->button) {
980 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
984 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
986 citems.push_back (SeparatorElem());
987 uint32_t const n_with_separator = citems.size ();
989 input_menu_bundles.clear ();
991 ARDOUR::BundleList current = _route->input()->bundles_connected ();
993 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
995 /* give user bundles first chance at being in the menu */
997 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
998 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
999 maybe_add_bundle_to_input_menu (*i, current);
1003 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1004 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1005 maybe_add_bundle_to_input_menu (*i, current);
1009 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1010 RouteList copy = *routes;
1011 copy.sort (RouteCompareByName ());
1012 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1013 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1016 if (citems.size() == n_with_separator) {
1017 /* no routes added; remove the separator */
1021 citems.push_back (SeparatorElem());
1022 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1025 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1026 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1031 citems.push_back (SeparatorElem());
1032 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1034 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1046 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1048 if (ignore_toggle) {
1052 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1054 if (std::find (current.begin(), current.end(), c) == current.end()) {
1055 _route->input()->connect_ports_to_bundle (c, true, this);
1057 _route->input()->disconnect_ports_from_bundle (c, this);
1062 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1064 if (ignore_toggle) {
1068 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1070 if (std::find (current.begin(), current.end(), c) == current.end()) {
1071 _route->output()->connect_ports_to_bundle (c, true, this);
1073 _route->output()->disconnect_ports_from_bundle (c, this);
1078 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1080 using namespace Menu_Helpers;
1082 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1086 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1087 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1091 if (i != input_menu_bundles.end()) {
1095 input_menu_bundles.push_back (b);
1097 MenuList& citems = input_menu.items();
1098 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1102 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1104 using namespace Menu_Helpers;
1106 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1110 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1111 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1115 if (i != output_menu_bundles.end()) {
1119 output_menu_bundles.push_back (b);
1121 MenuList& citems = output_menu.items();
1122 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1126 MixerStrip::update_diskstream_display ()
1128 if (is_track() && input_selector) {
1129 input_selector->hide_all ();
1132 route_color_changed ();
1136 MixerStrip::connect_to_pan ()
1138 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1140 panstate_connection.disconnect ();
1141 panstyle_connection.disconnect ();
1143 if (!_route->panner()) {
1147 boost::shared_ptr<Pannable> p = _route->pannable ();
1149 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1151 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1152 * However, that only works a panner was previously set.
1154 * PannerUI must remain subscribed to _panshell->Changed() in case
1155 * we switch the panner eg. AUX-Send and back
1156 * _route->panner_shell()->Changed() vs _panshell->Changed
1158 if (panners._panner == 0) {
1159 panners.panshell_changed ();
1161 update_panner_choices();
1165 MixerStrip::update_panner_choices ()
1167 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1168 if (!_route->panner_shell()) { return; }
1170 uint32_t in = _route->output()->n_ports().n_audio();
1172 if (_route->panner()) {
1173 in = _route->panner()->in().n_audio();
1176 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1180 * Output port labelling
1181 * =====================
1183 * Case 1: Each output has one connection, all connections are to system:playback_%i
1184 * out 1 -> system:playback_1
1185 * out 2 -> system:playback_2
1186 * out 3 -> system:playback_3
1189 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1190 * out 1 -> ardour:track_x/in 1
1191 * out 2 -> ardour:track_x/in 2
1192 * Display as: track_x
1194 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1195 * out 1 -> program x:foo
1196 * out 2 -> program x:foo
1197 * Display as: program x
1199 * Case 4: No connections (Disconnected)
1202 * Default case (unusual routing):
1203 * Display as: *number of connections*
1207 * .-----------------------------------------------.
1209 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1210 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1211 * '-----------------------------------------------'
1212 * .-----------------------------------------------.
1215 * '-----------------------------------------------'
1219 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1223 boost::shared_ptr<IO> io;
1224 boost::shared_ptr<Port> port;
1225 vector<string> port_connections;
1227 uint32_t total_connection_count = 0;
1228 uint32_t io_connection_count = 0;
1229 uint32_t ardour_connection_count = 0;
1230 uint32_t system_connection_count = 0;
1231 uint32_t other_connection_count = 0;
1232 uint32_t typed_connection_count = 0;
1234 ostringstream label;
1236 bool have_label = false;
1237 bool each_io_has_one_connection = true;
1239 string connection_name;
1240 string ardour_track_name;
1241 string other_connection_type;
1242 string system_ports;
1245 ostringstream tooltip;
1246 char * tooltip_cstr;
1248 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1250 * First of all, if the user made only connections to a given type, we should use that one since
1251 * it is very probably what the user expects. If there are several connections types, then show
1252 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1253 * synthesisers. This first heuristic can be expressed with these two rules:
1254 * A) If there are connected audio ports, consider audio as primary type.
1255 * B) Else, if there are connected midi ports, consider midi as primary type.
1257 * If there are no connected ports, then we choose the primary type based on the type of existing
1258 * but unconnected ports. Again:
1259 * C) If there are audio ports, consider audio as primary type.
1260 * D) Else, if there are midi ports, consider midi as primary type. */
1262 DataType dt = DataType::AUDIO;
1266 io = route->input();
1268 io = route->output();
1271 io_count = io->n_ports().n_total();
1272 for (io_index = 0; io_index < io_count; ++io_index) {
1273 port = io->nth (io_index);
1274 if (port->connected()) {
1276 if (port->type() == DataType::AUDIO) {
1277 /* Rule A) applies no matter the remaining ports */
1278 dt = DataType::AUDIO;
1281 if (port->type() == DataType::MIDI) {
1282 /* Rule B) is a good candidate... */
1283 dt = DataType::MIDI;
1284 /* ...but continue the loop to check remaining ports for rule A) */
1290 /* Neither rule A) nor rule B) matched */
1291 if ( io->n_ports().n_audio() > 0 ) {
1293 dt = DataType::AUDIO;
1294 } else if ( io->n_ports().n_midi() > 0 ) {
1296 dt = DataType::MIDI;
1300 if ( dt == DataType::MIDI ) {
1301 tooltip << _("MIDI ");
1305 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1307 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1310 for (io_index = 0; io_index < io_count; ++io_index) {
1311 port = io->nth (io_index);
1313 port_connections.clear ();
1314 port->get_connections(port_connections);
1316 //ignore any port connections that don't match our DataType
1317 if (port->type() != dt) {
1318 if (!port_connections.empty()) {
1319 ++typed_connection_count;
1324 io_connection_count = 0;
1326 if (!port_connections.empty()) {
1327 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1329 string& connection_name (*i);
1331 if (connection_name.find("system:") == 0) {
1332 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1335 if (io_connection_count == 0) {
1336 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1338 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1341 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1344 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1345 if (ardour_track_name.empty()) {
1346 // "ardour:Master/in 1" -> "ardour:Master/"
1347 string::size_type slash = connection_name.find("/");
1348 if (slash != string::npos) {
1349 ardour_track_name = connection_name.substr(0, slash + 1);
1353 if (connection_name.find(ardour_track_name) == 0) {
1354 ++ardour_connection_count;
1356 } else if (!pn.empty()) {
1357 if (system_ports.empty()) {
1360 system_ports += "/" + pn;
1362 if (connection_name.find("system:") == 0) {
1363 ++system_connection_count;
1365 } else if (connection_name.find("system:midi_") == 0) {
1367 // "system:midi_capture_123" -> "123"
1368 system_port = "M " + connection_name.substr(20);
1370 // "system:midi_playback_123" -> "123"
1371 system_port = "M " + connection_name.substr(21);
1374 if (system_ports.empty()) {
1375 system_ports += system_port;
1377 system_ports += "/" + system_port;
1380 ++system_connection_count;
1382 } else if (connection_name.find("system:") == 0) {
1384 // "system:capture_123" -> "123"
1385 system_port = connection_name.substr(15);
1387 // "system:playback_123" -> "123"
1388 system_port = connection_name.substr(16);
1391 if (system_ports.empty()) {
1392 system_ports += system_port;
1394 system_ports += "/" + system_port;
1397 ++system_connection_count;
1399 if (other_connection_type.empty()) {
1400 // "jamin:in 1" -> "jamin:"
1401 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1404 if (connection_name.find(other_connection_type) == 0) {
1405 ++other_connection_count;
1409 ++total_connection_count;
1410 ++io_connection_count;
1414 if (io_connection_count != 1) {
1415 each_io_has_one_connection = false;
1419 if (total_connection_count == 0) {
1420 tooltip << endl << _("Disconnected");
1423 tooltip_cstr = new char[tooltip.str().size() + 1];
1424 strcpy(tooltip_cstr, tooltip.str().c_str());
1427 set_tooltip (&input_button, tooltip_cstr);
1429 set_tooltip (&output_button, tooltip_cstr);
1432 delete [] tooltip_cstr;
1434 if (each_io_has_one_connection) {
1435 if (total_connection_count == ardour_connection_count) {
1436 // all connections are to the same track in ardour
1437 // "ardour:Master/" -> "Master"
1438 string::size_type slash = ardour_track_name.find("/");
1439 if (slash != string::npos) {
1440 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1441 label << ardour_track_name.substr (ppps, slash - ppps);
1445 else if (total_connection_count == system_connection_count) {
1446 // all connections are to system ports
1447 label << system_ports;
1450 else if (total_connection_count == other_connection_count) {
1451 // all connections are to the same external program eg jamin
1452 // "jamin:" -> "jamin"
1453 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1459 if (total_connection_count == 0) {
1463 // Odd configuration
1464 label << "*" << total_connection_count << "*";
1466 if (typed_connection_count > 0) {
1467 label << "\u2295"; // circled plus
1472 input_button.set_text (label.str());
1474 output_button.set_text (label.str());
1479 MixerStrip::update_input_display ()
1481 update_io_button (_route, _width, true);
1482 panners.setup_pan ();
1484 if (has_audio_outputs ()) {
1485 panners.show_all ();
1487 panners.hide_all ();
1493 MixerStrip::update_output_display ()
1495 update_io_button (_route, _width, false);
1496 gpm.setup_meters ();
1497 panners.setup_pan ();
1499 if (has_audio_outputs ()) {
1500 panners.show_all ();
1502 panners.hide_all ();
1507 MixerStrip::fast_update ()
1509 gpm.update_meters ();
1513 MixerStrip::diskstream_changed ()
1515 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1519 MixerStrip::io_changed_proxy ()
1521 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1522 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1526 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1528 boost::shared_ptr<Port> a = wa.lock ();
1529 boost::shared_ptr<Port> b = wb.lock ();
1531 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1532 update_input_display ();
1533 set_width_enum (_width, this);
1536 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1537 update_output_display ();
1538 set_width_enum (_width, this);
1543 MixerStrip::setup_comment_button ()
1545 std::string comment = _route->comment();
1547 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1549 if (comment.empty ()) {
1550 _comment_button.set_name ("generic button");
1551 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1555 _comment_button.set_name ("comment button");
1557 string::size_type pos = comment.find_first_of (" \t\n");
1558 if (pos != string::npos) {
1559 comment = comment.substr (0, pos);
1561 if (comment.empty()) {
1562 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1564 _comment_button.set_text (comment);
1569 MixerStrip::select_route_group (GdkEventButton *ev)
1571 using namespace Menu_Helpers;
1573 if (ev->button == 1) {
1575 if (group_menu == 0) {
1577 PropertyList* plist = new PropertyList();
1579 plist->add (Properties::group_gain, true);
1580 plist->add (Properties::group_mute, true);
1581 plist->add (Properties::group_solo, true);
1583 group_menu = new RouteGroupMenu (_session, plist);
1587 r.push_back (route ());
1588 group_menu->build (r);
1590 RouteGroup *rg = _route->route_group();
1592 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1593 rg ? rg->name() : _("No Group"),
1601 MixerStrip::route_group_changed ()
1603 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1605 RouteGroup *rg = _route->route_group();
1608 group_button.set_text (PBD::short_version (rg->name(), 5));
1612 group_button.set_text (_("Grp"));
1615 group_button.set_text (_("~G"));
1622 MixerStrip::route_color_changed ()
1624 name_button.modify_bg (STATE_NORMAL, color());
1625 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1626 reset_strip_style ();
1630 MixerStrip::show_passthru_color ()
1632 reset_strip_style ();
1637 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1639 boost::shared_ptr<Processor> processor (p.lock ());
1640 if (!processor || !processor->display_to_user()) {
1643 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1645 if (pi && pi->is_channelstrip ()) {
1650 ++_plugin_insert_cnt;
1654 MixerStrip::build_route_ops_menu ()
1656 using namespace Menu_Helpers;
1657 route_ops_menu = new Menu;
1658 route_ops_menu->set_name ("ArdourContextMenu");
1660 MenuList& items = route_ops_menu->items();
1662 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1664 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1666 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1668 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1670 if (!Profile->get_mixbus()) {
1671 items.push_back (SeparatorElem());
1674 if (!_route->is_master()
1676 && !_route->mixbus()
1679 if (Profile->get_mixbus()) {
1680 items.push_back (SeparatorElem());
1682 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1685 if (!Profile->get_mixbus()) {
1686 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1687 /* do not allow rename if the track is record-enabled */
1688 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1691 items.push_back (SeparatorElem());
1692 items.push_back (CheckMenuElem (_("Active")));
1693 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1694 i->set_active (_route->active());
1695 i->set_sensitive(! _session->transport_rolling());
1696 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1698 if (!Profile->get_mixbus ()) {
1699 items.push_back (SeparatorElem());
1700 items.push_back (CheckMenuElem (_("Strict I/O")));
1701 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1702 i->set_active (_route->strict_io());
1703 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1706 _plugin_insert_cnt = 0;
1707 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1708 if (_plugin_insert_cnt > 0) {
1709 items.push_back (SeparatorElem());
1710 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1713 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1714 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1715 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1716 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1719 items.push_back (SeparatorElem());
1720 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1722 items.push_back (SeparatorElem());
1723 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1724 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1725 denormal_menu_item->set_active (_route->denormal_protection());
1728 /* note that this relies on selection being shared across editor and
1729 mixer (or global to the backend, in the future), which is the only
1730 sane thing for users anyway.
1733 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1735 Selection& selection (PublicEditor::instance().get_selection());
1736 if (!selection.selected (rtav)) {
1737 selection.set (rtav);
1740 if (!_route->is_master()) {
1741 items.push_back (SeparatorElem());
1742 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1745 items.push_back (SeparatorElem());
1746 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1752 MixerStrip::name_button_button_press (GdkEventButton* ev)
1754 if (ev->button == 1 || ev->button == 3) {
1755 list_route_operations ();
1757 if (ev->button == 1) {
1758 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1761 route_ops_menu->popup (3, ev->time);
1771 MixerStrip::number_button_button_press (GdkEventButton* ev)
1773 if ( ev->button == 3 ) {
1774 list_route_operations ();
1776 route_ops_menu->popup (1, ev->time);
1785 MixerStrip::list_route_operations ()
1787 delete route_ops_menu;
1788 build_route_ops_menu ();
1792 MixerStrip::set_selected (bool yn)
1794 AxisView::set_selected (yn);
1797 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1798 global_frame.set_name ("MixerStripSelectedFrame");
1800 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1801 global_frame.set_name ("MixerStripFrame");
1804 global_frame.queue_draw ();
1807 // processor_box.deselect_all_processors();
1811 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1813 if (what_changed.contains (ARDOUR::Properties::name)) {
1819 MixerStrip::name_changed ()
1823 name_button.set_text (_route->name());
1826 name_button.set_text (PBD::short_version (_route->name(), 5));
1830 set_tooltip (name_button, _route->name());
1832 if (_session->config.get_track_name_number()) {
1833 const int64_t track_number = _route->track_number ();
1834 if (track_number == 0) {
1835 number_label.set_text ("-");
1837 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1840 number_label.set_text ("");
1845 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1847 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1851 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1853 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1857 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1859 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1863 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1865 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1869 MixerStrip::width_button_pressed (GdkEventButton* ev)
1871 if (ev->button != 1) {
1875 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1878 _mixer.set_strip_width (Narrow, true);
1882 _mixer.set_strip_width (Wide, true);
1888 set_width_enum (Narrow, this);
1891 set_width_enum (Wide, this);
1900 MixerStrip::hide_clicked ()
1902 // LAME fix to reset the button status for when it is redisplayed (part 1)
1903 hide_button.set_sensitive(false);
1906 Hiding(); /* EMIT_SIGNAL */
1908 _mixer.hide_strip (this);
1912 hide_button.set_sensitive(true);
1916 MixerStrip::set_embedded (bool yn)
1922 MixerStrip::map_frozen ()
1924 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1926 boost::shared_ptr<AudioTrack> at = audio_track();
1929 switch (at->freeze_state()) {
1930 case AudioTrack::Frozen:
1931 processor_box.set_sensitive (false);
1932 hide_redirect_editors ();
1935 processor_box.set_sensitive (true);
1936 // XXX need some way, maybe, to retoggle redirect editors
1940 processor_box.set_sensitive (true);
1942 RouteUI::map_frozen ();
1946 MixerStrip::hide_redirect_editors ()
1948 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1952 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1954 boost::shared_ptr<Processor> processor (p.lock ());
1959 Gtk::Window* w = processor_box.get_processor_ui (processor);
1967 MixerStrip::reset_strip_style ()
1969 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1971 gpm.set_fader_name ("SendStripBase");
1975 if (is_midi_track()) {
1976 if (_route->active()) {
1977 set_name ("MidiTrackStripBase");
1979 set_name ("MidiTrackStripBaseInactive");
1981 gpm.set_fader_name ("MidiTrackFader");
1982 } else if (is_audio_track()) {
1983 if (_route->active()) {
1984 set_name ("AudioTrackStripBase");
1986 set_name ("AudioTrackStripBaseInactive");
1988 gpm.set_fader_name ("AudioTrackFader");
1990 if (_route->active()) {
1991 set_name ("AudioBusStripBase");
1993 set_name ("AudioBusStripBaseInactive");
1995 gpm.set_fader_name ("AudioBusFader");
1997 /* (no MIDI busses yet) */
2004 MixerStrip::engine_stopped ()
2009 MixerStrip::engine_running ()
2014 MixerStrip::meter_point_string (MeterPoint mp)
2027 case MeterPostFader:
2044 return S_("Meter|In");
2048 return S_("Meter|Pr");
2051 case MeterPostFader:
2052 return S_("Meter|Po");
2056 return S_("Meter|O");
2061 return S_("Meter|C");
2070 /** Called when the monitor-section state */
2072 MixerStrip::monitor_changed ()
2074 assert (monitor_section_button);
2075 if (_session->monitor_active()) {
2076 monitor_section_button->set_name ("master monitor section button active");
2078 monitor_section_button->set_name ("master monitor section button normal");
2082 /** Called when the metering point has changed */
2084 MixerStrip::meter_changed ()
2086 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2087 gpm.setup_meters ();
2088 // reset peak when meter point changes
2089 gpm.reset_peak_display();
2092 /** The bus that we are displaying sends to has changed, or been turned off.
2093 * @param send_to New bus that we are displaying sends to, or 0.
2096 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2098 RouteUI::bus_send_display_changed (send_to);
2101 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2106 revert_to_default_display ();
2109 revert_to_default_display ();
2114 MixerStrip::drop_send ()
2116 boost::shared_ptr<Send> current_send;
2118 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2119 current_send->set_metering (false);
2122 send_gone_connection.disconnect ();
2123 input_button.set_sensitive (true);
2124 output_button.set_sensitive (true);
2125 group_button.set_sensitive (true);
2126 set_invert_sensitive (true);
2127 gpm.meter_point_button.set_sensitive (true);
2128 mute_button->set_sensitive (true);
2129 solo_button->set_sensitive (true);
2130 solo_isolated_led->set_sensitive (true);
2131 solo_safe_led->set_sensitive (true);
2132 monitor_input_button->set_sensitive (true);
2133 monitor_disk_button->set_sensitive (true);
2134 _comment_button.set_sensitive (true);
2135 RouteUI::check_rec_enable_sensitivity ();
2136 set_button_names (); // update solo button visual state
2140 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2142 _current_delivery = d;
2143 DeliveryChanged (_current_delivery);
2147 MixerStrip::show_send (boost::shared_ptr<Send> send)
2153 set_current_delivery (send);
2155 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2156 send->set_metering (true);
2157 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2159 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2160 gain_meter().setup_meters ();
2162 uint32_t const in = _current_delivery->pans_required();
2163 uint32_t const out = _current_delivery->pan_outs();
2165 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2166 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2167 panner_ui().setup_pan ();
2168 panner_ui().set_send_drawing_mode (true);
2169 panner_ui().show_all ();
2171 input_button.set_sensitive (false);
2172 group_button.set_sensitive (false);
2173 set_invert_sensitive (false);
2174 gpm.meter_point_button.set_sensitive (false);
2175 mute_button->set_sensitive (false);
2176 solo_button->set_sensitive (false);
2177 rec_enable_button->set_sensitive (false);
2178 solo_isolated_led->set_sensitive (false);
2179 solo_safe_led->set_sensitive (false);
2180 monitor_input_button->set_sensitive (false);
2181 monitor_disk_button->set_sensitive (false);
2182 _comment_button.set_sensitive (false);
2184 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2185 output_button.set_sensitive (false);
2188 reset_strip_style ();
2192 MixerStrip::revert_to_default_display ()
2196 set_current_delivery (_route->main_outs ());
2198 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2199 gain_meter().setup_meters ();
2201 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2202 update_panner_choices();
2203 panner_ui().setup_pan ();
2204 panner_ui().set_send_drawing_mode (false);
2206 if (has_audio_outputs ()) {
2207 panners.show_all ();
2209 panners.hide_all ();
2212 reset_strip_style ();
2216 MixerStrip::set_button_names ()
2220 mute_button->set_text (_("Mute"));
2221 monitor_input_button->set_text (_("In"));
2222 monitor_disk_button->set_text (_("Disk"));
2223 if (monitor_section_button) {
2224 monitor_section_button->set_text (_("Mon"));
2227 if (_route && _route->solo_safe_control()->solo_safe()) {
2228 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2230 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2232 if (!Config->get_solo_control_is_listen_control()) {
2233 solo_button->set_text (_("Solo"));
2235 switch (Config->get_listen_position()) {
2236 case AfterFaderListen:
2237 solo_button->set_text (_("AFL"));
2239 case PreFaderListen:
2240 solo_button->set_text (_("PFL"));
2244 solo_isolated_led->set_text (_("Iso"));
2245 solo_safe_led->set_text (S_("SoloLock|Lock"));
2249 mute_button->set_text (S_("Mute|M"));
2250 monitor_input_button->set_text (S_("MonitorInput|I"));
2251 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2252 if (monitor_section_button) {
2253 monitor_section_button->set_text (S_("Mon|O"));
2256 if (_route && _route->solo_safe_control()->solo_safe()) {
2257 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2259 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2261 if (!Config->get_solo_control_is_listen_control()) {
2262 solo_button->set_text (S_("Solo|S"));
2264 switch (Config->get_listen_position()) {
2265 case AfterFaderListen:
2266 solo_button->set_text (S_("AfterFader|A"));
2268 case PreFaderListen:
2269 solo_button->set_text (S_("Prefader|P"));
2274 solo_isolated_led->set_text (S_("SoloIso|I"));
2275 solo_safe_led->set_text (S_("SoloLock|L"));
2280 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2282 gpm.meter_point_button.set_text ("");
2287 MixerStrip::plugin_selector()
2289 return _mixer.plugin_selector();
2293 MixerStrip::hide_things ()
2295 processor_box.hide_things ();
2299 MixerStrip::input_active_button_press (GdkEventButton*)
2301 /* nothing happens on press */
2306 MixerStrip::input_active_button_release (GdkEventButton* ev)
2308 boost::shared_ptr<MidiTrack> mt = midi_track ();
2314 boost::shared_ptr<RouteList> rl (new RouteList);
2316 rl->push_back (route());
2318 _session->set_exclusive_input_active (rl, !mt->input_active(),
2319 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2325 MixerStrip::midi_input_status_changed ()
2327 if (midi_input_enable_button) {
2328 boost::shared_ptr<MidiTrack> mt = midi_track ();
2330 midi_input_enable_button->set_active (mt->input_active ());
2335 MixerStrip::state_id () const
2337 return string_compose ("strip %1", _route->id().to_s());
2341 MixerStrip::parameter_changed (string p)
2343 if (p == _visibility.get_state_name()) {
2344 /* The user has made changes to the mixer strip visibility, so get
2345 our VisibilityGroup to reflect these changes in our widgets.
2347 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2348 } else if (p == "track-name-number") {
2350 } else if (p == "use-monitor-bus") {
2351 if (monitor_section_button) {
2352 if (mute_button->get_parent()) {
2353 mute_button->get_parent()->remove(*mute_button);
2355 if (monitor_section_button->get_parent()) {
2356 monitor_section_button->get_parent()->remove(*monitor_section_button);
2358 if (Config->get_use_monitor_bus ()) {
2359 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2360 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2361 mute_button->show();
2362 monitor_section_button->show();
2364 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2365 mute_button->show();
2368 } else if (p == "track-name-number") {
2369 update_track_number_visibility();
2373 /** Called to decide whether the solo isolate / solo lock button visibility should
2374 * be overridden from that configured by the user. We do this for the master bus.
2376 * @return optional value that is present if visibility state should be overridden.
2378 boost::optional<bool>
2379 MixerStrip::override_solo_visibility () const
2381 if (_route && _route->is_master ()) {
2382 return boost::optional<bool> (false);
2385 return boost::optional<bool> ();
2389 MixerStrip::add_input_port (DataType t)
2391 _route->input()->add_port ("", this, t);
2395 MixerStrip::add_output_port (DataType t)
2397 _route->output()->add_port ("", this, t);
2401 MixerStrip::route_active_changed ()
2403 reset_strip_style ();
2407 MixerStrip::copy_processors ()
2409 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2413 MixerStrip::cut_processors ()
2415 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2419 MixerStrip::paste_processors ()
2421 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2425 MixerStrip::select_all_processors ()
2427 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2431 MixerStrip::deselect_all_processors ()
2433 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2437 MixerStrip::delete_processors ()
2439 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2443 MixerStrip::toggle_processors ()
2445 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2449 MixerStrip::ab_plugins ()
2451 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2455 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2457 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2460 if (ev->button == 3) {
2461 popup_level_meter_menu (ev);
2469 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2471 using namespace Gtk::Menu_Helpers;
2473 Gtk::Menu* m = manage (new Menu);
2474 MenuList& items = m->items ();
2476 RadioMenuItem::Group group;
2478 _suspend_menu_callbacks = true;
2479 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2480 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2481 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2482 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2483 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2485 if (gpm.meter_channels().n_audio() == 0) {
2486 m->popup (ev->button, ev->time);
2487 _suspend_menu_callbacks = false;
2491 RadioMenuItem::Group tgroup;
2492 items.push_back (SeparatorElem());
2494 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2495 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2496 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2497 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2498 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2499 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2500 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2501 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2502 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2503 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2504 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2507 if (_route->is_master()) {
2510 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2511 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2512 /* non-master bus */
2515 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2522 MeterType cmt = _route->meter_type();
2523 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2525 items.push_back (SeparatorElem());
2526 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2527 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2528 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2529 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2530 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2531 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2533 m->popup (ev->button, ev->time);
2534 _suspend_menu_callbacks = false;
2538 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2539 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2541 using namespace Menu_Helpers;
2543 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2544 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2545 i->set_active (_route->meter_point() == point);
2549 MixerStrip::set_meter_point (MeterPoint p)
2551 if (_suspend_menu_callbacks) return;
2552 _route->set_meter_point (p);
2556 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2557 RadioMenuItem::Group& group, string const & name, MeterType type)
2559 using namespace Menu_Helpers;
2561 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2562 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2563 i->set_active (_route->meter_type() == type);
2567 MixerStrip::set_meter_type (MeterType t)
2569 if (_suspend_menu_callbacks) return;
2574 MixerStrip::update_track_number_visibility ()
2576 DisplaySuspender ds;
2577 bool show_label = _session->config.get_track_name_number();
2579 if (_route && _route->is_master()) {
2584 number_label.show ();
2585 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2586 // except the width of the number label is subtracted from the name-hbox, so we
2587 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2588 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2590 number_label.set_size_request(tnw, -1);
2591 number_label.show ();
2593 number_label.hide ();
2598 MixerStrip::color () const
2600 return route_color ();
2604 MixerStrip::marked_for_display () const
2606 return !_route->presentation_info().hidden();
2610 MixerStrip::set_marked_for_display (bool yn)
2612 return RouteUI::mark_hidden (!yn);