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;
156 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
157 longest_label = "longest label";
159 string t = _("Click to toggle the width of this mixer strip.");
161 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
164 width_button.set_icon (ArdourIcon::StripWidth);
165 hide_button.set_tweaks (ArdourButton::Square);
166 set_tooltip (width_button, t);
168 hide_button.set_icon (ArdourIcon::CloseCross);
169 hide_button.set_tweaks (ArdourButton::Square);
170 set_tooltip (&hide_button, _("Hide this mixer strip"));
172 input_button_box.set_spacing(2);
174 input_button.set_text (_("Input"));
175 input_button.set_name ("mixer strip button");
176 input_button_box.pack_start (input_button, true, true);
178 output_button.set_text (_("Output"));
179 output_button.set_name ("mixer strip button");
181 set_tooltip (&meter_point_button, _("Click to select metering point"));
182 meter_point_button.set_name ("mixer strip button");
184 bottom_button_table.attach (meter_point_button, 2, 3, 0, 1);
186 meter_point_button.signal_button_press_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_press), false);
187 meter_point_button.signal_button_release_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_release), false);
189 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
191 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
192 solo_isolated_led->show ();
193 solo_isolated_led->set_no_show_all (true);
194 solo_isolated_led->set_name (X_("solo isolate"));
195 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
196 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
197 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
199 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
200 solo_safe_led->show ();
201 solo_safe_led->set_no_show_all (true);
202 solo_safe_led->set_name (X_("solo safe"));
203 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
204 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
205 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
207 solo_safe_led->set_text (S_("SoloLock|Lock"));
208 solo_isolated_led->set_text (_("Iso"));
210 solo_iso_table.set_homogeneous (true);
211 solo_iso_table.set_spacings (2);
212 if (!ARDOUR::Profile->get_trx()) {
213 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
214 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
216 solo_iso_table.show ();
218 rec_mon_table.set_homogeneous (true);
219 rec_mon_table.set_row_spacings (2);
220 rec_mon_table.set_col_spacings (2);
221 if (ARDOUR::Profile->get_mixbus()) {
222 rec_mon_table.resize (1, 3);
223 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
224 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
225 } else if (!ARDOUR::Profile->get_trx()) {
226 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
227 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
229 rec_mon_table.show ();
231 if (solo_isolated_led) {
232 button_size_group->add_widget (*solo_isolated_led);
235 button_size_group->add_widget (*solo_safe_led);
238 if (!ARDOUR::Profile->get_mixbus()) {
239 if (rec_enable_button) {
240 button_size_group->add_widget (*rec_enable_button);
242 if (monitor_disk_button) {
243 button_size_group->add_widget (*monitor_disk_button);
245 if (monitor_input_button) {
246 button_size_group->add_widget (*monitor_input_button);
250 mute_solo_table.set_homogeneous (true);
251 mute_solo_table.set_spacings (2);
253 bottom_button_table.set_spacings (2);
254 bottom_button_table.set_homogeneous (true);
255 bottom_button_table.attach (group_button, 1, 2, 0, 1);
256 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
258 name_button.set_name ("mixer strip button");
259 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
260 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
262 set_tooltip (&group_button, _("Mix group"));
263 group_button.set_name ("mixer strip button");
265 _comment_button.set_name (X_("mixer strip button"));
266 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
267 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
268 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
270 // TODO implement ArdourKnob::on_size_request properly
271 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
272 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
274 trim_control.set_tooltip_prefix (_("Trim: "));
275 trim_control.set_name ("trim knob");
276 trim_control.set_no_show_all (true);
277 input_button_box.pack_start (trim_control, false, false);
279 global_vpacker.set_border_width (1);
280 global_vpacker.set_spacing (0);
282 width_button.set_name ("mixer strip button");
283 hide_button.set_name ("mixer strip button");
285 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
286 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
288 width_hide_box.set_spacing (2);
289 width_hide_box.pack_start (width_button, false, true);
290 width_hide_box.pack_start (number_label, true, true);
291 width_hide_box.pack_end (hide_button, false, true);
293 number_label.set_text ("-");
294 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
295 number_label.set_no_show_all ();
296 number_label.set_name ("tracknumber label");
297 number_label.set_fixed_colors (0x80808080, 0x80808080);
298 number_label.set_alignment (.5, .5);
299 number_label.set_fallthrough_to_parent (true);
300 number_label.set_tweaks (ArdourButton::OccasionalText);
302 global_vpacker.set_spacing (2);
303 if (!ARDOUR::Profile->get_trx()) {
304 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (processor_box, true, true);
310 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
317 if (!ARDOUR::Profile->get_trx()) {
318 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
321 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
324 //add a spacer underneath the master bus;
325 //this fills the area that is taken up by the scrollbar on the tracks;
326 //and therefore keeps the faders "even" across the bottom
327 HScrollbar scrollbar;
328 Gtk::Requisition requisition(scrollbar.size_request ());
329 int scrollbar_height = requisition.height;
330 spacer.set_size_request (-1, scrollbar_height+2); //+2 is a fudge factor to accomodate extra padding in mixer strip
331 global_vpacker.pack_end (spacer, false, false);
333 global_frame.add (global_vpacker);
334 global_frame.set_shadow_type (Gtk::SHADOW_IN);
335 global_frame.set_name ("BaseFrame");
339 /* force setting of visible selected status */
342 set_selected (false);
347 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
348 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
350 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
351 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
352 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
354 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
355 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
357 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
358 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
359 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
361 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
363 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
365 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
369 /* start off as a passthru strip. we'll correct this, if necessary,
370 in update_diskstream_display().
373 /* start off as a passthru strip. we'll correct this, if necessary,
374 in update_diskstream_display().
377 if (is_midi_track()) {
378 set_name ("MidiTrackStripBase");
380 set_name ("AudioTrackStripBase");
383 add_events (Gdk::BUTTON_RELEASE_MASK|
384 Gdk::ENTER_NOTIFY_MASK|
385 Gdk::LEAVE_NOTIFY_MASK|
387 Gdk::KEY_RELEASE_MASK);
389 set_flags (get_flags() | Gtk::CAN_FOCUS);
391 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
392 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
395 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
396 must be the same as those used in RCOptionEditor so that the configuration changes
397 are recognised when they occur.
399 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
400 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
401 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
402 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
403 _visibility.add (&output_button, X_("Output"), _("Output"), false);
404 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
405 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
407 parameter_changed (X_("mixer-element-visibility"));
408 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
409 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
410 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
412 //watch for mouse enter/exit so we can do some stuff
413 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
414 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
416 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
419 MixerStrip::~MixerStrip ()
421 CatchDeletion (this);
423 if (this ==_entered_mixer_strip)
424 _entered_mixer_strip = NULL;
428 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
430 _entered_mixer_strip = this;
432 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
433 //because the mixerstrip control is a parent that encompasses the strip
434 deselect_all_processors();
440 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
442 //if we have moved outside our strip, but not into a child view, then deselect ourselves
443 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
444 _entered_mixer_strip= 0;
446 //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
447 gpm.gain_display.set_sensitive(false);
449 gpm.gain_display.set_sensitive(true);
451 //if we leave this mixer strip we need to clear out any selections
452 //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
459 MixerStrip::name() const
462 return _route->name();
468 MixerStrip::update_trim_control ()
470 if (route()->trim() && route()->trim()->active() &&
471 route()->n_inputs().n_audio() > 0) {
472 trim_control.show ();
473 trim_control.set_controllable (route()->trim()->gain_control());
475 trim_control.hide ();
476 boost::shared_ptr<Controllable> none;
477 trim_control.set_controllable (none);
482 MixerStrip::set_route (boost::shared_ptr<Route> rt)
484 //the rec/monitor stuff only shows up for tracks.
485 //the show_sends only shows up for buses.
486 //remove them all here, and we may add them back later
487 if (show_sends_button->get_parent()) {
488 rec_mon_table.remove (*show_sends_button);
490 if (rec_enable_button->get_parent()) {
491 rec_mon_table.remove (*rec_enable_button);
493 if (monitor_input_button->get_parent()) {
494 rec_mon_table.remove (*monitor_input_button);
496 if (monitor_disk_button->get_parent()) {
497 rec_mon_table.remove (*monitor_disk_button);
499 if (group_button.get_parent()) {
500 bottom_button_table.remove (group_button);
503 RouteUI::set_route (rt);
505 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
507 /* ProcessorBox needs access to _route so that it can read
510 processor_box.set_route (rt);
512 revert_to_default_display ();
514 /* unpack these from the parent and stuff them into our own
518 if (gpm.peak_display.get_parent()) {
519 gpm.peak_display.get_parent()->remove (gpm.peak_display);
521 if (gpm.gain_display.get_parent()) {
522 gpm.gain_display.get_parent()->remove (gpm.gain_display);
525 gpm.set_type (rt->meter_type());
527 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
528 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
530 if (solo_button->get_parent()) {
531 mute_solo_table.remove (*solo_button);
534 if (mute_button->get_parent()) {
535 mute_solo_table.remove (*mute_button);
538 if (route()->is_master()) {
539 solo_button->hide ();
540 mute_button->show ();
541 rec_mon_table.hide ();
542 if (solo_iso_table.get_parent()) {
543 solo_iso_table.get_parent()->remove(solo_iso_table);
545 if (monitor_section_button == 0) {
546 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
547 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
549 monitor_section_button = manage (new ArdourButton);
551 monitor_section_button->set_related_action (act);
552 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
553 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
554 monitor_section_button->show();
555 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
557 parameter_changed ("use-monitor-bus");
559 bottom_button_table.attach (group_button, 1, 2, 0, 1);
560 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
561 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
562 mute_button->show ();
563 solo_button->show ();
564 rec_mon_table.show ();
567 if (_mixer_owned && route()->is_master() ) {
574 monitor_input_button->show ();
575 monitor_disk_button->show ();
577 monitor_input_button->hide();
578 monitor_disk_button->hide ();
581 update_trim_control();
583 if (is_midi_track()) {
584 if (midi_input_enable_button == 0) {
585 midi_input_enable_button = manage (new ArdourButton);
586 midi_input_enable_button->set_name ("midi input button");
587 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
588 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
589 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
590 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
591 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
593 input_button_box.remove (*midi_input_enable_button);
595 /* get current state */
596 midi_input_status_changed ();
597 input_button_box.pack_start (*midi_input_enable_button, false, false);
599 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
601 if (midi_input_enable_button) {
602 /* removal from the container will delete it */
603 input_button_box.remove (*midi_input_enable_button);
604 midi_input_enable_button = 0;
608 if (is_audio_track()) {
609 boost::shared_ptr<AudioTrack> at = audio_track();
610 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
615 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
616 rec_enable_button->show();
618 if (ARDOUR::Profile->get_mixbus()) {
619 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
620 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
621 } else if (ARDOUR::Profile->get_trx()) {
622 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
624 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
625 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
632 if (!_route->is_master()) {
633 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
634 show_sends_button->show();
638 meter_point_button.set_text (meter_point_string (_route->meter_point()));
640 delete route_ops_menu;
643 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
644 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
645 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
646 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
648 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
650 if (_route->panner_shell()) {
651 update_panner_choices();
652 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
655 if (is_audio_track()) {
656 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
659 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
661 set_stuff_from_route ();
663 /* now force an update of all the various elements */
665 update_mute_display ();
666 update_solo_display ();
669 route_group_changed ();
670 update_track_number_visibility ();
673 panners.setup_pan ();
675 if (has_audio_outputs ()) {
681 update_diskstream_display ();
682 update_input_display ();
683 update_output_display ();
685 add_events (Gdk::BUTTON_RELEASE_MASK);
687 processor_box.show ();
689 if (!route()->is_master() && !route()->is_monitor()) {
690 /* we don't allow master or control routes to be hidden */
695 gpm.reset_peak_display ();
696 gpm.gain_display.show ();
697 gpm.peak_display.show ();
700 width_hide_box.show();
702 global_vpacker.show();
703 mute_solo_table.show();
704 bottom_button_table.show();
706 meter_point_button.show();
707 input_button_box.show_all();
708 output_button.show();
710 _comment_button.show();
712 gpm.gain_automation_state_button.show();
714 parameter_changed ("mixer-element-visibility");
721 MixerStrip::set_stuff_from_route ()
723 /* if width is not set, it will be set by the MixerUI or editor */
725 string str = gui_property ("strip-width");
727 set_width_enum (Width (string_2_enum (str, _width)), this);
732 MixerStrip::set_width_enum (Width w, void* owner)
734 /* always set the gpm width again, things may be hidden */
737 panners.set_width (w);
739 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
741 _width_owner = owner;
745 if (_width_owner == this) {
746 set_gui_property ("strip-width", enum_2_string (_width));
751 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
756 if (show_sends_button) {
757 show_sends_button->set_text (_("Aux"));
760 gpm.gain_automation_style_button.set_text (
761 gpm.astyle_string(gain_automation->automation_style()));
762 gpm.gain_automation_state_button.set_text (
763 gpm.astate_string(gain_automation->automation_state()));
765 if (_route->panner()) {
766 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
767 panners.astyle_string(_route->panner()->automation_style()));
768 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
769 panners.astate_string(_route->panner()->automation_state()));
773 // panners expect an even number of horiz. pixels
774 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
776 set_size_request (width, -1);
782 if (show_sends_button) {
783 show_sends_button->set_text (_("Snd"));
786 gpm.gain_automation_style_button.set_text (
787 gpm.short_astyle_string(gain_automation->automation_style()));
788 gpm.gain_automation_state_button.set_text (
789 gpm.short_astate_string(gain_automation->automation_state()));
790 gain_meter().setup_meters (); // recalc meter width
792 if (_route->panner()) {
793 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
794 panners.short_astyle_string(_route->panner()->automation_style()));
795 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
796 panners.short_astate_string(_route->panner()->automation_state()));
800 // panners expect an even number of horiz. pixels
801 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
803 set_size_request (width, -1);
808 processor_box.set_width (w);
810 update_input_display ();
811 update_output_display ();
812 setup_comment_button ();
813 route_group_changed ();
819 MixerStrip::set_packed (bool yn)
824 set_gui_property ("visible", true);
826 set_gui_property ("visible", false);
831 struct RouteCompareByName {
832 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
833 return a->name().compare (b->name()) < 0;
838 MixerStrip::output_release (GdkEventButton *ev)
840 switch (ev->button) {
842 edit_output_configuration ();
850 MixerStrip::output_press (GdkEventButton *ev)
852 using namespace Menu_Helpers;
853 if (!_session->engine().connected()) {
854 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
859 MenuList& citems = output_menu.items();
860 switch (ev->button) {
863 return false; //wait for the mouse-up to pop the dialog
867 output_menu.set_name ("ArdourContextMenu");
869 output_menu_bundles.clear ();
871 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
873 citems.push_back (SeparatorElem());
874 uint32_t const n_with_separator = citems.size ();
876 ARDOUR::BundleList current = _route->output()->bundles_connected ();
878 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
880 /* give user bundles first chance at being in the menu */
882 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
883 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
884 maybe_add_bundle_to_output_menu (*i, current);
888 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
889 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
890 maybe_add_bundle_to_output_menu (*i, current);
894 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
895 RouteList copy = *routes;
896 copy.sort (RouteCompareByName ());
897 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
898 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
901 if (citems.size() == n_with_separator) {
902 /* no routes added; remove the separator */
906 if (!ARDOUR::Profile->get_mixbus()) {
907 citems.push_back (SeparatorElem());
909 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
912 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
913 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
919 citems.push_back (SeparatorElem());
920 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
922 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
935 MixerStrip::input_release (GdkEventButton *ev)
937 switch (ev->button) {
940 edit_input_configuration ();
952 MixerStrip::input_press (GdkEventButton *ev)
954 using namespace Menu_Helpers;
956 MenuList& citems = input_menu.items();
957 input_menu.set_name ("ArdourContextMenu");
960 if (!_session->engine().connected()) {
961 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
966 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
969 switch (ev->button) {
972 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
976 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
978 citems.push_back (SeparatorElem());
979 uint32_t const n_with_separator = citems.size ();
981 input_menu_bundles.clear ();
983 ARDOUR::BundleList current = _route->input()->bundles_connected ();
985 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
987 /* give user bundles first chance at being in the menu */
989 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
990 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
991 maybe_add_bundle_to_input_menu (*i, current);
995 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
996 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
997 maybe_add_bundle_to_input_menu (*i, current);
1001 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1002 RouteList copy = *routes;
1003 copy.sort (RouteCompareByName ());
1004 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1005 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1008 if (citems.size() == n_with_separator) {
1009 /* no routes added; remove the separator */
1013 citems.push_back (SeparatorElem());
1014 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1017 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1018 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1023 citems.push_back (SeparatorElem());
1024 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1026 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1038 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1040 if (ignore_toggle) {
1044 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1046 if (std::find (current.begin(), current.end(), c) == current.end()) {
1047 _route->input()->connect_ports_to_bundle (c, true, this);
1049 _route->input()->disconnect_ports_from_bundle (c, this);
1054 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1056 if (ignore_toggle) {
1060 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1062 if (std::find (current.begin(), current.end(), c) == current.end()) {
1063 _route->output()->connect_ports_to_bundle (c, true, this);
1065 _route->output()->disconnect_ports_from_bundle (c, this);
1070 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1072 using namespace Menu_Helpers;
1074 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1078 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1079 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1083 if (i != input_menu_bundles.end()) {
1087 input_menu_bundles.push_back (b);
1089 MenuList& citems = input_menu.items();
1091 std::string n = b->name ();
1092 replace_all (n, "_", " ");
1094 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1098 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1100 using namespace Menu_Helpers;
1102 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1106 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1107 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1111 if (i != output_menu_bundles.end()) {
1115 output_menu_bundles.push_back (b);
1117 MenuList& citems = output_menu.items();
1119 std::string n = b->name ();
1120 replace_all (n, "_", " ");
1122 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1126 MixerStrip::update_diskstream_display ()
1128 if (is_track() && input_selector) {
1129 input_selector->hide_all ();
1132 route_color_changed ();
1136 MixerStrip::connect_to_pan ()
1138 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1140 panstate_connection.disconnect ();
1141 panstyle_connection.disconnect ();
1143 if (!_route->panner()) {
1147 boost::shared_ptr<Pannable> p = _route->pannable ();
1149 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1150 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1152 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1153 * However, that only works a panner was previously set.
1155 * PannerUI must remain subscribed to _panshell->Changed() in case
1156 * we switch the panner eg. AUX-Send and back
1157 * _route->panner_shell()->Changed() vs _panshell->Changed
1159 if (panners._panner == 0) {
1160 panners.panshell_changed ();
1162 update_panner_choices();
1166 MixerStrip::update_panner_choices ()
1168 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1169 if (!_route->panner_shell()) { return; }
1171 uint32_t in = _route->output()->n_ports().n_audio();
1173 if (_route->panner()) {
1174 in = _route->panner()->in().n_audio();
1177 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1181 * Output port labelling
1182 * =====================
1184 * Case 1: Each output has one connection, all connections are to system:playback_%i
1185 * out 1 -> system:playback_1
1186 * out 2 -> system:playback_2
1187 * out 3 -> system:playback_3
1190 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1191 * out 1 -> ardour:track_x/in 1
1192 * out 2 -> ardour:track_x/in 2
1193 * Display as: track_x
1195 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1196 * out 1 -> program x:foo
1197 * out 2 -> program x:foo
1198 * Display as: program x
1200 * Case 4: No connections (Disconnected)
1203 * Default case (unusual routing):
1204 * Display as: *number of connections*
1208 * .-----------------------------------------------.
1210 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1211 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1212 * '-----------------------------------------------'
1213 * .-----------------------------------------------.
1216 * '-----------------------------------------------'
1220 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1224 boost::shared_ptr<IO> io;
1225 boost::shared_ptr<Port> port;
1226 vector<string> port_connections;
1228 uint32_t total_connection_count = 0;
1229 uint32_t io_connection_count = 0;
1230 uint32_t ardour_connection_count = 0;
1231 uint32_t system_connection_count = 0;
1232 uint32_t other_connection_count = 0;
1233 uint32_t typed_connection_count = 0;
1235 ostringstream label;
1237 bool have_label = false;
1238 bool each_io_has_one_connection = true;
1240 string connection_name;
1241 string ardour_track_name;
1242 string other_connection_type;
1243 string system_ports;
1246 ostringstream tooltip;
1247 char * tooltip_cstr;
1249 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1251 * First of all, if the user made only connections to a given type, we should use that one since
1252 * it is very probably what the user expects. If there are several connections types, then show
1253 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1254 * synthesisers. This first heuristic can be expressed with these two rules:
1255 * A) If there are connected audio ports, consider audio as primary type.
1256 * B) Else, if there are connected midi ports, consider midi as primary type.
1258 * If there are no connected ports, then we choose the primary type based on the type of existing
1259 * but unconnected ports. Again:
1260 * C) If there are audio ports, consider audio as primary type.
1261 * D) Else, if there are midi ports, consider midi as primary type. */
1263 DataType dt = DataType::AUDIO;
1267 io = route->input();
1269 io = route->output();
1272 io_count = io->n_ports().n_total();
1273 for (io_index = 0; io_index < io_count; ++io_index) {
1274 port = io->nth (io_index);
1275 if (port->connected()) {
1277 if (port->type() == DataType::AUDIO) {
1278 /* Rule A) applies no matter the remaining ports */
1279 dt = DataType::AUDIO;
1282 if (port->type() == DataType::MIDI) {
1283 /* Rule B) is a good candidate... */
1284 dt = DataType::MIDI;
1285 /* ...but continue the loop to check remaining ports for rule A) */
1291 /* Neither rule A) nor rule B) matched */
1292 if ( io->n_ports().n_audio() > 0 ) {
1294 dt = DataType::AUDIO;
1295 } else if ( io->n_ports().n_midi() > 0 ) {
1297 dt = DataType::MIDI;
1301 if ( dt == DataType::MIDI ) {
1302 tooltip << _("MIDI ");
1306 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1308 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1311 for (io_index = 0; io_index < io_count; ++io_index) {
1312 port = io->nth (io_index);
1314 port_connections.clear ();
1315 port->get_connections(port_connections);
1317 //ignore any port connections that don't match our DataType
1318 if (port->type() != dt) {
1319 if (!port_connections.empty()) {
1320 ++typed_connection_count;
1325 io_connection_count = 0;
1327 if (!port_connections.empty()) {
1328 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1330 string& connection_name (*i);
1332 if (connection_name.find("system:") == 0) {
1333 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1336 if (io_connection_count == 0) {
1337 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1339 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1342 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1345 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1346 if (ardour_track_name.empty()) {
1347 // "ardour:Master/in 1" -> "ardour:Master/"
1348 string::size_type slash = connection_name.find("/");
1349 if (slash != string::npos) {
1350 ardour_track_name = connection_name.substr(0, slash + 1);
1354 if (connection_name.find(ardour_track_name) == 0) {
1355 ++ardour_connection_count;
1357 } else if (!pn.empty()) {
1358 if (system_ports.empty()) {
1361 system_ports += "/" + pn;
1363 if (connection_name.find("system:") == 0) {
1364 ++system_connection_count;
1366 } else if (connection_name.find("system:midi_") == 0) {
1368 // "system:midi_capture_123" -> "123"
1369 system_port = "M " + connection_name.substr(20);
1371 // "system:midi_playback_123" -> "123"
1372 system_port = "M " + connection_name.substr(21);
1375 if (system_ports.empty()) {
1376 system_ports += system_port;
1378 system_ports += "/" + system_port;
1381 ++system_connection_count;
1383 } else if (connection_name.find("system:") == 0) {
1385 // "system:capture_123" -> "123"
1386 system_port = connection_name.substr(15);
1388 // "system:playback_123" -> "123"
1389 system_port = connection_name.substr(16);
1392 if (system_ports.empty()) {
1393 system_ports += system_port;
1395 system_ports += "/" + system_port;
1398 ++system_connection_count;
1400 if (other_connection_type.empty()) {
1401 // "jamin:in 1" -> "jamin:"
1402 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1405 if (connection_name.find(other_connection_type) == 0) {
1406 ++other_connection_count;
1410 ++total_connection_count;
1411 ++io_connection_count;
1415 if (io_connection_count != 1) {
1416 each_io_has_one_connection = false;
1420 if (total_connection_count == 0) {
1421 tooltip << endl << _("Disconnected");
1424 tooltip_cstr = new char[tooltip.str().size() + 1];
1425 strcpy(tooltip_cstr, tooltip.str().c_str());
1428 set_tooltip (&input_button, tooltip_cstr);
1430 set_tooltip (&output_button, tooltip_cstr);
1433 delete [] tooltip_cstr;
1435 if (each_io_has_one_connection) {
1436 if (total_connection_count == ardour_connection_count) {
1437 // all connections are to the same track in ardour
1438 // "ardour:Master/" -> "Master"
1439 string::size_type slash = ardour_track_name.find("/");
1440 if (slash != string::npos) {
1441 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1442 label << ardour_track_name.substr (ppps, slash - ppps);
1446 else if (total_connection_count == system_connection_count) {
1447 // all connections are to system ports
1448 label << system_ports;
1451 else if (total_connection_count == other_connection_count) {
1452 // all connections are to the same external program eg jamin
1453 // "jamin:" -> "jamin"
1454 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1460 if (total_connection_count == 0) {
1464 // Odd configuration
1465 label << "*" << total_connection_count << "*";
1467 if (typed_connection_count > 0) {
1468 label << "\u2295"; // circled plus
1473 input_button.set_text (label.str());
1475 output_button.set_text (label.str());
1480 MixerStrip::update_input_display ()
1482 update_io_button (_route, _width, true);
1483 panners.setup_pan ();
1485 if (has_audio_outputs ()) {
1486 panners.show_all ();
1488 panners.hide_all ();
1494 MixerStrip::update_output_display ()
1496 update_io_button (_route, _width, false);
1497 gpm.setup_meters ();
1498 panners.setup_pan ();
1500 if (has_audio_outputs ()) {
1501 panners.show_all ();
1503 panners.hide_all ();
1508 MixerStrip::fast_update ()
1510 gpm.update_meters ();
1514 MixerStrip::diskstream_changed ()
1516 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1520 MixerStrip::io_changed_proxy ()
1522 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1523 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1527 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1529 boost::shared_ptr<Port> a = wa.lock ();
1530 boost::shared_ptr<Port> b = wb.lock ();
1532 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1533 update_input_display ();
1534 set_width_enum (_width, this);
1537 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1538 update_output_display ();
1539 set_width_enum (_width, this);
1544 MixerStrip::setup_comment_button ()
1546 std::string comment = _route->comment();
1548 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1550 if (comment.empty ()) {
1551 _comment_button.set_name ("generic button");
1552 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1556 _comment_button.set_name ("comment button");
1558 string::size_type pos = comment.find_first_of (" \t\n");
1559 if (pos != string::npos) {
1560 comment = comment.substr (0, pos);
1562 if (comment.empty()) {
1563 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1565 _comment_button.set_text (comment);
1570 MixerStrip::select_route_group (GdkEventButton *ev)
1572 using namespace Menu_Helpers;
1574 if (ev->button == 1) {
1576 if (group_menu == 0) {
1578 PropertyList* plist = new PropertyList();
1580 plist->add (Properties::group_gain, true);
1581 plist->add (Properties::group_mute, true);
1582 plist->add (Properties::group_solo, true);
1584 group_menu = new RouteGroupMenu (_session, plist);
1588 r.push_back (route ());
1589 group_menu->build (r);
1591 RouteGroup *rg = _route->route_group();
1593 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1594 rg ? rg->name() : _("No Group"),
1602 MixerStrip::route_group_changed ()
1604 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1606 RouteGroup *rg = _route->route_group();
1609 group_button.set_text (PBD::short_version (rg->name(), 5));
1613 group_button.set_text (_("Grp"));
1616 group_button.set_text (_("~G"));
1623 MixerStrip::route_color_changed ()
1625 name_button.modify_bg (STATE_NORMAL, color());
1626 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1627 reset_strip_style ();
1631 MixerStrip::show_passthru_color ()
1633 reset_strip_style ();
1638 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1640 boost::shared_ptr<Processor> processor (p.lock ());
1641 if (!processor || !processor->display_to_user()) {
1644 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1646 if (pi && pi->is_channelstrip ()) {
1651 ++_plugin_insert_cnt;
1655 MixerStrip::build_route_ops_menu ()
1657 using namespace Menu_Helpers;
1658 route_ops_menu = new Menu;
1659 route_ops_menu->set_name ("ArdourContextMenu");
1661 MenuList& items = route_ops_menu->items();
1663 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1665 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1667 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1669 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1671 items.push_back (SeparatorElem());
1673 if (!_route->is_master()) {
1674 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1676 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1677 rename_menu_item = &items.back();
1679 items.push_back (SeparatorElem());
1680 items.push_back (CheckMenuElem (_("Active")));
1681 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1682 i->set_active (_route->active());
1683 i->set_sensitive(! _session->transport_rolling());
1684 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1686 if (!Profile->get_mixbus ()) {
1687 items.push_back (SeparatorElem());
1688 items.push_back (CheckMenuElem (_("Strict I/O")));
1689 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1690 i->set_active (_route->strict_io());
1691 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1694 _plugin_insert_cnt = 0;
1695 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1696 if (_plugin_insert_cnt > 0) {
1697 items.push_back (SeparatorElem());
1698 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1701 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1702 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1703 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1704 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1707 items.push_back (SeparatorElem());
1708 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1710 items.push_back (SeparatorElem());
1711 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1712 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1713 denormal_menu_item->set_active (_route->denormal_protection());
1716 /* note that this relies on selection being shared across editor and
1717 mixer (or global to the backend, in the future), which is the only
1718 sane thing for users anyway.
1721 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1723 Selection& selection (PublicEditor::instance().get_selection());
1724 if (!selection.selected (rtav)) {
1725 selection.set (rtav);
1728 if (!_route->is_master()) {
1729 items.push_back (SeparatorElem());
1730 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1733 items.push_back (SeparatorElem());
1734 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1740 MixerStrip::name_button_button_press (GdkEventButton* ev)
1742 if (ev->button == 1 || ev->button == 3) {
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 if (ev->button == 1) {
1748 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1751 route_ops_menu->popup (3, ev->time);
1761 MixerStrip::number_button_button_press (GdkEventButton* ev)
1763 if ( ev->button == 3 ) {
1764 list_route_operations ();
1766 /* do not allow rename if the track is record-enabled */
1767 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1768 route_ops_menu->popup (1, ev->time);
1777 MixerStrip::list_route_operations ()
1779 delete route_ops_menu;
1780 build_route_ops_menu ();
1784 MixerStrip::set_selected (bool yn)
1786 AxisView::set_selected (yn);
1789 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1790 global_frame.set_name ("MixerStripSelectedFrame");
1792 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1793 global_frame.set_name ("MixerStripFrame");
1796 global_frame.queue_draw ();
1799 // processor_box.deselect_all_processors();
1803 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1805 if (what_changed.contains (ARDOUR::Properties::name)) {
1811 MixerStrip::name_changed ()
1815 name_button.set_text (_route->name());
1818 name_button.set_text (PBD::short_version (_route->name(), 5));
1822 set_tooltip (name_button, _route->name());
1824 if (_session->config.get_track_name_number()) {
1825 const int64_t track_number = _route->track_number ();
1826 if (track_number == 0) {
1827 number_label.set_text ("-");
1829 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1832 number_label.set_text ("");
1837 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1839 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1843 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1845 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1849 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1851 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1855 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1857 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1861 MixerStrip::width_button_pressed (GdkEventButton* ev)
1863 if (ev->button != 1) {
1867 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1870 _mixer.set_strip_width (Narrow, true);
1874 _mixer.set_strip_width (Wide, true);
1880 set_width_enum (Narrow, this);
1883 set_width_enum (Wide, this);
1892 MixerStrip::hide_clicked ()
1894 // LAME fix to reset the button status for when it is redisplayed (part 1)
1895 hide_button.set_sensitive(false);
1898 Hiding(); /* EMIT_SIGNAL */
1900 _mixer.hide_strip (this);
1904 hide_button.set_sensitive(true);
1908 MixerStrip::set_embedded (bool yn)
1914 MixerStrip::map_frozen ()
1916 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1918 boost::shared_ptr<AudioTrack> at = audio_track();
1921 switch (at->freeze_state()) {
1922 case AudioTrack::Frozen:
1923 processor_box.set_sensitive (false);
1924 hide_redirect_editors ();
1927 processor_box.set_sensitive (true);
1928 // XXX need some way, maybe, to retoggle redirect editors
1932 processor_box.set_sensitive (true);
1934 RouteUI::map_frozen ();
1938 MixerStrip::hide_redirect_editors ()
1940 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1944 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1946 boost::shared_ptr<Processor> processor (p.lock ());
1951 Gtk::Window* w = processor_box.get_processor_ui (processor);
1959 MixerStrip::reset_strip_style ()
1961 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1963 gpm.set_fader_name ("SendStripBase");
1967 if (is_midi_track()) {
1968 if (_route->active()) {
1969 set_name ("MidiTrackStripBase");
1971 set_name ("MidiTrackStripBaseInactive");
1973 gpm.set_fader_name ("MidiTrackFader");
1974 } else if (is_audio_track()) {
1975 if (_route->active()) {
1976 set_name ("AudioTrackStripBase");
1978 set_name ("AudioTrackStripBaseInactive");
1980 gpm.set_fader_name ("AudioTrackFader");
1982 if (_route->active()) {
1983 set_name ("AudioBusStripBase");
1985 set_name ("AudioBusStripBaseInactive");
1987 gpm.set_fader_name ("AudioBusFader");
1989 /* (no MIDI busses yet) */
1996 MixerStrip::engine_stopped ()
2001 MixerStrip::engine_running ()
2006 MixerStrip::meter_point_string (MeterPoint mp)
2019 case MeterPostFader:
2036 return S_("Meter|In");
2040 return S_("Meter|Pr");
2043 case MeterPostFader:
2044 return S_("Meter|Po");
2048 return S_("Meter|O");
2053 return S_("Meter|C");
2062 /** Called when the monitor-section state */
2064 MixerStrip::monitor_changed ()
2066 assert (monitor_section_button);
2067 if (_session->monitor_active()) {
2068 monitor_section_button->set_name ("master monitor section button active");
2070 monitor_section_button->set_name ("master monitor section button normal");
2074 /** Called when the metering point has changed */
2076 MixerStrip::meter_changed ()
2078 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2079 gpm.setup_meters ();
2080 // reset peak when meter point changes
2081 gpm.reset_peak_display();
2084 /** The bus that we are displaying sends to has changed, or been turned off.
2085 * @param send_to New bus that we are displaying sends to, or 0.
2088 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2090 RouteUI::bus_send_display_changed (send_to);
2093 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2098 revert_to_default_display ();
2101 revert_to_default_display ();
2106 MixerStrip::drop_send ()
2108 boost::shared_ptr<Send> current_send;
2110 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2111 current_send->set_metering (false);
2114 send_gone_connection.disconnect ();
2115 input_button.set_sensitive (true);
2116 output_button.set_sensitive (true);
2117 group_button.set_sensitive (true);
2118 set_invert_sensitive (true);
2119 meter_point_button.set_sensitive (true);
2120 mute_button->set_sensitive (true);
2121 solo_button->set_sensitive (true);
2122 solo_isolated_led->set_sensitive (true);
2123 solo_safe_led->set_sensitive (true);
2124 monitor_input_button->set_sensitive (true);
2125 monitor_disk_button->set_sensitive (true);
2126 _comment_button.set_sensitive (true);
2127 RouteUI::check_rec_enable_sensitivity ();
2128 set_button_names (); // update solo button visual state
2132 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2134 _current_delivery = d;
2135 DeliveryChanged (_current_delivery);
2139 MixerStrip::show_send (boost::shared_ptr<Send> send)
2145 set_current_delivery (send);
2147 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2148 send->set_metering (true);
2149 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2151 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2152 gain_meter().setup_meters ();
2154 uint32_t const in = _current_delivery->pans_required();
2155 uint32_t const out = _current_delivery->pan_outs();
2157 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2158 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2159 panner_ui().setup_pan ();
2160 panner_ui().set_send_drawing_mode (true);
2161 panner_ui().show_all ();
2163 input_button.set_sensitive (false);
2164 group_button.set_sensitive (false);
2165 set_invert_sensitive (false);
2166 meter_point_button.set_sensitive (false);
2167 mute_button->set_sensitive (false);
2168 solo_button->set_sensitive (false);
2169 rec_enable_button->set_sensitive (false);
2170 solo_isolated_led->set_sensitive (false);
2171 solo_safe_led->set_sensitive (false);
2172 monitor_input_button->set_sensitive (false);
2173 monitor_disk_button->set_sensitive (false);
2174 _comment_button.set_sensitive (false);
2176 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2177 output_button.set_sensitive (false);
2180 reset_strip_style ();
2184 MixerStrip::revert_to_default_display ()
2188 set_current_delivery (_route->main_outs ());
2190 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2191 gain_meter().setup_meters ();
2193 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2194 update_panner_choices();
2195 panner_ui().setup_pan ();
2196 panner_ui().set_send_drawing_mode (false);
2198 if (has_audio_outputs ()) {
2199 panners.show_all ();
2201 panners.hide_all ();
2204 reset_strip_style ();
2208 MixerStrip::set_button_names ()
2212 mute_button->set_text (_("Mute"));
2213 monitor_input_button->set_text (_("In"));
2214 monitor_disk_button->set_text (_("Disk"));
2215 if (monitor_section_button) {
2216 monitor_section_button->set_text (_("Mon"));
2219 if (_route && _route->solo_safe_control()->solo_safe()) {
2220 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2222 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2224 if (!Config->get_solo_control_is_listen_control()) {
2225 solo_button->set_text (_("Solo"));
2227 switch (Config->get_listen_position()) {
2228 case AfterFaderListen:
2229 solo_button->set_text (_("AFL"));
2231 case PreFaderListen:
2232 solo_button->set_text (_("PFL"));
2236 solo_isolated_led->set_text (_("Iso"));
2237 solo_safe_led->set_text (S_("SoloLock|Lock"));
2241 mute_button->set_text (S_("Mute|M"));
2242 monitor_input_button->set_text (S_("MonitorInput|I"));
2243 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2244 if (monitor_section_button) {
2245 monitor_section_button->set_text (S_("Mon|O"));
2248 if (_route && _route->solo_safe_control()->solo_safe()) {
2249 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2251 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2253 if (!Config->get_solo_control_is_listen_control()) {
2254 solo_button->set_text (S_("Solo|S"));
2256 switch (Config->get_listen_position()) {
2257 case AfterFaderListen:
2258 solo_button->set_text (S_("AfterFader|A"));
2260 case PreFaderListen:
2261 solo_button->set_text (S_("Prefader|P"));
2266 solo_isolated_led->set_text (S_("SoloIso|I"));
2267 solo_safe_led->set_text (S_("SoloLock|L"));
2272 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2274 meter_point_button.set_text ("");
2279 MixerStrip::plugin_selector()
2281 return _mixer.plugin_selector();
2285 MixerStrip::hide_things ()
2287 processor_box.hide_things ();
2291 MixerStrip::input_active_button_press (GdkEventButton*)
2293 /* nothing happens on press */
2298 MixerStrip::input_active_button_release (GdkEventButton* ev)
2300 boost::shared_ptr<MidiTrack> mt = midi_track ();
2306 boost::shared_ptr<RouteList> rl (new RouteList);
2308 rl->push_back (route());
2310 _session->set_exclusive_input_active (rl, !mt->input_active(),
2311 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2317 MixerStrip::midi_input_status_changed ()
2319 if (midi_input_enable_button) {
2320 boost::shared_ptr<MidiTrack> mt = midi_track ();
2322 midi_input_enable_button->set_active (mt->input_active ());
2327 MixerStrip::state_id () const
2329 return string_compose ("strip %1", _route->id().to_s());
2333 MixerStrip::parameter_changed (string p)
2335 if (p == _visibility.get_state_name()) {
2336 /* The user has made changes to the mixer strip visibility, so get
2337 our VisibilityGroup to reflect these changes in our widgets.
2339 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2340 } else if (p == "track-name-number") {
2342 } else if (p == "use-monitor-bus") {
2343 if (monitor_section_button) {
2344 if (mute_button->get_parent()) {
2345 mute_button->get_parent()->remove(*mute_button);
2347 if (monitor_section_button->get_parent()) {
2348 monitor_section_button->get_parent()->remove(*monitor_section_button);
2350 if (Config->get_use_monitor_bus ()) {
2351 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2352 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2353 mute_button->show();
2354 monitor_section_button->show();
2356 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2357 mute_button->show();
2360 } else if (p == "track-name-number") {
2361 update_track_number_visibility();
2365 /** Called to decide whether the solo isolate / solo lock button visibility should
2366 * be overridden from that configured by the user. We do this for the master bus.
2368 * @return optional value that is present if visibility state should be overridden.
2370 boost::optional<bool>
2371 MixerStrip::override_solo_visibility () const
2373 if (_route && _route->is_master ()) {
2374 return boost::optional<bool> (false);
2377 return boost::optional<bool> ();
2381 MixerStrip::add_input_port (DataType t)
2383 _route->input()->add_port ("", this, t);
2387 MixerStrip::add_output_port (DataType t)
2389 _route->output()->add_port ("", this, t);
2393 MixerStrip::route_active_changed ()
2395 reset_strip_style ();
2399 MixerStrip::copy_processors ()
2401 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2405 MixerStrip::cut_processors ()
2407 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2411 MixerStrip::paste_processors ()
2413 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2417 MixerStrip::select_all_processors ()
2419 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2423 MixerStrip::deselect_all_processors ()
2425 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2429 MixerStrip::delete_processors ()
2431 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2435 MixerStrip::toggle_processors ()
2437 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2441 MixerStrip::ab_plugins ()
2443 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2447 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2449 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2452 if (ev->button == 3) {
2453 popup_level_meter_menu (ev);
2461 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2463 using namespace Gtk::Menu_Helpers;
2465 Gtk::Menu* m = manage (new Menu);
2466 MenuList& items = m->items ();
2468 RadioMenuItem::Group group;
2470 _suspend_menu_callbacks = true;
2471 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2472 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2473 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2474 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2475 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2477 if (gpm.meter_channels().n_audio() == 0) {
2478 m->popup (ev->button, ev->time);
2479 _suspend_menu_callbacks = false;
2483 RadioMenuItem::Group tgroup;
2484 items.push_back (SeparatorElem());
2486 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2487 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2488 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2489 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2490 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2491 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2492 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2493 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2494 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2495 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2496 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2499 if (_route->is_master()) {
2502 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2503 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2504 /* non-master bus */
2507 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2514 MeterType cmt = _route->meter_type();
2515 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2517 items.push_back (SeparatorElem());
2518 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2519 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2520 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2521 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2522 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2523 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2525 m->popup (ev->button, ev->time);
2526 _suspend_menu_callbacks = false;
2530 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2531 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2533 using namespace Menu_Helpers;
2535 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2536 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2537 i->set_active (_route->meter_point() == point);
2541 MixerStrip::set_meter_point (MeterPoint p)
2543 if (_suspend_menu_callbacks) return;
2544 _route->set_meter_point (p);
2548 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2549 RadioMenuItem::Group& group, string const & name, MeterType type)
2551 using namespace Menu_Helpers;
2553 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2554 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2555 i->set_active (_route->meter_type() == type);
2559 MixerStrip::set_meter_type (MeterType t)
2561 if (_suspend_menu_callbacks) return;
2566 MixerStrip::update_track_number_visibility ()
2568 DisplaySuspender ds;
2569 bool show_label = _session->config.get_track_name_number();
2571 if (_route && _route->is_master()) {
2576 number_label.show ();
2577 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2578 // except the width of the number label is subtracted from the name-hbox, so we
2579 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2580 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2582 number_label.set_size_request(tnw, -1);
2583 number_label.show ();
2585 number_label.hide ();
2590 MixerStrip::color () const
2592 return route_color ();
2596 MixerStrip::marked_for_display () const
2598 return !_route->presentation_info().hidden();
2602 MixerStrip::set_marked_for_display (bool yn)
2604 return RouteUI::mark_hidden (!yn);