2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <sigc++/bind.h>
25 #include "pbd/convert.h"
26 #include "pbd/enumwriter.h"
27 #include "pbd/replace_all.h"
28 #include "pbd/stacktrace.h"
30 #include <gtkmm2ext/gtk_ui.h>
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/choice.h>
33 #include <gtkmm2ext/doi.h>
34 #include <gtkmm2ext/slider_controller.h>
35 #include <gtkmm2ext/bindable_button.h>
37 #include "ardour/amp.h"
38 #include "ardour/audio_track.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/internal_send.h"
41 #include "ardour/io.h"
42 #include "ardour/meter.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/pannable.h"
45 #include "ardour/panner.h"
46 #include "ardour/panner_shell.h"
47 #include "ardour/panner_manager.h"
48 #include "ardour/port.h"
49 #include "ardour/profile.h"
50 #include "ardour/route.h"
51 #include "ardour/route_group.h"
52 #include "ardour/send.h"
53 #include "ardour/session.h"
54 #include "ardour/types.h"
55 #include "ardour/user_bundle.h"
56 #include "ardour/vca.h"
57 #include "ardour/vca_manager.h"
59 #include "ardour_window.h"
60 #include "mixer_strip.h"
63 #include "ardour_button.h"
64 #include "public_editor.h"
66 #include "io_selector.h"
68 #include "gui_thread.h"
69 #include "route_group_menu.h"
70 #include "meter_patterns.h"
72 #include "ui_config.h"
76 using namespace ARDOUR;
77 using namespace ARDOUR_UI_UTILS;
80 using namespace Gtkmm2ext;
82 using namespace ArdourMeter;
84 MixerStrip* MixerStrip::_entered_mixer_strip;
85 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
87 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
88 : SessionHandlePtr (sess)
91 , _mixer_owned (in_mixer)
92 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
95 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
96 , rec_mon_table (2, 2)
97 , solo_iso_table (1, 2)
98 , mute_solo_table (1, 2)
99 , bottom_button_table (1, 3)
100 , meter_point_button (_("pre"))
101 , monitor_section_button (0)
102 , midi_input_enable_button (0)
103 , _plugin_insert_cnt (0)
104 , _comment_button (_("Comments"))
105 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
106 , _visibility (X_("mixer-element-visibility"))
107 , control_slave_ui (sess)
112 /* the editor mixer strip: don't destroy it every time
113 the underlying route goes away.
116 self_destruct = false;
120 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
121 : SessionHandlePtr (sess)
124 , _mixer_owned (in_mixer)
125 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
128 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
129 , rec_mon_table (2, 2)
130 , solo_iso_table (1, 2)
131 , mute_solo_table (1, 2)
132 , bottom_button_table (1, 3)
133 , meter_point_button (_("pre"))
134 , monitor_section_button (0)
135 , midi_input_enable_button (0)
136 , _comment_button (_("Comments"))
137 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
138 , _visibility (X_("mixer-element-visibility"))
139 , control_slave_ui (sess)
148 _entered_mixer_strip= 0;
151 ignore_comment_edit = false;
152 ignore_toggle = false;
157 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
158 longest_label = "longest label";
160 string t = _("Click to toggle the width of this mixer strip.");
162 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
165 width_button.set_icon (ArdourIcon::StripWidth);
166 hide_button.set_tweaks (ArdourButton::Square);
167 set_tooltip (width_button, t);
169 hide_button.set_icon (ArdourIcon::CloseCross);
170 hide_button.set_tweaks (ArdourButton::Square);
171 set_tooltip (&hide_button, _("Hide this mixer strip"));
173 input_button_box.set_spacing(2);
175 input_button.set_text (_("Input"));
176 input_button.set_name ("mixer strip button");
177 input_button_box.pack_start (input_button, true, true);
179 output_button.set_text (_("Output"));
180 output_button.set_name ("mixer strip button");
182 set_tooltip (&meter_point_button, _("Click to select metering point"));
183 meter_point_button.set_name ("mixer strip button");
185 bottom_button_table.attach (meter_point_button, 2, 3, 0, 1);
187 meter_point_button.signal_button_press_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_press), false);
188 meter_point_button.signal_button_release_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_release), false);
190 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
192 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
193 solo_isolated_led->show ();
194 solo_isolated_led->set_no_show_all (true);
195 solo_isolated_led->set_name (X_("solo isolate"));
196 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
197 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
198 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
200 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
201 solo_safe_led->show ();
202 solo_safe_led->set_no_show_all (true);
203 solo_safe_led->set_name (X_("solo safe"));
204 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
205 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
206 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
208 solo_safe_led->set_text (S_("SoloLock|Lock"));
209 solo_isolated_led->set_text (_("Iso"));
211 solo_iso_table.set_homogeneous (true);
212 solo_iso_table.set_spacings (2);
213 if (!ARDOUR::Profile->get_trx()) {
214 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
215 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
217 solo_iso_table.show ();
219 rec_mon_table.set_homogeneous (true);
220 rec_mon_table.set_row_spacings (2);
221 rec_mon_table.set_col_spacings (2);
222 if (ARDOUR::Profile->get_mixbus()) {
223 rec_mon_table.resize (1, 3);
224 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
225 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
226 } else if (!ARDOUR::Profile->get_trx()) {
227 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
228 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
230 rec_mon_table.show ();
232 if (solo_isolated_led) {
233 button_size_group->add_widget (*solo_isolated_led);
236 button_size_group->add_widget (*solo_safe_led);
239 if (!ARDOUR::Profile->get_mixbus()) {
240 if (rec_enable_button) {
241 button_size_group->add_widget (*rec_enable_button);
243 if (monitor_disk_button) {
244 button_size_group->add_widget (*monitor_disk_button);
246 if (monitor_input_button) {
247 button_size_group->add_widget (*monitor_input_button);
251 mute_solo_table.set_homogeneous (true);
252 mute_solo_table.set_spacings (2);
254 bottom_button_table.set_spacings (2);
255 bottom_button_table.set_homogeneous (true);
256 bottom_button_table.attach (group_button, 1, 2, 0, 1);
257 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
259 name_button.set_name ("mixer strip button");
260 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
263 set_tooltip (&group_button, _("Mix group"));
264 group_button.set_name ("mixer strip button");
266 _comment_button.set_name (X_("mixer strip button"));
267 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
268 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
269 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
271 // TODO implement ArdourKnob::on_size_request properly
272 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
273 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
275 trim_control.set_tooltip_prefix (_("Trim: "));
276 trim_control.set_name ("trim knob");
277 trim_control.set_no_show_all (true);
278 input_button_box.pack_start (trim_control, false, false);
280 global_vpacker.set_border_width (1);
281 global_vpacker.set_spacing (0);
283 width_button.set_name ("mixer strip button");
284 hide_button.set_name ("mixer strip button");
286 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
287 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
289 width_hide_box.set_spacing (2);
290 width_hide_box.pack_start (width_button, false, true);
291 width_hide_box.pack_start (number_label, true, true);
292 width_hide_box.pack_end (hide_button, false, true);
294 number_label.set_text ("-");
295 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
296 number_label.set_no_show_all ();
297 number_label.set_name ("tracknumber label");
298 number_label.set_fixed_colors (0x80808080, 0x80808080);
299 number_label.set_alignment (.5, .5);
300 number_label.set_fallthrough_to_parent (true);
301 number_label.set_tweaks (ArdourButton::OccasionalText);
303 global_vpacker.set_spacing (2);
304 if (!ARDOUR::Profile->get_trx()) {
305 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (processor_box, true, true);
311 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
318 if (!ARDOUR::Profile->get_trx()) {
319 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
320 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
322 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
325 global_frame.add (global_vpacker);
326 global_frame.set_shadow_type (Gtk::SHADOW_IN);
327 global_frame.set_name ("BaseFrame");
331 /* force setting of visible selected status */
334 set_selected (false);
339 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
340 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
342 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
343 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
344 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
346 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
347 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
349 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
350 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
351 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
353 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
355 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
356 name_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_release), false);
358 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
362 /* start off as a passthru strip. we'll correct this, if necessary,
363 in update_diskstream_display().
366 /* start off as a passthru strip. we'll correct this, if necessary,
367 in update_diskstream_display().
370 if (is_midi_track()) {
371 set_name ("MidiTrackStripBase");
373 set_name ("AudioTrackStripBase");
376 add_events (Gdk::BUTTON_RELEASE_MASK|
377 Gdk::ENTER_NOTIFY_MASK|
378 Gdk::LEAVE_NOTIFY_MASK|
380 Gdk::KEY_RELEASE_MASK);
382 set_flags (get_flags() | Gtk::CAN_FOCUS);
384 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
385 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
388 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
389 must be the same as those used in RCOptionEditor so that the configuration changes
390 are recognised when they occur.
392 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
393 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
394 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
395 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
396 _visibility.add (&output_button, X_("Output"), _("Output"), false);
397 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
398 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
400 parameter_changed (X_("mixer-element-visibility"));
401 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
402 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
403 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
405 //watch for mouse enter/exit so we can do some stuff
406 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
407 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
409 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
412 MixerStrip::~MixerStrip ()
414 CatchDeletion (this);
416 if (this ==_entered_mixer_strip)
417 _entered_mixer_strip = NULL;
421 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
423 _entered_mixer_strip = this;
425 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
426 //because the mixerstrip control is a parent that encompasses the strip
427 deselect_all_processors();
433 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
435 //if we have moved outside our strip, but not into a child view, then deselect ourselves
436 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
437 _entered_mixer_strip= 0;
439 //clear keyboard focus in the gain display. this is cheesy but fixes a longstanding "bug" where the user starts typing in the gain entry, and leaves it active, thereby prohibiting other keybindings from working
440 gpm.gain_display.set_sensitive(false);
442 gpm.gain_display.set_sensitive(true);
444 //if we leave this mixer strip we need to clear out any selections
445 //processor_box.processor_display.select_none(); //but this doesn't work, because it gets triggered when (for example) you open the menu or start a drag
452 MixerStrip::name() const
455 return _route->name();
461 MixerStrip::update_trim_control ()
463 if (route()->trim() && route()->trim()->active() &&
464 route()->n_inputs().n_audio() > 0) {
465 trim_control.show ();
466 trim_control.set_controllable (route()->trim()->gain_control());
468 trim_control.hide ();
469 boost::shared_ptr<Controllable> none;
470 trim_control.set_controllable (none);
475 MixerStrip::set_route (boost::shared_ptr<Route> rt)
477 //the rec/monitor stuff only shows up for tracks.
478 //the show_sends only shows up for buses.
479 //remove them all here, and we may add them back later
480 if (show_sends_button->get_parent()) {
481 rec_mon_table.remove (*show_sends_button);
483 if (rec_enable_button->get_parent()) {
484 rec_mon_table.remove (*rec_enable_button);
486 if (monitor_input_button->get_parent()) {
487 rec_mon_table.remove (*monitor_input_button);
489 if (monitor_disk_button->get_parent()) {
490 rec_mon_table.remove (*monitor_disk_button);
492 if (group_button.get_parent()) {
493 bottom_button_table.remove (group_button);
496 RouteUI::set_route (rt);
498 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
500 /* ProcessorBox needs access to _route so that it can read
503 processor_box.set_route (rt);
505 revert_to_default_display ();
507 /* unpack these from the parent and stuff them into our own
511 if (gpm.peak_display.get_parent()) {
512 gpm.peak_display.get_parent()->remove (gpm.peak_display);
514 if (gpm.gain_display.get_parent()) {
515 gpm.gain_display.get_parent()->remove (gpm.gain_display);
518 gpm.set_type (rt->meter_type());
520 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
521 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
523 if (solo_button->get_parent()) {
524 mute_solo_table.remove (*solo_button);
527 if (mute_button->get_parent()) {
528 mute_solo_table.remove (*mute_button);
531 if (route()->is_master()) {
532 solo_button->hide ();
533 mute_button->show ();
534 rec_mon_table.hide ();
535 if (solo_iso_table.get_parent()) {
536 solo_iso_table.get_parent()->remove(solo_iso_table);
538 if (monitor_section_button == 0) {
539 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
540 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
542 monitor_section_button = manage (new ArdourButton);
544 monitor_section_button->set_related_action (act);
545 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
546 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
547 monitor_section_button->show();
548 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
550 parameter_changed ("use-monitor-bus");
552 bottom_button_table.attach (group_button, 1, 2, 0, 1);
553 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
554 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
555 mute_button->show ();
556 solo_button->show ();
557 rec_mon_table.show ();
560 if (_mixer_owned && route()->is_master() ) {
562 HScrollbar scrollbar;
563 Gtk::Requisition requisition(scrollbar.size_request ());
564 int scrollbar_height = requisition.height;
566 spacer = manage (new EventBox);
567 spacer->set_size_request (-1, scrollbar_height+2);
568 global_vpacker.pack_start (*spacer, false, false);
573 monitor_input_button->show ();
574 monitor_disk_button->show ();
576 monitor_input_button->hide();
577 monitor_disk_button->hide ();
580 update_trim_control();
582 if (is_midi_track()) {
583 if (midi_input_enable_button == 0) {
584 midi_input_enable_button = manage (new ArdourButton);
585 midi_input_enable_button->set_name ("midi input button");
586 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
587 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
588 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
589 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
590 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
592 input_button_box.remove (*midi_input_enable_button);
594 /* get current state */
595 midi_input_status_changed ();
596 input_button_box.pack_start (*midi_input_enable_button, false, false);
598 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
600 if (midi_input_enable_button) {
601 /* removal from the container will delete it */
602 input_button_box.remove (*midi_input_enable_button);
603 midi_input_enable_button = 0;
607 if (is_audio_track()) {
608 boost::shared_ptr<AudioTrack> at = audio_track();
609 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
614 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
615 rec_enable_button->show();
617 if (ARDOUR::Profile->get_mixbus()) {
618 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
619 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
620 } else if (ARDOUR::Profile->get_trx()) {
621 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
623 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
624 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
631 if (!_route->is_master()) {
632 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
633 show_sends_button->show();
637 meter_point_button.set_text (meter_point_string (_route->meter_point()));
639 delete route_ops_menu;
642 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
643 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
644 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
645 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
647 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
649 if (_route->panner_shell()) {
650 update_panner_choices();
651 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
654 if (is_audio_track()) {
655 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
658 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
660 set_stuff_from_route ();
662 /* now force an update of all the various elements */
664 update_mute_display ();
665 update_solo_display ();
668 route_group_changed ();
669 update_track_number_visibility ();
672 panners.setup_pan ();
674 if (has_audio_outputs ()) {
680 update_diskstream_display ();
681 update_input_display ();
682 update_output_display ();
684 add_events (Gdk::BUTTON_RELEASE_MASK);
686 processor_box.show ();
688 if (!route()->is_master() && !route()->is_monitor()) {
689 /* we don't allow master or control routes to be hidden */
694 gpm.reset_peak_display ();
695 gpm.gain_display.show ();
696 gpm.peak_display.show ();
699 width_hide_box.show();
701 global_vpacker.show();
702 mute_solo_table.show();
703 bottom_button_table.show();
705 meter_point_button.show();
706 input_button_box.show_all();
707 output_button.show();
709 _comment_button.show();
711 gpm.gain_automation_state_button.show();
713 parameter_changed ("mixer-element-visibility");
720 MixerStrip::set_stuff_from_route ()
722 /* if width is not set, it will be set by the MixerUI or editor */
724 string str = gui_property ("strip-width");
726 set_width_enum (Width (string_2_enum (str, _width)), this);
731 MixerStrip::set_width_enum (Width w, void* owner)
733 /* always set the gpm width again, things may be hidden */
736 panners.set_width (w);
738 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
740 _width_owner = owner;
744 if (_width_owner == this) {
745 set_gui_property ("strip-width", enum_2_string (_width));
750 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
755 if (show_sends_button) {
756 show_sends_button->set_text (_("Aux"));
759 gpm.gain_automation_style_button.set_text (
760 gpm.astyle_string(gain_automation->automation_style()));
761 gpm.gain_automation_state_button.set_text (
762 gpm.astate_string(gain_automation->automation_state()));
764 if (_route->panner()) {
765 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
766 panners.astyle_string(_route->panner()->automation_style()));
767 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
768 panners.astate_string(_route->panner()->automation_state()));
772 // panners expect an even number of horiz. pixels
773 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
775 set_size_request (width, -1);
781 if (show_sends_button) {
782 show_sends_button->set_text (_("Snd"));
785 gpm.gain_automation_style_button.set_text (
786 gpm.short_astyle_string(gain_automation->automation_style()));
787 gpm.gain_automation_state_button.set_text (
788 gpm.short_astate_string(gain_automation->automation_state()));
789 gain_meter().setup_meters (); // recalc meter width
791 if (_route->panner()) {
792 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
793 panners.short_astyle_string(_route->panner()->automation_style()));
794 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
795 panners.short_astate_string(_route->panner()->automation_state()));
799 // panners expect an even number of horiz. pixels
800 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
802 set_size_request (width, -1);
807 processor_box.set_width (w);
809 update_input_display ();
810 update_output_display ();
811 setup_comment_button ();
812 route_group_changed ();
818 MixerStrip::set_packed (bool yn)
823 set_gui_property ("visible", true);
825 set_gui_property ("visible", false);
830 struct RouteCompareByName {
831 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
832 return a->name().compare (b->name()) < 0;
837 MixerStrip::output_release (GdkEventButton *ev)
839 switch (ev->button) {
841 edit_output_configuration ();
849 MixerStrip::output_press (GdkEventButton *ev)
851 using namespace Menu_Helpers;
852 if (!_session->engine().connected()) {
853 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
858 MenuList& citems = output_menu.items();
859 switch (ev->button) {
862 return false; //wait for the mouse-up to pop the dialog
866 output_menu.set_name ("ArdourContextMenu");
868 output_menu_bundles.clear ();
870 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
872 citems.push_back (SeparatorElem());
873 uint32_t const n_with_separator = citems.size ();
875 ARDOUR::BundleList current = _route->output()->bundles_connected ();
877 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
879 /* give user bundles first chance at being in the menu */
881 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
882 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
883 maybe_add_bundle_to_output_menu (*i, current);
887 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
888 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
889 maybe_add_bundle_to_output_menu (*i, current);
893 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
894 RouteList copy = *routes;
895 copy.sort (RouteCompareByName ());
896 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
897 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
900 if (citems.size() == n_with_separator) {
901 /* no routes added; remove the separator */
905 if (!ARDOUR::Profile->get_mixbus()) {
906 citems.push_back (SeparatorElem());
908 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
911 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
912 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
918 citems.push_back (SeparatorElem());
919 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
921 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
934 MixerStrip::input_release (GdkEventButton *ev)
936 switch (ev->button) {
939 edit_input_configuration ();
951 MixerStrip::input_press (GdkEventButton *ev)
953 using namespace Menu_Helpers;
955 MenuList& citems = input_menu.items();
956 input_menu.set_name ("ArdourContextMenu");
959 if (!_session->engine().connected()) {
960 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
965 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
968 switch (ev->button) {
971 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
975 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
977 citems.push_back (SeparatorElem());
978 uint32_t const n_with_separator = citems.size ();
980 input_menu_bundles.clear ();
982 ARDOUR::BundleList current = _route->input()->bundles_connected ();
984 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
986 /* give user bundles first chance at being in the menu */
988 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
989 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
990 maybe_add_bundle_to_input_menu (*i, current);
994 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
995 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
996 maybe_add_bundle_to_input_menu (*i, current);
1000 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1001 RouteList copy = *routes;
1002 copy.sort (RouteCompareByName ());
1003 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1004 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1007 if (citems.size() == n_with_separator) {
1008 /* no routes added; remove the separator */
1012 citems.push_back (SeparatorElem());
1013 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1016 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1017 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1022 citems.push_back (SeparatorElem());
1023 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1025 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1037 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1039 if (ignore_toggle) {
1043 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1045 if (std::find (current.begin(), current.end(), c) == current.end()) {
1046 _route->input()->connect_ports_to_bundle (c, true, this);
1048 _route->input()->disconnect_ports_from_bundle (c, this);
1053 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1055 if (ignore_toggle) {
1059 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1061 if (std::find (current.begin(), current.end(), c) == current.end()) {
1062 _route->output()->connect_ports_to_bundle (c, true, this);
1064 _route->output()->disconnect_ports_from_bundle (c, this);
1069 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1071 using namespace Menu_Helpers;
1073 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1077 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1078 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1082 if (i != input_menu_bundles.end()) {
1086 input_menu_bundles.push_back (b);
1088 MenuList& citems = input_menu.items();
1090 std::string n = b->name ();
1091 replace_all (n, "_", " ");
1093 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1097 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1099 using namespace Menu_Helpers;
1101 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1105 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1106 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1110 if (i != output_menu_bundles.end()) {
1114 output_menu_bundles.push_back (b);
1116 MenuList& citems = output_menu.items();
1118 std::string n = b->name ();
1119 replace_all (n, "_", " ");
1121 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1125 MixerStrip::update_diskstream_display ()
1127 if (is_track() && input_selector) {
1128 input_selector->hide_all ();
1131 route_color_changed ();
1135 MixerStrip::connect_to_pan ()
1137 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1139 panstate_connection.disconnect ();
1140 panstyle_connection.disconnect ();
1142 if (!_route->panner()) {
1146 boost::shared_ptr<Pannable> p = _route->pannable ();
1148 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1149 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_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 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1644 ++_plugin_insert_cnt;
1648 MixerStrip::build_route_ops_menu ()
1650 using namespace Menu_Helpers;
1651 route_ops_menu = new Menu;
1652 route_ops_menu->set_name ("ArdourContextMenu");
1654 MenuList& items = route_ops_menu->items();
1656 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1658 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1660 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1662 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1664 items.push_back (SeparatorElem());
1666 if (!_route->is_master()) {
1667 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1669 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1670 rename_menu_item = &items.back();
1672 items.push_back (SeparatorElem());
1673 items.push_back (CheckMenuElem (_("Active")));
1674 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1675 i->set_active (_route->active());
1676 i->set_sensitive(! _session->transport_rolling());
1677 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1679 if (!Profile->get_mixbus ()) {
1680 items.push_back (SeparatorElem());
1681 items.push_back (CheckMenuElem (_("Strict I/O")));
1682 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1683 i->set_active (_route->strict_io());
1684 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1687 _plugin_insert_cnt = 0;
1688 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1689 if (_plugin_insert_cnt > 0) {
1690 items.push_back (SeparatorElem());
1691 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1694 items.push_back (SeparatorElem());
1695 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1697 items.push_back (SeparatorElem());
1698 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1699 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1700 denormal_menu_item->set_active (_route->denormal_protection());
1703 /* note that this relies on selection being shared across editor and
1704 mixer (or global to the backend, in the future), which is the only
1705 sane thing for users anyway.
1708 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1710 Selection& selection (PublicEditor::instance().get_selection());
1711 if (!selection.selected (rtav)) {
1712 selection.set (rtav);
1715 if (!_route->is_master()) {
1716 items.push_back (SeparatorElem());
1717 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1720 items.push_back (SeparatorElem());
1721 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1727 MixerStrip::name_button_button_press (GdkEventButton* ev)
1729 if (ev->button == 3) {
1730 list_route_operations ();
1732 /* do not allow rename if the track is record-enabled */
1733 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1734 route_ops_menu->popup (1, ev->time);
1743 MixerStrip::name_button_button_release (GdkEventButton* ev)
1745 if (ev->button == 1) {
1746 list_route_operations ();
1748 /* do not allow rename if the track is record-enabled */
1749 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1750 route_ops_menu->popup (1, ev->time);
1757 MixerStrip::number_button_button_press (GdkEventButton* ev)
1759 if ( ev->button == 3 ) {
1760 list_route_operations ();
1762 /* do not allow rename if the track is record-enabled */
1763 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1764 route_ops_menu->popup (1, ev->time);
1773 MixerStrip::list_route_operations ()
1775 delete route_ops_menu;
1776 build_route_ops_menu ();
1780 MixerStrip::set_selected (bool yn)
1782 AxisView::set_selected (yn);
1785 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1786 global_frame.set_name ("MixerStripSelectedFrame");
1788 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1789 global_frame.set_name ("MixerStripFrame");
1792 global_frame.queue_draw ();
1795 // processor_box.deselect_all_processors();
1799 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1801 if (what_changed.contains (ARDOUR::Properties::name)) {
1807 MixerStrip::name_changed ()
1811 name_button.set_text (_route->name());
1814 name_button.set_text (PBD::short_version (_route->name(), 5));
1818 set_tooltip (name_button, _route->name());
1820 if (_session->config.get_track_name_number()) {
1821 const int64_t track_number = _route->track_number ();
1822 if (track_number == 0) {
1823 number_label.set_text ("-");
1825 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1828 number_label.set_text ("");
1833 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1835 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1839 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1841 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1845 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1847 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1851 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1853 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1857 MixerStrip::width_button_pressed (GdkEventButton* ev)
1859 if (ev->button != 1) {
1863 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1866 _mixer.set_strip_width (Narrow, true);
1870 _mixer.set_strip_width (Wide, true);
1876 set_width_enum (Narrow, this);
1879 set_width_enum (Wide, this);
1888 MixerStrip::hide_clicked ()
1890 // LAME fix to reset the button status for when it is redisplayed (part 1)
1891 hide_button.set_sensitive(false);
1894 Hiding(); /* EMIT_SIGNAL */
1896 _mixer.hide_strip (this);
1900 hide_button.set_sensitive(true);
1904 MixerStrip::set_embedded (bool yn)
1910 MixerStrip::map_frozen ()
1912 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1914 boost::shared_ptr<AudioTrack> at = audio_track();
1917 switch (at->freeze_state()) {
1918 case AudioTrack::Frozen:
1919 processor_box.set_sensitive (false);
1920 hide_redirect_editors ();
1923 processor_box.set_sensitive (true);
1924 // XXX need some way, maybe, to retoggle redirect editors
1928 processor_box.set_sensitive (true);
1930 RouteUI::map_frozen ();
1934 MixerStrip::hide_redirect_editors ()
1936 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1940 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1942 boost::shared_ptr<Processor> processor (p.lock ());
1947 Gtk::Window* w = processor_box.get_processor_ui (processor);
1955 MixerStrip::reset_strip_style ()
1957 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1959 gpm.set_fader_name ("SendStripBase");
1963 if (is_midi_track()) {
1964 if (_route->active()) {
1965 set_name ("MidiTrackStripBase");
1967 set_name ("MidiTrackStripBaseInactive");
1969 gpm.set_fader_name ("MidiTrackFader");
1970 } else if (is_audio_track()) {
1971 if (_route->active()) {
1972 set_name ("AudioTrackStripBase");
1974 set_name ("AudioTrackStripBaseInactive");
1976 gpm.set_fader_name ("AudioTrackFader");
1978 if (_route->active()) {
1979 set_name ("AudioBusStripBase");
1981 set_name ("AudioBusStripBaseInactive");
1983 gpm.set_fader_name ("AudioBusFader");
1985 /* (no MIDI busses yet) */
1992 MixerStrip::engine_stopped ()
1997 MixerStrip::engine_running ()
2002 MixerStrip::meter_point_string (MeterPoint mp)
2015 case MeterPostFader:
2032 return S_("Meter|In");
2036 return S_("Meter|Pr");
2039 case MeterPostFader:
2040 return S_("Meter|Po");
2044 return S_("Meter|O");
2049 return S_("Meter|C");
2058 /** Called when the monitor-section state */
2060 MixerStrip::monitor_changed ()
2062 assert (monitor_section_button);
2063 if (_session->monitor_active()) {
2064 monitor_section_button->set_name ("master monitor section button active");
2066 monitor_section_button->set_name ("master monitor section button normal");
2070 /** Called when the metering point has changed */
2072 MixerStrip::meter_changed ()
2074 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2075 gpm.setup_meters ();
2076 // reset peak when meter point changes
2077 gpm.reset_peak_display();
2080 /** The bus that we are displaying sends to has changed, or been turned off.
2081 * @param send_to New bus that we are displaying sends to, or 0.
2084 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2086 RouteUI::bus_send_display_changed (send_to);
2089 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2094 revert_to_default_display ();
2097 revert_to_default_display ();
2102 MixerStrip::drop_send ()
2104 boost::shared_ptr<Send> current_send;
2106 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2107 current_send->set_metering (false);
2110 send_gone_connection.disconnect ();
2111 input_button.set_sensitive (true);
2112 output_button.set_sensitive (true);
2113 group_button.set_sensitive (true);
2114 set_invert_sensitive (true);
2115 meter_point_button.set_sensitive (true);
2116 mute_button->set_sensitive (true);
2117 solo_button->set_sensitive (true);
2118 solo_isolated_led->set_sensitive (true);
2119 solo_safe_led->set_sensitive (true);
2120 monitor_input_button->set_sensitive (true);
2121 monitor_disk_button->set_sensitive (true);
2122 _comment_button.set_sensitive (true);
2123 RouteUI::check_rec_enable_sensitivity ();
2124 set_button_names (); // update solo button visual state
2128 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2130 _current_delivery = d;
2131 DeliveryChanged (_current_delivery);
2135 MixerStrip::show_send (boost::shared_ptr<Send> send)
2141 set_current_delivery (send);
2143 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2144 send->set_metering (true);
2145 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2147 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2148 gain_meter().setup_meters ();
2150 uint32_t const in = _current_delivery->pans_required();
2151 uint32_t const out = _current_delivery->pan_outs();
2153 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2154 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2155 panner_ui().setup_pan ();
2156 panner_ui().set_send_drawing_mode (true);
2157 panner_ui().show_all ();
2159 input_button.set_sensitive (false);
2160 group_button.set_sensitive (false);
2161 set_invert_sensitive (false);
2162 meter_point_button.set_sensitive (false);
2163 mute_button->set_sensitive (false);
2164 solo_button->set_sensitive (false);
2165 rec_enable_button->set_sensitive (false);
2166 solo_isolated_led->set_sensitive (false);
2167 solo_safe_led->set_sensitive (false);
2168 monitor_input_button->set_sensitive (false);
2169 monitor_disk_button->set_sensitive (false);
2170 _comment_button.set_sensitive (false);
2172 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2173 output_button.set_sensitive (false);
2176 reset_strip_style ();
2180 MixerStrip::revert_to_default_display ()
2184 set_current_delivery (_route->main_outs ());
2186 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2187 gain_meter().setup_meters ();
2189 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2190 update_panner_choices();
2191 panner_ui().setup_pan ();
2192 panner_ui().set_send_drawing_mode (false);
2194 if (has_audio_outputs ()) {
2195 panners.show_all ();
2197 panners.hide_all ();
2200 reset_strip_style ();
2204 MixerStrip::set_button_names ()
2208 mute_button->set_text (_("Mute"));
2209 monitor_input_button->set_text (_("In"));
2210 monitor_disk_button->set_text (_("Disk"));
2211 if (monitor_section_button) {
2212 monitor_section_button->set_text (_("Mon"));
2215 if (_route && _route->solo_safe_control()->solo_safe()) {
2216 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2218 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2220 if (!Config->get_solo_control_is_listen_control()) {
2221 solo_button->set_text (_("Solo"));
2223 switch (Config->get_listen_position()) {
2224 case AfterFaderListen:
2225 solo_button->set_text (_("AFL"));
2227 case PreFaderListen:
2228 solo_button->set_text (_("PFL"));
2232 solo_isolated_led->set_text (_("Iso"));
2233 solo_safe_led->set_text (S_("SoloLock|Lock"));
2237 mute_button->set_text (S_("Mute|M"));
2238 monitor_input_button->set_text (S_("MonitorInput|I"));
2239 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2240 if (monitor_section_button) {
2241 monitor_section_button->set_text (S_("Mon|O"));
2244 if (_route && _route->solo_safe_control()->solo_safe()) {
2245 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2247 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2249 if (!Config->get_solo_control_is_listen_control()) {
2250 solo_button->set_text (S_("Solo|S"));
2252 switch (Config->get_listen_position()) {
2253 case AfterFaderListen:
2254 solo_button->set_text (S_("AfterFader|A"));
2256 case PreFaderListen:
2257 solo_button->set_text (S_("Prefader|P"));
2262 solo_isolated_led->set_text (S_("SoloIso|I"));
2263 solo_safe_led->set_text (S_("SoloLock|L"));
2268 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2270 meter_point_button.set_text ("");
2275 MixerStrip::plugin_selector()
2277 return _mixer.plugin_selector();
2281 MixerStrip::hide_things ()
2283 processor_box.hide_things ();
2287 MixerStrip::input_active_button_press (GdkEventButton*)
2289 /* nothing happens on press */
2294 MixerStrip::input_active_button_release (GdkEventButton* ev)
2296 boost::shared_ptr<MidiTrack> mt = midi_track ();
2302 boost::shared_ptr<RouteList> rl (new RouteList);
2304 rl->push_back (route());
2306 _session->set_exclusive_input_active (rl, !mt->input_active(),
2307 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2313 MixerStrip::midi_input_status_changed ()
2315 if (midi_input_enable_button) {
2316 boost::shared_ptr<MidiTrack> mt = midi_track ();
2318 midi_input_enable_button->set_active (mt->input_active ());
2323 MixerStrip::state_id () const
2325 return string_compose ("strip %1", _route->id().to_s());
2329 MixerStrip::parameter_changed (string p)
2331 if (p == _visibility.get_state_name()) {
2332 /* The user has made changes to the mixer strip visibility, so get
2333 our VisibilityGroup to reflect these changes in our widgets.
2335 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2336 } else if (p == "track-name-number") {
2338 } else if (p == "use-monitor-bus") {
2339 if (monitor_section_button) {
2340 if (mute_button->get_parent()) {
2341 mute_button->get_parent()->remove(*mute_button);
2343 if (monitor_section_button->get_parent()) {
2344 monitor_section_button->get_parent()->remove(*monitor_section_button);
2346 if (Config->get_use_monitor_bus ()) {
2347 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2348 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2349 mute_button->show();
2350 monitor_section_button->show();
2352 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2353 mute_button->show();
2356 } else if (p == "track-name-number") {
2357 update_track_number_visibility();
2361 /** Called to decide whether the solo isolate / solo lock button visibility should
2362 * be overridden from that configured by the user. We do this for the master bus.
2364 * @return optional value that is present if visibility state should be overridden.
2366 boost::optional<bool>
2367 MixerStrip::override_solo_visibility () const
2369 if (_route && _route->is_master ()) {
2370 return boost::optional<bool> (false);
2373 return boost::optional<bool> ();
2377 MixerStrip::add_input_port (DataType t)
2379 _route->input()->add_port ("", this, t);
2383 MixerStrip::add_output_port (DataType t)
2385 _route->output()->add_port ("", this, t);
2389 MixerStrip::route_active_changed ()
2391 reset_strip_style ();
2395 MixerStrip::copy_processors ()
2397 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2401 MixerStrip::cut_processors ()
2403 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2407 MixerStrip::paste_processors ()
2409 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2413 MixerStrip::select_all_processors ()
2415 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2419 MixerStrip::deselect_all_processors ()
2421 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2425 MixerStrip::delete_processors ()
2427 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2431 MixerStrip::toggle_processors ()
2433 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2437 MixerStrip::ab_plugins ()
2439 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2443 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2445 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2448 if (ev->button == 3) {
2449 popup_level_meter_menu (ev);
2457 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2459 using namespace Gtk::Menu_Helpers;
2461 Gtk::Menu* m = manage (new Menu);
2462 MenuList& items = m->items ();
2464 RadioMenuItem::Group group;
2466 _suspend_menu_callbacks = true;
2467 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2468 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2469 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2470 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2471 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2473 if (gpm.meter_channels().n_audio() == 0) {
2474 m->popup (ev->button, ev->time);
2475 _suspend_menu_callbacks = false;
2479 RadioMenuItem::Group tgroup;
2480 items.push_back (SeparatorElem());
2482 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2483 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2484 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2485 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2486 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2487 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2488 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2489 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2490 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2491 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2492 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2495 if (_route->is_master()) {
2498 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2499 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2500 /* non-master bus */
2503 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2510 MeterType cmt = _route->meter_type();
2511 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2513 items.push_back (SeparatorElem());
2514 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2515 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2516 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2517 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2518 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2519 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2521 m->popup (ev->button, ev->time);
2522 _suspend_menu_callbacks = false;
2526 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2527 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2529 using namespace Menu_Helpers;
2531 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2532 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2533 i->set_active (_route->meter_point() == point);
2537 MixerStrip::set_meter_point (MeterPoint p)
2539 if (_suspend_menu_callbacks) return;
2540 _route->set_meter_point (p);
2544 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2545 RadioMenuItem::Group& group, string const & name, MeterType type)
2547 using namespace Menu_Helpers;
2549 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2550 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2551 i->set_active (_route->meter_type() == type);
2555 MixerStrip::set_meter_type (MeterType t)
2557 if (_suspend_menu_callbacks) return;
2562 MixerStrip::update_track_number_visibility ()
2564 DisplaySuspender ds;
2565 bool show_label = _session->config.get_track_name_number();
2567 if (_route && _route->is_master()) {
2572 number_label.show ();
2573 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2574 // except the width of the number label is subtracted from the name-hbox, so we
2575 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2576 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2578 number_label.set_size_request(tnw, -1);
2579 number_label.show ();
2581 number_label.hide ();
2586 MixerStrip::color () const
2588 return route_color ();
2592 MixerStrip::marked_for_display () const
2594 return !_route->presentation_info().hidden();
2598 MixerStrip::set_marked_for_display (bool yn)
2600 return RouteUI::mark_hidden (!yn);