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 output_menu.popup (1, ev->time);
932 MixerStrip::input_release (GdkEventButton *ev)
934 switch (ev->button) {
937 edit_input_configuration ();
949 MixerStrip::input_press (GdkEventButton *ev)
951 using namespace Menu_Helpers;
953 MenuList& citems = input_menu.items();
954 input_menu.set_name ("ArdourContextMenu");
957 if (!_session->engine().connected()) {
958 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
963 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
966 switch (ev->button) {
969 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
973 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
975 citems.push_back (SeparatorElem());
976 uint32_t const n_with_separator = citems.size ();
978 input_menu_bundles.clear ();
980 ARDOUR::BundleList current = _route->input()->bundles_connected ();
982 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
984 /* give user bundles first chance at being in the menu */
986 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
987 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
988 maybe_add_bundle_to_input_menu (*i, current);
992 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
993 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
994 maybe_add_bundle_to_input_menu (*i, current);
998 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
999 RouteList copy = *routes;
1000 copy.sort (RouteCompareByName ());
1001 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1002 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1005 if (citems.size() == n_with_separator) {
1006 /* no routes added; remove the separator */
1010 citems.push_back (SeparatorElem());
1011 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1014 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1015 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1020 citems.push_back (SeparatorElem());
1021 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1023 input_menu.popup (1, ev->time);
1034 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1036 if (ignore_toggle) {
1040 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1042 if (std::find (current.begin(), current.end(), c) == current.end()) {
1043 _route->input()->connect_ports_to_bundle (c, true, this);
1045 _route->input()->disconnect_ports_from_bundle (c, this);
1050 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1052 if (ignore_toggle) {
1056 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1058 if (std::find (current.begin(), current.end(), c) == current.end()) {
1059 _route->output()->connect_ports_to_bundle (c, true, this);
1061 _route->output()->disconnect_ports_from_bundle (c, this);
1066 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1068 using namespace Menu_Helpers;
1070 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1074 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1075 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1079 if (i != input_menu_bundles.end()) {
1083 input_menu_bundles.push_back (b);
1085 MenuList& citems = input_menu.items();
1087 std::string n = b->name ();
1088 replace_all (n, "_", " ");
1090 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1094 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1096 using namespace Menu_Helpers;
1098 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1102 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1103 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1107 if (i != output_menu_bundles.end()) {
1111 output_menu_bundles.push_back (b);
1113 MenuList& citems = output_menu.items();
1115 std::string n = b->name ();
1116 replace_all (n, "_", " ");
1118 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1122 MixerStrip::update_diskstream_display ()
1124 if (is_track() && input_selector) {
1125 input_selector->hide_all ();
1128 route_color_changed ();
1132 MixerStrip::connect_to_pan ()
1134 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1136 panstate_connection.disconnect ();
1137 panstyle_connection.disconnect ();
1139 if (!_route->panner()) {
1143 boost::shared_ptr<Pannable> p = _route->pannable ();
1145 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1146 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1148 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1149 * However, that only works a panner was previously set.
1151 * PannerUI must remain subscribed to _panshell->Changed() in case
1152 * we switch the panner eg. AUX-Send and back
1153 * _route->panner_shell()->Changed() vs _panshell->Changed
1155 if (panners._panner == 0) {
1156 panners.panshell_changed ();
1158 update_panner_choices();
1162 MixerStrip::update_panner_choices ()
1164 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1165 if (!_route->panner_shell()) { return; }
1167 uint32_t in = _route->output()->n_ports().n_audio();
1169 if (_route->panner()) {
1170 in = _route->panner()->in().n_audio();
1173 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1177 * Output port labelling
1178 * =====================
1180 * Case 1: Each output has one connection, all connections are to system:playback_%i
1181 * out 1 -> system:playback_1
1182 * out 2 -> system:playback_2
1183 * out 3 -> system:playback_3
1186 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1187 * out 1 -> ardour:track_x/in 1
1188 * out 2 -> ardour:track_x/in 2
1189 * Display as: track_x
1191 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1192 * out 1 -> program x:foo
1193 * out 2 -> program x:foo
1194 * Display as: program x
1196 * Case 4: No connections (Disconnected)
1199 * Default case (unusual routing):
1200 * Display as: *number of connections*
1204 * .-----------------------------------------------.
1206 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1207 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1208 * '-----------------------------------------------'
1209 * .-----------------------------------------------.
1212 * '-----------------------------------------------'
1216 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1220 boost::shared_ptr<IO> io;
1221 boost::shared_ptr<Port> port;
1222 vector<string> port_connections;
1224 uint32_t total_connection_count = 0;
1225 uint32_t io_connection_count = 0;
1226 uint32_t ardour_connection_count = 0;
1227 uint32_t system_connection_count = 0;
1228 uint32_t other_connection_count = 0;
1229 uint32_t typed_connection_count = 0;
1231 ostringstream label;
1233 bool have_label = false;
1234 bool each_io_has_one_connection = true;
1236 string connection_name;
1237 string ardour_track_name;
1238 string other_connection_type;
1239 string system_ports;
1242 ostringstream tooltip;
1243 char * tooltip_cstr;
1245 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1247 * First of all, if the user made only connections to a given type, we should use that one since
1248 * it is very probably what the user expects. If there are several connections types, then show
1249 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1250 * synthesisers. This first heuristic can be expressed with these two rules:
1251 * A) If there are connected audio ports, consider audio as primary type.
1252 * B) Else, if there are connected midi ports, consider midi as primary type.
1254 * If there are no connected ports, then we choose the primary type based on the type of existing
1255 * but unconnected ports. Again:
1256 * C) If there are audio ports, consider audio as primary type.
1257 * D) Else, if there are midi ports, consider midi as primary type. */
1259 DataType dt = DataType::AUDIO;
1263 io = route->input();
1265 io = route->output();
1268 io_count = io->n_ports().n_total();
1269 for (io_index = 0; io_index < io_count; ++io_index) {
1270 port = io->nth (io_index);
1271 if (port->connected()) {
1273 if (port->type() == DataType::AUDIO) {
1274 /* Rule A) applies no matter the remaining ports */
1275 dt = DataType::AUDIO;
1278 if (port->type() == DataType::MIDI) {
1279 /* Rule B) is a good candidate... */
1280 dt = DataType::MIDI;
1281 /* ...but continue the loop to check remaining ports for rule A) */
1287 /* Neither rule A) nor rule B) matched */
1288 if ( io->n_ports().n_audio() > 0 ) {
1290 dt = DataType::AUDIO;
1291 } else if ( io->n_ports().n_midi() > 0 ) {
1293 dt = DataType::MIDI;
1297 if ( dt == DataType::MIDI ) {
1298 tooltip << _("MIDI ");
1302 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1304 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1307 for (io_index = 0; io_index < io_count; ++io_index) {
1308 port = io->nth (io_index);
1310 port_connections.clear ();
1311 port->get_connections(port_connections);
1313 //ignore any port connections that don't match our DataType
1314 if (port->type() != dt) {
1315 if (!port_connections.empty()) {
1316 ++typed_connection_count;
1321 io_connection_count = 0;
1323 if (!port_connections.empty()) {
1324 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1326 string& connection_name (*i);
1328 if (connection_name.find("system:") == 0) {
1329 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1332 if (io_connection_count == 0) {
1333 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1335 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1338 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1341 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1342 if (ardour_track_name.empty()) {
1343 // "ardour:Master/in 1" -> "ardour:Master/"
1344 string::size_type slash = connection_name.find("/");
1345 if (slash != string::npos) {
1346 ardour_track_name = connection_name.substr(0, slash + 1);
1350 if (connection_name.find(ardour_track_name) == 0) {
1351 ++ardour_connection_count;
1353 } else if (!pn.empty()) {
1354 if (system_ports.empty()) {
1357 system_ports += "/" + pn;
1359 if (connection_name.find("system:") == 0) {
1360 ++system_connection_count;
1362 } else if (connection_name.find("system:midi_") == 0) {
1364 // "system:midi_capture_123" -> "123"
1365 system_port = "M " + connection_name.substr(20);
1367 // "system:midi_playback_123" -> "123"
1368 system_port = "M " + connection_name.substr(21);
1371 if (system_ports.empty()) {
1372 system_ports += system_port;
1374 system_ports += "/" + system_port;
1377 ++system_connection_count;
1379 } else if (connection_name.find("system:") == 0) {
1381 // "system:capture_123" -> "123"
1382 system_port = connection_name.substr(15);
1384 // "system:playback_123" -> "123"
1385 system_port = connection_name.substr(16);
1388 if (system_ports.empty()) {
1389 system_ports += system_port;
1391 system_ports += "/" + system_port;
1394 ++system_connection_count;
1396 if (other_connection_type.empty()) {
1397 // "jamin:in 1" -> "jamin:"
1398 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1401 if (connection_name.find(other_connection_type) == 0) {
1402 ++other_connection_count;
1406 ++total_connection_count;
1407 ++io_connection_count;
1411 if (io_connection_count != 1) {
1412 each_io_has_one_connection = false;
1416 if (total_connection_count == 0) {
1417 tooltip << endl << _("Disconnected");
1420 tooltip_cstr = new char[tooltip.str().size() + 1];
1421 strcpy(tooltip_cstr, tooltip.str().c_str());
1424 set_tooltip (&input_button, tooltip_cstr);
1426 set_tooltip (&output_button, tooltip_cstr);
1429 delete [] tooltip_cstr;
1431 if (each_io_has_one_connection) {
1432 if (total_connection_count == ardour_connection_count) {
1433 // all connections are to the same track in ardour
1434 // "ardour:Master/" -> "Master"
1435 string::size_type slash = ardour_track_name.find("/");
1436 if (slash != string::npos) {
1437 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1438 label << ardour_track_name.substr (ppps, slash - ppps);
1442 else if (total_connection_count == system_connection_count) {
1443 // all connections are to system ports
1444 label << system_ports;
1447 else if (total_connection_count == other_connection_count) {
1448 // all connections are to the same external program eg jamin
1449 // "jamin:" -> "jamin"
1450 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1456 if (total_connection_count == 0) {
1460 // Odd configuration
1461 label << "*" << total_connection_count << "*";
1463 if (typed_connection_count > 0) {
1464 label << "\u2295"; // circled plus
1469 input_button.set_text (label.str());
1471 output_button.set_text (label.str());
1476 MixerStrip::update_input_display ()
1478 update_io_button (_route, _width, true);
1479 panners.setup_pan ();
1481 if (has_audio_outputs ()) {
1482 panners.show_all ();
1484 panners.hide_all ();
1490 MixerStrip::update_output_display ()
1492 update_io_button (_route, _width, false);
1493 gpm.setup_meters ();
1494 panners.setup_pan ();
1496 if (has_audio_outputs ()) {
1497 panners.show_all ();
1499 panners.hide_all ();
1504 MixerStrip::fast_update ()
1506 gpm.update_meters ();
1510 MixerStrip::diskstream_changed ()
1512 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1516 MixerStrip::io_changed_proxy ()
1518 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1519 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1523 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1525 boost::shared_ptr<Port> a = wa.lock ();
1526 boost::shared_ptr<Port> b = wb.lock ();
1528 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1529 update_input_display ();
1530 set_width_enum (_width, this);
1533 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1534 update_output_display ();
1535 set_width_enum (_width, this);
1540 MixerStrip::setup_comment_button ()
1542 std::string comment = _route->comment();
1544 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1546 if (comment.empty ()) {
1547 _comment_button.set_name ("generic button");
1548 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1552 _comment_button.set_name ("comment button");
1554 string::size_type pos = comment.find_first_of (" \t\n");
1555 if (pos != string::npos) {
1556 comment = comment.substr (0, pos);
1558 if (comment.empty()) {
1559 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1561 _comment_button.set_text (comment);
1566 MixerStrip::select_route_group (GdkEventButton *ev)
1568 using namespace Menu_Helpers;
1570 if (ev->button == 1) {
1572 if (group_menu == 0) {
1574 PropertyList* plist = new PropertyList();
1576 plist->add (Properties::group_gain, true);
1577 plist->add (Properties::group_mute, true);
1578 plist->add (Properties::group_solo, true);
1580 group_menu = new RouteGroupMenu (_session, plist);
1584 r.push_back (route ());
1585 group_menu->build (r);
1586 group_menu->menu()->popup (1, ev->time);
1593 MixerStrip::route_group_changed ()
1595 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1597 RouteGroup *rg = _route->route_group();
1600 group_button.set_text (PBD::short_version (rg->name(), 5));
1604 group_button.set_text (_("Grp"));
1607 group_button.set_text (_("~G"));
1614 MixerStrip::route_color_changed ()
1616 name_button.modify_bg (STATE_NORMAL, color());
1617 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1618 reset_strip_style ();
1622 MixerStrip::show_passthru_color ()
1624 reset_strip_style ();
1629 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1631 boost::shared_ptr<Processor> processor (p.lock ());
1632 if (!processor || !processor->display_to_user()) {
1635 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1636 ++_plugin_insert_cnt;
1640 MixerStrip::build_route_ops_menu ()
1642 using namespace Menu_Helpers;
1643 route_ops_menu = new Menu;
1644 route_ops_menu->set_name ("ArdourContextMenu");
1646 MenuList& items = route_ops_menu->items();
1648 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1650 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1652 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1654 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1656 items.push_back (SeparatorElem());
1658 if (!_route->is_master()) {
1659 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1661 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1662 rename_menu_item = &items.back();
1664 items.push_back (SeparatorElem());
1665 items.push_back (CheckMenuElem (_("Active")));
1666 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1667 i->set_active (_route->active());
1668 i->set_sensitive(! _session->transport_rolling());
1669 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1671 if (!Profile->get_mixbus ()) {
1672 items.push_back (SeparatorElem());
1673 items.push_back (CheckMenuElem (_("Strict I/O")));
1674 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1675 i->set_active (_route->strict_io());
1676 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1679 _plugin_insert_cnt = 0;
1680 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1681 if (_plugin_insert_cnt > 0) {
1682 items.push_back (SeparatorElem());
1683 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1686 items.push_back (SeparatorElem());
1687 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1689 items.push_back (SeparatorElem());
1690 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1691 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1692 denormal_menu_item->set_active (_route->denormal_protection());
1695 /* note that this relies on selection being shared across editor and
1696 mixer (or global to the backend, in the future), which is the only
1697 sane thing for users anyway.
1700 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1702 Selection& selection (PublicEditor::instance().get_selection());
1703 if (!selection.selected (rtav)) {
1704 selection.set (rtav);
1707 if (!_route->is_master()) {
1708 items.push_back (SeparatorElem());
1709 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1712 items.push_back (SeparatorElem());
1713 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1719 MixerStrip::name_button_button_press (GdkEventButton* ev)
1721 if (ev->button == 3) {
1722 list_route_operations ();
1724 /* do not allow rename if the track is record-enabled */
1725 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1726 route_ops_menu->popup (1, ev->time);
1735 MixerStrip::name_button_button_release (GdkEventButton* ev)
1737 if (ev->button == 1) {
1738 list_route_operations ();
1740 /* do not allow rename if the track is record-enabled */
1741 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1742 route_ops_menu->popup (1, ev->time);
1749 MixerStrip::number_button_button_press (GdkEventButton* ev)
1751 if ( ev->button == 3 ) {
1752 list_route_operations ();
1754 /* do not allow rename if the track is record-enabled */
1755 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1756 route_ops_menu->popup (1, ev->time);
1765 MixerStrip::list_route_operations ()
1767 delete route_ops_menu;
1768 build_route_ops_menu ();
1772 MixerStrip::set_selected (bool yn)
1774 AxisView::set_selected (yn);
1777 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1778 global_frame.set_name ("MixerStripSelectedFrame");
1780 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1781 global_frame.set_name ("MixerStripFrame");
1784 global_frame.queue_draw ();
1787 // processor_box.deselect_all_processors();
1791 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1793 if (what_changed.contains (ARDOUR::Properties::name)) {
1799 MixerStrip::name_changed ()
1803 name_button.set_text (_route->name());
1806 name_button.set_text (PBD::short_version (_route->name(), 5));
1810 set_tooltip (name_button, _route->name());
1812 if (_session->config.get_track_name_number()) {
1813 const int64_t track_number = _route->track_number ();
1814 if (track_number == 0) {
1815 number_label.set_text ("-");
1817 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1820 number_label.set_text ("");
1825 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1827 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1831 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1833 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1837 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1839 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1843 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1845 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1849 MixerStrip::width_button_pressed (GdkEventButton* ev)
1851 if (ev->button != 1) {
1855 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1858 _mixer.set_strip_width (Narrow, true);
1862 _mixer.set_strip_width (Wide, true);
1868 set_width_enum (Narrow, this);
1871 set_width_enum (Wide, this);
1880 MixerStrip::hide_clicked ()
1882 // LAME fix to reset the button status for when it is redisplayed (part 1)
1883 hide_button.set_sensitive(false);
1886 Hiding(); /* EMIT_SIGNAL */
1888 _mixer.hide_strip (this);
1892 hide_button.set_sensitive(true);
1896 MixerStrip::set_embedded (bool yn)
1902 MixerStrip::map_frozen ()
1904 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1906 boost::shared_ptr<AudioTrack> at = audio_track();
1909 switch (at->freeze_state()) {
1910 case AudioTrack::Frozen:
1911 processor_box.set_sensitive (false);
1912 hide_redirect_editors ();
1915 processor_box.set_sensitive (true);
1916 // XXX need some way, maybe, to retoggle redirect editors
1920 processor_box.set_sensitive (true);
1922 RouteUI::map_frozen ();
1926 MixerStrip::hide_redirect_editors ()
1928 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1932 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1934 boost::shared_ptr<Processor> processor (p.lock ());
1939 Gtk::Window* w = processor_box.get_processor_ui (processor);
1947 MixerStrip::reset_strip_style ()
1949 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1951 gpm.set_fader_name ("SendStripBase");
1955 if (is_midi_track()) {
1956 if (_route->active()) {
1957 set_name ("MidiTrackStripBase");
1959 set_name ("MidiTrackStripBaseInactive");
1961 gpm.set_fader_name ("MidiTrackFader");
1962 } else if (is_audio_track()) {
1963 if (_route->active()) {
1964 set_name ("AudioTrackStripBase");
1966 set_name ("AudioTrackStripBaseInactive");
1968 gpm.set_fader_name ("AudioTrackFader");
1970 if (_route->active()) {
1971 set_name ("AudioBusStripBase");
1973 set_name ("AudioBusStripBaseInactive");
1975 gpm.set_fader_name ("AudioBusFader");
1977 /* (no MIDI busses yet) */
1984 MixerStrip::engine_stopped ()
1989 MixerStrip::engine_running ()
1994 MixerStrip::meter_point_string (MeterPoint mp)
2007 case MeterPostFader:
2024 return S_("Meter|In");
2028 return S_("Meter|Pr");
2031 case MeterPostFader:
2032 return S_("Meter|Po");
2036 return S_("Meter|O");
2041 return S_("Meter|C");
2050 /** Called when the monitor-section state */
2052 MixerStrip::monitor_changed ()
2054 assert (monitor_section_button);
2055 if (_session->monitor_active()) {
2056 monitor_section_button->set_name ("master monitor section button active");
2058 monitor_section_button->set_name ("master monitor section button normal");
2062 /** Called when the metering point has changed */
2064 MixerStrip::meter_changed ()
2066 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2067 gpm.setup_meters ();
2068 // reset peak when meter point changes
2069 gpm.reset_peak_display();
2072 /** The bus that we are displaying sends to has changed, or been turned off.
2073 * @param send_to New bus that we are displaying sends to, or 0.
2076 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2078 RouteUI::bus_send_display_changed (send_to);
2081 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2086 revert_to_default_display ();
2089 revert_to_default_display ();
2094 MixerStrip::drop_send ()
2096 boost::shared_ptr<Send> current_send;
2098 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2099 current_send->set_metering (false);
2102 send_gone_connection.disconnect ();
2103 input_button.set_sensitive (true);
2104 output_button.set_sensitive (true);
2105 group_button.set_sensitive (true);
2106 set_invert_sensitive (true);
2107 meter_point_button.set_sensitive (true);
2108 mute_button->set_sensitive (true);
2109 solo_button->set_sensitive (true);
2110 solo_isolated_led->set_sensitive (true);
2111 solo_safe_led->set_sensitive (true);
2112 monitor_input_button->set_sensitive (true);
2113 monitor_disk_button->set_sensitive (true);
2114 _comment_button.set_sensitive (true);
2115 RouteUI::check_rec_enable_sensitivity ();
2116 set_button_names (); // update solo button visual state
2120 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2122 _current_delivery = d;
2123 DeliveryChanged (_current_delivery);
2127 MixerStrip::show_send (boost::shared_ptr<Send> send)
2133 set_current_delivery (send);
2135 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2136 send->set_metering (true);
2137 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2139 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2140 gain_meter().setup_meters ();
2142 uint32_t const in = _current_delivery->pans_required();
2143 uint32_t const out = _current_delivery->pan_outs();
2145 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2146 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2147 panner_ui().setup_pan ();
2148 panner_ui().set_send_drawing_mode (true);
2149 panner_ui().show_all ();
2151 input_button.set_sensitive (false);
2152 group_button.set_sensitive (false);
2153 set_invert_sensitive (false);
2154 meter_point_button.set_sensitive (false);
2155 mute_button->set_sensitive (false);
2156 solo_button->set_sensitive (false);
2157 rec_enable_button->set_sensitive (false);
2158 solo_isolated_led->set_sensitive (false);
2159 solo_safe_led->set_sensitive (false);
2160 monitor_input_button->set_sensitive (false);
2161 monitor_disk_button->set_sensitive (false);
2162 _comment_button.set_sensitive (false);
2164 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2165 output_button.set_sensitive (false);
2168 reset_strip_style ();
2172 MixerStrip::revert_to_default_display ()
2176 set_current_delivery (_route->main_outs ());
2178 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2179 gain_meter().setup_meters ();
2181 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2182 update_panner_choices();
2183 panner_ui().setup_pan ();
2184 panner_ui().set_send_drawing_mode (false);
2186 if (has_audio_outputs ()) {
2187 panners.show_all ();
2189 panners.hide_all ();
2192 reset_strip_style ();
2196 MixerStrip::set_button_names ()
2200 mute_button->set_text (_("Mute"));
2201 monitor_input_button->set_text (_("In"));
2202 monitor_disk_button->set_text (_("Disk"));
2203 if (monitor_section_button) {
2204 monitor_section_button->set_text (_("Mon"));
2207 if (_route && _route->solo_safe_control()->solo_safe()) {
2208 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2210 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2212 if (!Config->get_solo_control_is_listen_control()) {
2213 solo_button->set_text (_("Solo"));
2215 switch (Config->get_listen_position()) {
2216 case AfterFaderListen:
2217 solo_button->set_text (_("AFL"));
2219 case PreFaderListen:
2220 solo_button->set_text (_("PFL"));
2224 solo_isolated_led->set_text (_("Iso"));
2225 solo_safe_led->set_text (S_("SoloLock|Lock"));
2229 mute_button->set_text (S_("Mute|M"));
2230 monitor_input_button->set_text (S_("MonitorInput|I"));
2231 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2232 if (monitor_section_button) {
2233 monitor_section_button->set_text (S_("Mon|O"));
2236 if (_route && _route->solo_safe_control()->solo_safe()) {
2237 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2239 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2241 if (!Config->get_solo_control_is_listen_control()) {
2242 solo_button->set_text (S_("Solo|S"));
2244 switch (Config->get_listen_position()) {
2245 case AfterFaderListen:
2246 solo_button->set_text (S_("AfterFader|A"));
2248 case PreFaderListen:
2249 solo_button->set_text (S_("Prefader|P"));
2254 solo_isolated_led->set_text (S_("SoloIso|I"));
2255 solo_safe_led->set_text (S_("SoloLock|L"));
2260 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2262 meter_point_button.set_text ("");
2267 MixerStrip::plugin_selector()
2269 return _mixer.plugin_selector();
2273 MixerStrip::hide_things ()
2275 processor_box.hide_things ();
2279 MixerStrip::input_active_button_press (GdkEventButton*)
2281 /* nothing happens on press */
2286 MixerStrip::input_active_button_release (GdkEventButton* ev)
2288 boost::shared_ptr<MidiTrack> mt = midi_track ();
2294 boost::shared_ptr<RouteList> rl (new RouteList);
2296 rl->push_back (route());
2298 _session->set_exclusive_input_active (rl, !mt->input_active(),
2299 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2305 MixerStrip::midi_input_status_changed ()
2307 if (midi_input_enable_button) {
2308 boost::shared_ptr<MidiTrack> mt = midi_track ();
2310 midi_input_enable_button->set_active (mt->input_active ());
2315 MixerStrip::state_id () const
2317 return string_compose ("strip %1", _route->id().to_s());
2321 MixerStrip::parameter_changed (string p)
2323 if (p == _visibility.get_state_name()) {
2324 /* The user has made changes to the mixer strip visibility, so get
2325 our VisibilityGroup to reflect these changes in our widgets.
2327 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2328 } else if (p == "track-name-number") {
2330 } else if (p == "use-monitor-bus") {
2331 if (monitor_section_button) {
2332 if (mute_button->get_parent()) {
2333 mute_button->get_parent()->remove(*mute_button);
2335 if (monitor_section_button->get_parent()) {
2336 monitor_section_button->get_parent()->remove(*monitor_section_button);
2338 if (Config->get_use_monitor_bus ()) {
2339 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2340 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2341 mute_button->show();
2342 monitor_section_button->show();
2344 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2345 mute_button->show();
2348 } else if (p == "track-name-number") {
2349 update_track_number_visibility();
2353 /** Called to decide whether the solo isolate / solo lock button visibility should
2354 * be overridden from that configured by the user. We do this for the master bus.
2356 * @return optional value that is present if visibility state should be overridden.
2358 boost::optional<bool>
2359 MixerStrip::override_solo_visibility () const
2361 if (_route && _route->is_master ()) {
2362 return boost::optional<bool> (false);
2365 return boost::optional<bool> ();
2369 MixerStrip::add_input_port (DataType t)
2371 _route->input()->add_port ("", this, t);
2375 MixerStrip::add_output_port (DataType t)
2377 _route->output()->add_port ("", this, t);
2381 MixerStrip::route_active_changed ()
2383 reset_strip_style ();
2387 MixerStrip::copy_processors ()
2389 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2393 MixerStrip::cut_processors ()
2395 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2399 MixerStrip::paste_processors ()
2401 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2405 MixerStrip::select_all_processors ()
2407 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2411 MixerStrip::deselect_all_processors ()
2413 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2417 MixerStrip::delete_processors ()
2419 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2423 MixerStrip::toggle_processors ()
2425 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2429 MixerStrip::ab_plugins ()
2431 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2435 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2437 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2440 if (ev->button == 3) {
2441 popup_level_meter_menu (ev);
2449 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2451 using namespace Gtk::Menu_Helpers;
2453 Gtk::Menu* m = manage (new Menu);
2454 MenuList& items = m->items ();
2456 RadioMenuItem::Group group;
2458 _suspend_menu_callbacks = true;
2459 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2460 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2461 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2462 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2463 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2465 if (gpm.meter_channels().n_audio() == 0) {
2466 m->popup (ev->button, ev->time);
2467 _suspend_menu_callbacks = false;
2471 RadioMenuItem::Group tgroup;
2472 items.push_back (SeparatorElem());
2474 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2475 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2476 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2477 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2478 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2479 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2480 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2481 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2482 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2483 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2484 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2487 if (_route->is_master()) {
2490 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2491 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2492 /* non-master bus */
2495 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2502 MeterType cmt = _route->meter_type();
2503 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2505 items.push_back (SeparatorElem());
2506 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2507 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2508 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2509 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2510 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2511 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2513 m->popup (ev->button, ev->time);
2514 _suspend_menu_callbacks = false;
2518 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2519 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2521 using namespace Menu_Helpers;
2523 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2524 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2525 i->set_active (_route->meter_point() == point);
2529 MixerStrip::set_meter_point (MeterPoint p)
2531 if (_suspend_menu_callbacks) return;
2532 _route->set_meter_point (p);
2536 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2537 RadioMenuItem::Group& group, string const & name, MeterType type)
2539 using namespace Menu_Helpers;
2541 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2542 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2543 i->set_active (_route->meter_type() == type);
2547 MixerStrip::set_meter_type (MeterType t)
2549 if (_suspend_menu_callbacks) return;
2554 MixerStrip::update_track_number_visibility ()
2556 DisplaySuspender ds;
2557 bool show_label = _session->config.get_track_name_number();
2559 if (_route && _route->is_master()) {
2564 number_label.show ();
2565 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2566 // except the width of the number label is subtracted from the name-hbox, so we
2567 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2568 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2570 number_label.set_size_request(tnw, -1);
2571 number_label.show ();
2573 number_label.hide ();
2578 MixerStrip::color () const
2580 return route_color ();
2584 MixerStrip::marked_for_display () const
2586 return !_route->presentation_info().hidden();
2590 MixerStrip::set_marked_for_display (bool yn)
2592 return RouteUI::mark_hidden (!yn);