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);
1587 RouteGroup *rg = _route->route_group();
1589 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1590 rg ? rg->name() : _("No Group"),
1598 MixerStrip::route_group_changed ()
1600 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1602 RouteGroup *rg = _route->route_group();
1605 group_button.set_text (PBD::short_version (rg->name(), 5));
1609 group_button.set_text (_("Grp"));
1612 group_button.set_text (_("~G"));
1619 MixerStrip::route_color_changed ()
1621 name_button.modify_bg (STATE_NORMAL, color());
1622 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1623 reset_strip_style ();
1627 MixerStrip::show_passthru_color ()
1629 reset_strip_style ();
1634 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1636 boost::shared_ptr<Processor> processor (p.lock ());
1637 if (!processor || !processor->display_to_user()) {
1640 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1641 ++_plugin_insert_cnt;
1645 MixerStrip::build_route_ops_menu ()
1647 using namespace Menu_Helpers;
1648 route_ops_menu = new Menu;
1649 route_ops_menu->set_name ("ArdourContextMenu");
1651 MenuList& items = route_ops_menu->items();
1653 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1655 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1657 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1659 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1661 items.push_back (SeparatorElem());
1663 if (!_route->is_master()) {
1664 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1666 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1667 rename_menu_item = &items.back();
1669 items.push_back (SeparatorElem());
1670 items.push_back (CheckMenuElem (_("Active")));
1671 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1672 i->set_active (_route->active());
1673 i->set_sensitive(! _session->transport_rolling());
1674 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1676 if (!Profile->get_mixbus ()) {
1677 items.push_back (SeparatorElem());
1678 items.push_back (CheckMenuElem (_("Strict I/O")));
1679 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1680 i->set_active (_route->strict_io());
1681 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1684 _plugin_insert_cnt = 0;
1685 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1686 if (_plugin_insert_cnt > 0) {
1687 items.push_back (SeparatorElem());
1688 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1691 items.push_back (SeparatorElem());
1692 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1694 items.push_back (SeparatorElem());
1695 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1696 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1697 denormal_menu_item->set_active (_route->denormal_protection());
1700 /* note that this relies on selection being shared across editor and
1701 mixer (or global to the backend, in the future), which is the only
1702 sane thing for users anyway.
1705 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1707 Selection& selection (PublicEditor::instance().get_selection());
1708 if (!selection.selected (rtav)) {
1709 selection.set (rtav);
1712 if (!_route->is_master()) {
1713 items.push_back (SeparatorElem());
1714 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1717 items.push_back (SeparatorElem());
1718 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1724 MixerStrip::name_button_button_press (GdkEventButton* ev)
1726 if (ev->button == 3) {
1727 list_route_operations ();
1729 /* do not allow rename if the track is record-enabled */
1730 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1731 route_ops_menu->popup (1, ev->time);
1740 MixerStrip::name_button_button_release (GdkEventButton* ev)
1742 if (ev->button == 1) {
1743 list_route_operations ();
1745 /* do not allow rename if the track is record-enabled */
1746 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1747 route_ops_menu->popup (1, ev->time);
1754 MixerStrip::number_button_button_press (GdkEventButton* ev)
1756 if ( ev->button == 3 ) {
1757 list_route_operations ();
1759 /* do not allow rename if the track is record-enabled */
1760 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1761 route_ops_menu->popup (1, ev->time);
1770 MixerStrip::list_route_operations ()
1772 delete route_ops_menu;
1773 build_route_ops_menu ();
1777 MixerStrip::set_selected (bool yn)
1779 AxisView::set_selected (yn);
1782 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1783 global_frame.set_name ("MixerStripSelectedFrame");
1785 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1786 global_frame.set_name ("MixerStripFrame");
1789 global_frame.queue_draw ();
1792 // processor_box.deselect_all_processors();
1796 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1798 if (what_changed.contains (ARDOUR::Properties::name)) {
1804 MixerStrip::name_changed ()
1808 name_button.set_text (_route->name());
1811 name_button.set_text (PBD::short_version (_route->name(), 5));
1815 set_tooltip (name_button, _route->name());
1817 if (_session->config.get_track_name_number()) {
1818 const int64_t track_number = _route->track_number ();
1819 if (track_number == 0) {
1820 number_label.set_text ("-");
1822 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1825 number_label.set_text ("");
1830 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1832 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1836 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1838 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1842 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1844 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1848 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1850 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1854 MixerStrip::width_button_pressed (GdkEventButton* ev)
1856 if (ev->button != 1) {
1860 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1863 _mixer.set_strip_width (Narrow, true);
1867 _mixer.set_strip_width (Wide, true);
1873 set_width_enum (Narrow, this);
1876 set_width_enum (Wide, this);
1885 MixerStrip::hide_clicked ()
1887 // LAME fix to reset the button status for when it is redisplayed (part 1)
1888 hide_button.set_sensitive(false);
1891 Hiding(); /* EMIT_SIGNAL */
1893 _mixer.hide_strip (this);
1897 hide_button.set_sensitive(true);
1901 MixerStrip::set_embedded (bool yn)
1907 MixerStrip::map_frozen ()
1909 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1911 boost::shared_ptr<AudioTrack> at = audio_track();
1914 switch (at->freeze_state()) {
1915 case AudioTrack::Frozen:
1916 processor_box.set_sensitive (false);
1917 hide_redirect_editors ();
1920 processor_box.set_sensitive (true);
1921 // XXX need some way, maybe, to retoggle redirect editors
1925 processor_box.set_sensitive (true);
1927 RouteUI::map_frozen ();
1931 MixerStrip::hide_redirect_editors ()
1933 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1937 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1939 boost::shared_ptr<Processor> processor (p.lock ());
1944 Gtk::Window* w = processor_box.get_processor_ui (processor);
1952 MixerStrip::reset_strip_style ()
1954 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1956 gpm.set_fader_name ("SendStripBase");
1960 if (is_midi_track()) {
1961 if (_route->active()) {
1962 set_name ("MidiTrackStripBase");
1964 set_name ("MidiTrackStripBaseInactive");
1966 gpm.set_fader_name ("MidiTrackFader");
1967 } else if (is_audio_track()) {
1968 if (_route->active()) {
1969 set_name ("AudioTrackStripBase");
1971 set_name ("AudioTrackStripBaseInactive");
1973 gpm.set_fader_name ("AudioTrackFader");
1975 if (_route->active()) {
1976 set_name ("AudioBusStripBase");
1978 set_name ("AudioBusStripBaseInactive");
1980 gpm.set_fader_name ("AudioBusFader");
1982 /* (no MIDI busses yet) */
1989 MixerStrip::engine_stopped ()
1994 MixerStrip::engine_running ()
1999 MixerStrip::meter_point_string (MeterPoint mp)
2012 case MeterPostFader:
2029 return S_("Meter|In");
2033 return S_("Meter|Pr");
2036 case MeterPostFader:
2037 return S_("Meter|Po");
2041 return S_("Meter|O");
2046 return S_("Meter|C");
2055 /** Called when the monitor-section state */
2057 MixerStrip::monitor_changed ()
2059 assert (monitor_section_button);
2060 if (_session->monitor_active()) {
2061 monitor_section_button->set_name ("master monitor section button active");
2063 monitor_section_button->set_name ("master monitor section button normal");
2067 /** Called when the metering point has changed */
2069 MixerStrip::meter_changed ()
2071 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2072 gpm.setup_meters ();
2073 // reset peak when meter point changes
2074 gpm.reset_peak_display();
2077 /** The bus that we are displaying sends to has changed, or been turned off.
2078 * @param send_to New bus that we are displaying sends to, or 0.
2081 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2083 RouteUI::bus_send_display_changed (send_to);
2086 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2091 revert_to_default_display ();
2094 revert_to_default_display ();
2099 MixerStrip::drop_send ()
2101 boost::shared_ptr<Send> current_send;
2103 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2104 current_send->set_metering (false);
2107 send_gone_connection.disconnect ();
2108 input_button.set_sensitive (true);
2109 output_button.set_sensitive (true);
2110 group_button.set_sensitive (true);
2111 set_invert_sensitive (true);
2112 meter_point_button.set_sensitive (true);
2113 mute_button->set_sensitive (true);
2114 solo_button->set_sensitive (true);
2115 solo_isolated_led->set_sensitive (true);
2116 solo_safe_led->set_sensitive (true);
2117 monitor_input_button->set_sensitive (true);
2118 monitor_disk_button->set_sensitive (true);
2119 _comment_button.set_sensitive (true);
2120 RouteUI::check_rec_enable_sensitivity ();
2121 set_button_names (); // update solo button visual state
2125 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2127 _current_delivery = d;
2128 DeliveryChanged (_current_delivery);
2132 MixerStrip::show_send (boost::shared_ptr<Send> send)
2138 set_current_delivery (send);
2140 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2141 send->set_metering (true);
2142 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2144 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2145 gain_meter().setup_meters ();
2147 uint32_t const in = _current_delivery->pans_required();
2148 uint32_t const out = _current_delivery->pan_outs();
2150 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2151 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2152 panner_ui().setup_pan ();
2153 panner_ui().set_send_drawing_mode (true);
2154 panner_ui().show_all ();
2156 input_button.set_sensitive (false);
2157 group_button.set_sensitive (false);
2158 set_invert_sensitive (false);
2159 meter_point_button.set_sensitive (false);
2160 mute_button->set_sensitive (false);
2161 solo_button->set_sensitive (false);
2162 rec_enable_button->set_sensitive (false);
2163 solo_isolated_led->set_sensitive (false);
2164 solo_safe_led->set_sensitive (false);
2165 monitor_input_button->set_sensitive (false);
2166 monitor_disk_button->set_sensitive (false);
2167 _comment_button.set_sensitive (false);
2169 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2170 output_button.set_sensitive (false);
2173 reset_strip_style ();
2177 MixerStrip::revert_to_default_display ()
2181 set_current_delivery (_route->main_outs ());
2183 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2184 gain_meter().setup_meters ();
2186 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2187 update_panner_choices();
2188 panner_ui().setup_pan ();
2189 panner_ui().set_send_drawing_mode (false);
2191 if (has_audio_outputs ()) {
2192 panners.show_all ();
2194 panners.hide_all ();
2197 reset_strip_style ();
2201 MixerStrip::set_button_names ()
2205 mute_button->set_text (_("Mute"));
2206 monitor_input_button->set_text (_("In"));
2207 monitor_disk_button->set_text (_("Disk"));
2208 if (monitor_section_button) {
2209 monitor_section_button->set_text (_("Mon"));
2212 if (_route && _route->solo_safe_control()->solo_safe()) {
2213 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2215 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2217 if (!Config->get_solo_control_is_listen_control()) {
2218 solo_button->set_text (_("Solo"));
2220 switch (Config->get_listen_position()) {
2221 case AfterFaderListen:
2222 solo_button->set_text (_("AFL"));
2224 case PreFaderListen:
2225 solo_button->set_text (_("PFL"));
2229 solo_isolated_led->set_text (_("Iso"));
2230 solo_safe_led->set_text (S_("SoloLock|Lock"));
2234 mute_button->set_text (S_("Mute|M"));
2235 monitor_input_button->set_text (S_("MonitorInput|I"));
2236 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2237 if (monitor_section_button) {
2238 monitor_section_button->set_text (S_("Mon|O"));
2241 if (_route && _route->solo_safe_control()->solo_safe()) {
2242 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2244 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2246 if (!Config->get_solo_control_is_listen_control()) {
2247 solo_button->set_text (S_("Solo|S"));
2249 switch (Config->get_listen_position()) {
2250 case AfterFaderListen:
2251 solo_button->set_text (S_("AfterFader|A"));
2253 case PreFaderListen:
2254 solo_button->set_text (S_("Prefader|P"));
2259 solo_isolated_led->set_text (S_("SoloIso|I"));
2260 solo_safe_led->set_text (S_("SoloLock|L"));
2265 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2267 meter_point_button.set_text ("");
2272 MixerStrip::plugin_selector()
2274 return _mixer.plugin_selector();
2278 MixerStrip::hide_things ()
2280 processor_box.hide_things ();
2284 MixerStrip::input_active_button_press (GdkEventButton*)
2286 /* nothing happens on press */
2291 MixerStrip::input_active_button_release (GdkEventButton* ev)
2293 boost::shared_ptr<MidiTrack> mt = midi_track ();
2299 boost::shared_ptr<RouteList> rl (new RouteList);
2301 rl->push_back (route());
2303 _session->set_exclusive_input_active (rl, !mt->input_active(),
2304 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2310 MixerStrip::midi_input_status_changed ()
2312 if (midi_input_enable_button) {
2313 boost::shared_ptr<MidiTrack> mt = midi_track ();
2315 midi_input_enable_button->set_active (mt->input_active ());
2320 MixerStrip::state_id () const
2322 return string_compose ("strip %1", _route->id().to_s());
2326 MixerStrip::parameter_changed (string p)
2328 if (p == _visibility.get_state_name()) {
2329 /* The user has made changes to the mixer strip visibility, so get
2330 our VisibilityGroup to reflect these changes in our widgets.
2332 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2333 } else if (p == "track-name-number") {
2335 } else if (p == "use-monitor-bus") {
2336 if (monitor_section_button) {
2337 if (mute_button->get_parent()) {
2338 mute_button->get_parent()->remove(*mute_button);
2340 if (monitor_section_button->get_parent()) {
2341 monitor_section_button->get_parent()->remove(*monitor_section_button);
2343 if (Config->get_use_monitor_bus ()) {
2344 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2345 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2346 mute_button->show();
2347 monitor_section_button->show();
2349 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2350 mute_button->show();
2353 } else if (p == "track-name-number") {
2354 update_track_number_visibility();
2358 /** Called to decide whether the solo isolate / solo lock button visibility should
2359 * be overridden from that configured by the user. We do this for the master bus.
2361 * @return optional value that is present if visibility state should be overridden.
2363 boost::optional<bool>
2364 MixerStrip::override_solo_visibility () const
2366 if (_route && _route->is_master ()) {
2367 return boost::optional<bool> (false);
2370 return boost::optional<bool> ();
2374 MixerStrip::add_input_port (DataType t)
2376 _route->input()->add_port ("", this, t);
2380 MixerStrip::add_output_port (DataType t)
2382 _route->output()->add_port ("", this, t);
2386 MixerStrip::route_active_changed ()
2388 reset_strip_style ();
2392 MixerStrip::copy_processors ()
2394 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2398 MixerStrip::cut_processors ()
2400 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2404 MixerStrip::paste_processors ()
2406 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2410 MixerStrip::select_all_processors ()
2412 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2416 MixerStrip::deselect_all_processors ()
2418 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2422 MixerStrip::delete_processors ()
2424 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2428 MixerStrip::toggle_processors ()
2430 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2434 MixerStrip::ab_plugins ()
2436 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2440 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2442 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2445 if (ev->button == 3) {
2446 popup_level_meter_menu (ev);
2454 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2456 using namespace Gtk::Menu_Helpers;
2458 Gtk::Menu* m = manage (new Menu);
2459 MenuList& items = m->items ();
2461 RadioMenuItem::Group group;
2463 _suspend_menu_callbacks = true;
2464 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2465 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2466 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2467 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2468 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2470 if (gpm.meter_channels().n_audio() == 0) {
2471 m->popup (ev->button, ev->time);
2472 _suspend_menu_callbacks = false;
2476 RadioMenuItem::Group tgroup;
2477 items.push_back (SeparatorElem());
2479 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2480 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2481 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2482 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2483 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2484 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2485 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2486 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2487 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2488 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2489 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2492 if (_route->is_master()) {
2495 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2496 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2497 /* non-master bus */
2500 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2507 MeterType cmt = _route->meter_type();
2508 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2510 items.push_back (SeparatorElem());
2511 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2512 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2513 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2514 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2515 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2516 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2518 m->popup (ev->button, ev->time);
2519 _suspend_menu_callbacks = false;
2523 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2524 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2526 using namespace Menu_Helpers;
2528 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2529 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2530 i->set_active (_route->meter_point() == point);
2534 MixerStrip::set_meter_point (MeterPoint p)
2536 if (_suspend_menu_callbacks) return;
2537 _route->set_meter_point (p);
2541 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2542 RadioMenuItem::Group& group, string const & name, MeterType type)
2544 using namespace Menu_Helpers;
2546 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2547 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2548 i->set_active (_route->meter_type() == type);
2552 MixerStrip::set_meter_type (MeterType t)
2554 if (_suspend_menu_callbacks) return;
2559 MixerStrip::update_track_number_visibility ()
2561 DisplaySuspender ds;
2562 bool show_label = _session->config.get_track_name_number();
2564 if (_route && _route->is_master()) {
2569 number_label.show ();
2570 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2571 // except the width of the number label is subtracted from the name-hbox, so we
2572 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2573 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2575 number_label.set_size_request(tnw, -1);
2576 number_label.show ();
2578 number_label.hide ();
2583 MixerStrip::color () const
2585 return route_color ();
2589 MixerStrip::marked_for_display () const
2591 return !_route->presentation_info().hidden();
2595 MixerStrip::set_marked_for_display (bool yn)
2597 return RouteUI::mark_hidden (!yn);