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::set_route (boost::shared_ptr<Route> rt)
463 //the rec/monitor stuff only shows up for tracks.
464 //the show_sends only shows up for buses.
465 //remove them all here, and we may add them back later
466 if (show_sends_button->get_parent()) {
467 rec_mon_table.remove (*show_sends_button);
469 if (rec_enable_button->get_parent()) {
470 rec_mon_table.remove (*rec_enable_button);
472 if (monitor_input_button->get_parent()) {
473 rec_mon_table.remove (*monitor_input_button);
475 if (monitor_disk_button->get_parent()) {
476 rec_mon_table.remove (*monitor_disk_button);
478 if (group_button.get_parent()) {
479 bottom_button_table.remove (group_button);
482 RouteUI::set_route (rt);
484 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
486 /* ProcessorBox needs access to _route so that it can read
489 processor_box.set_route (rt);
491 revert_to_default_display ();
493 /* unpack these from the parent and stuff them into our own
497 if (gpm.peak_display.get_parent()) {
498 gpm.peak_display.get_parent()->remove (gpm.peak_display);
500 if (gpm.gain_display.get_parent()) {
501 gpm.gain_display.get_parent()->remove (gpm.gain_display);
504 gpm.set_type (rt->meter_type());
506 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
507 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
509 if (solo_button->get_parent()) {
510 mute_solo_table.remove (*solo_button);
513 if (mute_button->get_parent()) {
514 mute_solo_table.remove (*mute_button);
517 if (route()->is_master()) {
518 solo_button->hide ();
519 mute_button->show ();
520 rec_mon_table.hide ();
521 if (solo_iso_table.get_parent()) {
522 solo_iso_table.get_parent()->remove(solo_iso_table);
524 if (monitor_section_button == 0) {
525 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
526 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
528 monitor_section_button = manage (new ArdourButton);
530 monitor_section_button->set_related_action (act);
531 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
532 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
533 monitor_section_button->show();
534 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
536 parameter_changed ("use-monitor-bus");
538 bottom_button_table.attach (group_button, 1, 2, 0, 1);
539 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
540 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
541 mute_button->show ();
542 solo_button->show ();
543 rec_mon_table.show ();
546 if (_mixer_owned && route()->is_master() ) {
548 HScrollbar scrollbar;
549 Gtk::Requisition requisition(scrollbar.size_request ());
550 int scrollbar_height = requisition.height;
552 spacer = manage (new EventBox);
553 spacer->set_size_request (-1, scrollbar_height+2);
554 global_vpacker.pack_start (*spacer, false, false);
559 monitor_input_button->show ();
560 monitor_disk_button->show ();
562 monitor_input_button->hide();
563 monitor_disk_button->hide ();
566 if (route()->trim() && route()->trim()->active()) {
567 trim_control.show ();
568 trim_control.set_controllable (route()->trim()->gain_control());
570 trim_control.hide ();
571 boost::shared_ptr<Controllable> none;
572 trim_control.set_controllable (none);
575 if (is_midi_track()) {
576 if (midi_input_enable_button == 0) {
577 midi_input_enable_button = manage (new ArdourButton);
578 midi_input_enable_button->set_name ("midi input button");
579 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
580 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
581 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
582 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
583 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
585 input_button_box.remove (*midi_input_enable_button);
587 /* get current state */
588 midi_input_status_changed ();
589 input_button_box.pack_start (*midi_input_enable_button, false, false);
591 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
593 if (midi_input_enable_button) {
594 /* removal from the container will delete it */
595 input_button_box.remove (*midi_input_enable_button);
596 midi_input_enable_button = 0;
600 if (is_audio_track()) {
601 boost::shared_ptr<AudioTrack> at = audio_track();
602 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
607 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
608 rec_enable_button->show();
610 if (ARDOUR::Profile->get_mixbus()) {
611 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
612 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
613 } else if (ARDOUR::Profile->get_trx()) {
614 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
616 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
617 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
624 if (!_route->is_master()) {
625 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
626 show_sends_button->show();
630 meter_point_button.set_text (meter_point_string (_route->meter_point()));
632 delete route_ops_menu;
635 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
636 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
637 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
638 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
640 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
642 if (_route->panner_shell()) {
643 update_panner_choices();
644 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
647 if (is_audio_track()) {
648 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
651 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
653 set_stuff_from_route ();
655 /* now force an update of all the various elements */
657 update_mute_display ();
658 update_solo_display ();
661 route_group_changed ();
662 update_track_number_visibility ();
665 panners.setup_pan ();
667 if (has_audio_outputs ()) {
673 update_diskstream_display ();
674 update_input_display ();
675 update_output_display ();
677 add_events (Gdk::BUTTON_RELEASE_MASK);
679 processor_box.show ();
681 if (!route()->is_master() && !route()->is_monitor()) {
682 /* we don't allow master or control routes to be hidden */
687 gpm.reset_peak_display ();
688 gpm.gain_display.show ();
689 gpm.peak_display.show ();
692 width_hide_box.show();
694 global_vpacker.show();
695 mute_solo_table.show();
696 bottom_button_table.show();
698 meter_point_button.show();
699 input_button_box.show_all();
700 output_button.show();
702 _comment_button.show();
704 gpm.gain_automation_state_button.show();
706 parameter_changed ("mixer-element-visibility");
713 MixerStrip::set_stuff_from_route ()
715 /* if width is not set, it will be set by the MixerUI or editor */
717 string str = gui_property ("strip-width");
719 set_width_enum (Width (string_2_enum (str, _width)), this);
724 MixerStrip::set_width_enum (Width w, void* owner)
726 /* always set the gpm width again, things may be hidden */
729 panners.set_width (w);
731 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
733 _width_owner = owner;
737 if (_width_owner == this) {
738 set_gui_property ("strip-width", enum_2_string (_width));
743 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
748 if (show_sends_button) {
749 show_sends_button->set_text (_("Aux"));
752 gpm.gain_automation_style_button.set_text (
753 gpm.astyle_string(gain_automation->automation_style()));
754 gpm.gain_automation_state_button.set_text (
755 gpm.astate_string(gain_automation->automation_state()));
757 if (_route->panner()) {
758 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
759 panners.astyle_string(_route->panner()->automation_style()));
760 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
761 panners.astate_string(_route->panner()->automation_state()));
765 // panners expect an even number of horiz. pixels
766 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
768 set_size_request (width, -1);
774 if (show_sends_button) {
775 show_sends_button->set_text (_("Snd"));
778 gpm.gain_automation_style_button.set_text (
779 gpm.short_astyle_string(gain_automation->automation_style()));
780 gpm.gain_automation_state_button.set_text (
781 gpm.short_astate_string(gain_automation->automation_state()));
782 gain_meter().setup_meters (); // recalc meter width
784 if (_route->panner()) {
785 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
786 panners.short_astyle_string(_route->panner()->automation_style()));
787 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
788 panners.short_astate_string(_route->panner()->automation_state()));
792 // panners expect an even number of horiz. pixels
793 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
795 set_size_request (width, -1);
800 processor_box.set_width (w);
802 update_input_display ();
803 update_output_display ();
804 setup_comment_button ();
805 route_group_changed ();
811 MixerStrip::set_packed (bool yn)
816 set_gui_property ("visible", true);
818 set_gui_property ("visible", false);
823 struct RouteCompareByName {
824 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
825 return a->name().compare (b->name()) < 0;
830 MixerStrip::output_release (GdkEventButton *ev)
832 switch (ev->button) {
834 edit_output_configuration ();
842 MixerStrip::output_press (GdkEventButton *ev)
844 using namespace Menu_Helpers;
845 if (!_session->engine().connected()) {
846 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
851 MenuList& citems = output_menu.items();
852 switch (ev->button) {
855 return false; //wait for the mouse-up to pop the dialog
859 output_menu.set_name ("ArdourContextMenu");
861 output_menu_bundles.clear ();
863 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
865 citems.push_back (SeparatorElem());
866 uint32_t const n_with_separator = citems.size ();
868 ARDOUR::BundleList current = _route->output()->bundles_connected ();
870 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
872 /* give user bundles first chance at being in the menu */
874 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
875 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
876 maybe_add_bundle_to_output_menu (*i, current);
880 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
881 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
882 maybe_add_bundle_to_output_menu (*i, current);
886 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
887 RouteList copy = *routes;
888 copy.sort (RouteCompareByName ());
889 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
890 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
893 if (citems.size() == n_with_separator) {
894 /* no routes added; remove the separator */
898 if (!ARDOUR::Profile->get_mixbus()) {
899 citems.push_back (SeparatorElem());
901 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
904 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
905 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
911 citems.push_back (SeparatorElem());
912 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
914 output_menu.popup (1, ev->time);
925 MixerStrip::input_release (GdkEventButton *ev)
927 switch (ev->button) {
930 edit_input_configuration ();
942 MixerStrip::input_press (GdkEventButton *ev)
944 using namespace Menu_Helpers;
946 MenuList& citems = input_menu.items();
947 input_menu.set_name ("ArdourContextMenu");
950 if (!_session->engine().connected()) {
951 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
956 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
959 switch (ev->button) {
962 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
966 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
968 citems.push_back (SeparatorElem());
969 uint32_t const n_with_separator = citems.size ();
971 input_menu_bundles.clear ();
973 ARDOUR::BundleList current = _route->input()->bundles_connected ();
975 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
977 /* give user bundles first chance at being in the menu */
979 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
980 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
981 maybe_add_bundle_to_input_menu (*i, current);
985 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
986 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
987 maybe_add_bundle_to_input_menu (*i, current);
991 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
992 RouteList copy = *routes;
993 copy.sort (RouteCompareByName ());
994 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
995 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
998 if (citems.size() == n_with_separator) {
999 /* no routes added; remove the separator */
1003 citems.push_back (SeparatorElem());
1004 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1007 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1008 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1013 citems.push_back (SeparatorElem());
1014 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1016 input_menu.popup (1, ev->time);
1027 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1029 if (ignore_toggle) {
1033 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1035 if (std::find (current.begin(), current.end(), c) == current.end()) {
1036 _route->input()->connect_ports_to_bundle (c, true, this);
1038 _route->input()->disconnect_ports_from_bundle (c, this);
1043 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1045 if (ignore_toggle) {
1049 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1051 if (std::find (current.begin(), current.end(), c) == current.end()) {
1052 _route->output()->connect_ports_to_bundle (c, true, this);
1054 _route->output()->disconnect_ports_from_bundle (c, this);
1059 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1061 using namespace Menu_Helpers;
1063 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1067 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1068 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1072 if (i != input_menu_bundles.end()) {
1076 input_menu_bundles.push_back (b);
1078 MenuList& citems = input_menu.items();
1080 std::string n = b->name ();
1081 replace_all (n, "_", " ");
1083 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1087 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1089 using namespace Menu_Helpers;
1091 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1095 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1096 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1100 if (i != output_menu_bundles.end()) {
1104 output_menu_bundles.push_back (b);
1106 MenuList& citems = output_menu.items();
1108 std::string n = b->name ();
1109 replace_all (n, "_", " ");
1111 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1115 MixerStrip::update_diskstream_display ()
1117 if (is_track() && input_selector) {
1118 input_selector->hide_all ();
1121 route_color_changed ();
1125 MixerStrip::connect_to_pan ()
1127 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1129 panstate_connection.disconnect ();
1130 panstyle_connection.disconnect ();
1132 if (!_route->panner()) {
1136 boost::shared_ptr<Pannable> p = _route->pannable ();
1138 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1139 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1141 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1142 * However, that only works a panner was previously set.
1144 * PannerUI must remain subscribed to _panshell->Changed() in case
1145 * we switch the panner eg. AUX-Send and back
1146 * _route->panner_shell()->Changed() vs _panshell->Changed
1148 if (panners._panner == 0) {
1149 panners.panshell_changed ();
1151 update_panner_choices();
1155 MixerStrip::update_panner_choices ()
1157 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1158 if (!_route->panner_shell()) { return; }
1160 uint32_t in = _route->output()->n_ports().n_audio();
1162 if (_route->panner()) {
1163 in = _route->panner()->in().n_audio();
1166 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1170 * Output port labelling
1171 * =====================
1173 * Case 1: Each output has one connection, all connections are to system:playback_%i
1174 * out 1 -> system:playback_1
1175 * out 2 -> system:playback_2
1176 * out 3 -> system:playback_3
1179 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1180 * out 1 -> ardour:track_x/in 1
1181 * out 2 -> ardour:track_x/in 2
1182 * Display as: track_x
1184 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1185 * out 1 -> program x:foo
1186 * out 2 -> program x:foo
1187 * Display as: program x
1189 * Case 4: No connections (Disconnected)
1192 * Default case (unusual routing):
1193 * Display as: *number of connections*
1197 * .-----------------------------------------------.
1199 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1200 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1201 * '-----------------------------------------------'
1202 * .-----------------------------------------------.
1205 * '-----------------------------------------------'
1209 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1213 boost::shared_ptr<IO> io;
1214 boost::shared_ptr<Port> port;
1215 vector<string> port_connections;
1217 uint32_t total_connection_count = 0;
1218 uint32_t io_connection_count = 0;
1219 uint32_t ardour_connection_count = 0;
1220 uint32_t system_connection_count = 0;
1221 uint32_t other_connection_count = 0;
1222 uint32_t typed_connection_count = 0;
1224 ostringstream label;
1226 bool have_label = false;
1227 bool each_io_has_one_connection = true;
1229 string connection_name;
1230 string ardour_track_name;
1231 string other_connection_type;
1232 string system_ports;
1235 ostringstream tooltip;
1236 char * tooltip_cstr;
1238 //to avoid confusion, the button caption should only show connections that match the datatype of the track
1239 DataType dt = DataType::AUDIO;
1240 if ( boost::dynamic_pointer_cast<MidiTrack>(route) != 0 ) {
1241 dt = DataType::MIDI;
1242 // avoid further confusion with Midi-tracks that have a synth.
1243 // Audio-ports may be connected, but button says "Disconnected"
1244 tooltip << _("MIDI ");
1248 io = route->input();
1249 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1251 io = route->output();
1252 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1255 io_count = io->n_ports().n_total();
1257 for (io_index = 0; io_index < io_count; ++io_index) {
1258 port = io->nth (io_index);
1260 port_connections.clear ();
1261 port->get_connections(port_connections);
1263 //ignore any port connections that don't match our DataType
1264 if (port->type() != dt) {
1265 if (!port_connections.empty()) {
1266 ++typed_connection_count;
1271 io_connection_count = 0;
1273 if (!port_connections.empty()) {
1274 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1276 string& connection_name (*i);
1278 if (connection_name.find("system:") == 0) {
1279 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1282 if (io_connection_count == 0) {
1283 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1285 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1288 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1291 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1292 if (ardour_track_name.empty()) {
1293 // "ardour:Master/in 1" -> "ardour:Master/"
1294 string::size_type slash = connection_name.find("/");
1295 if (slash != string::npos) {
1296 ardour_track_name = connection_name.substr(0, slash + 1);
1300 if (connection_name.find(ardour_track_name) == 0) {
1301 ++ardour_connection_count;
1303 } else if (!pn.empty()) {
1304 if (system_ports.empty()) {
1307 system_ports += "/" + pn;
1309 if (connection_name.find("system:") == 0) {
1310 ++system_connection_count;
1312 } else if (connection_name.find("system:midi_") == 0) {
1314 // "system:midi_capture_123" -> "123"
1315 system_port = "M " + connection_name.substr(20);
1317 // "system:midi_playback_123" -> "123"
1318 system_port = "M " + connection_name.substr(21);
1321 if (system_ports.empty()) {
1322 system_ports += system_port;
1324 system_ports += "/" + system_port;
1327 ++system_connection_count;
1329 } else if (connection_name.find("system:") == 0) {
1331 // "system:capture_123" -> "123"
1332 system_port = connection_name.substr(15);
1334 // "system:playback_123" -> "123"
1335 system_port = connection_name.substr(16);
1338 if (system_ports.empty()) {
1339 system_ports += system_port;
1341 system_ports += "/" + system_port;
1344 ++system_connection_count;
1346 if (other_connection_type.empty()) {
1347 // "jamin:in 1" -> "jamin:"
1348 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1351 if (connection_name.find(other_connection_type) == 0) {
1352 ++other_connection_count;
1356 ++total_connection_count;
1357 ++io_connection_count;
1361 if (io_connection_count != 1) {
1362 each_io_has_one_connection = false;
1366 if (total_connection_count == 0) {
1367 tooltip << endl << _("Disconnected");
1370 tooltip_cstr = new char[tooltip.str().size() + 1];
1371 strcpy(tooltip_cstr, tooltip.str().c_str());
1374 set_tooltip (&input_button, tooltip_cstr);
1376 set_tooltip (&output_button, tooltip_cstr);
1379 delete [] tooltip_cstr;
1381 if (each_io_has_one_connection) {
1382 if (total_connection_count == ardour_connection_count) {
1383 // all connections are to the same track in ardour
1384 // "ardour:Master/" -> "Master"
1385 string::size_type slash = ardour_track_name.find("/");
1386 if (slash != string::npos) {
1387 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1388 label << ardour_track_name.substr (ppps, slash - ppps);
1392 else if (total_connection_count == system_connection_count) {
1393 // all connections are to system ports
1394 label << system_ports;
1397 else if (total_connection_count == other_connection_count) {
1398 // all connections are to the same external program eg jamin
1399 // "jamin:" -> "jamin"
1400 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1406 if (total_connection_count == 0) {
1410 // Odd configuration
1411 label << "*" << total_connection_count << "*";
1413 if (typed_connection_count > 0) {
1414 label << "\u2295"; // circled plus
1419 input_button.set_text (label.str());
1421 output_button.set_text (label.str());
1426 MixerStrip::update_input_display ()
1428 update_io_button (_route, _width, true);
1429 panners.setup_pan ();
1431 if (has_audio_outputs ()) {
1432 panners.show_all ();
1434 panners.hide_all ();
1440 MixerStrip::update_output_display ()
1442 update_io_button (_route, _width, false);
1443 gpm.setup_meters ();
1444 panners.setup_pan ();
1446 if (has_audio_outputs ()) {
1447 panners.show_all ();
1449 panners.hide_all ();
1454 MixerStrip::fast_update ()
1456 gpm.update_meters ();
1460 MixerStrip::diskstream_changed ()
1462 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1466 MixerStrip::io_changed_proxy ()
1468 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1472 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1474 boost::shared_ptr<Port> a = wa.lock ();
1475 boost::shared_ptr<Port> b = wb.lock ();
1477 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1478 update_input_display ();
1479 set_width_enum (_width, this);
1482 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1483 update_output_display ();
1484 set_width_enum (_width, this);
1489 MixerStrip::setup_comment_button ()
1491 std::string comment = _route->comment();
1493 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1495 if (comment.empty ()) {
1496 _comment_button.set_name ("generic button");
1497 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1501 _comment_button.set_name ("comment button");
1503 string::size_type pos = comment.find_first_of (" \t\n");
1504 if (pos != string::npos) {
1505 comment = comment.substr (0, pos);
1507 if (comment.empty()) {
1508 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1510 _comment_button.set_text (comment);
1515 MixerStrip::select_route_group (GdkEventButton *ev)
1517 using namespace Menu_Helpers;
1519 if (ev->button == 1) {
1521 if (group_menu == 0) {
1523 PropertyList* plist = new PropertyList();
1525 plist->add (Properties::group_gain, true);
1526 plist->add (Properties::group_mute, true);
1527 plist->add (Properties::group_solo, true);
1529 group_menu = new RouteGroupMenu (_session, plist);
1533 r.push_back (route ());
1534 group_menu->build (r);
1535 group_menu->menu()->popup (1, ev->time);
1542 MixerStrip::route_group_changed ()
1544 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1546 RouteGroup *rg = _route->route_group();
1549 group_button.set_text (PBD::short_version (rg->name(), 5));
1553 group_button.set_text (_("Grp"));
1556 group_button.set_text (_("~G"));
1563 MixerStrip::route_color_changed ()
1565 name_button.modify_bg (STATE_NORMAL, color());
1566 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1567 reset_strip_style ();
1571 MixerStrip::show_passthru_color ()
1573 reset_strip_style ();
1578 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1580 boost::shared_ptr<Processor> processor (p.lock ());
1581 if (!processor || !processor->display_to_user()) {
1584 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1585 ++_plugin_insert_cnt;
1589 MixerStrip::build_route_ops_menu ()
1591 using namespace Menu_Helpers;
1592 route_ops_menu = new Menu;
1593 route_ops_menu->set_name ("ArdourContextMenu");
1595 MenuList& items = route_ops_menu->items();
1597 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1599 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1601 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1603 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1605 items.push_back (SeparatorElem());
1607 if (!_route->is_master()) {
1608 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1610 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1611 rename_menu_item = &items.back();
1613 items.push_back (SeparatorElem());
1614 items.push_back (CheckMenuElem (_("Active")));
1615 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1616 i->set_active (_route->active());
1617 i->set_sensitive(! _session->transport_rolling());
1618 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1620 if (!Profile->get_mixbus ()) {
1621 items.push_back (SeparatorElem());
1622 items.push_back (CheckMenuElem (_("Strict I/O")));
1623 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1624 i->set_active (_route->strict_io());
1625 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1628 _plugin_insert_cnt = 0;
1629 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1630 if (_plugin_insert_cnt > 0) {
1631 items.push_back (SeparatorElem());
1632 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1635 items.push_back (SeparatorElem());
1636 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1638 items.push_back (SeparatorElem());
1639 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1640 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1641 denormal_menu_item->set_active (_route->denormal_protection());
1644 /* note that this relies on selection being shared across editor and
1645 mixer (or global to the backend, in the future), which is the only
1646 sane thing for users anyway.
1649 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1651 Selection& selection (PublicEditor::instance().get_selection());
1652 if (!selection.selected (rtav)) {
1653 selection.set (rtav);
1656 if (!_route->is_master()) {
1657 items.push_back (SeparatorElem());
1658 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1661 items.push_back (SeparatorElem());
1662 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1668 MixerStrip::name_button_button_press (GdkEventButton* ev)
1670 if (ev->button == 3) {
1671 list_route_operations ();
1673 /* do not allow rename if the track is record-enabled */
1674 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1675 route_ops_menu->popup (1, ev->time);
1684 MixerStrip::name_button_button_release (GdkEventButton* ev)
1686 if (ev->button == 1) {
1687 list_route_operations ();
1689 /* do not allow rename if the track is record-enabled */
1690 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1691 route_ops_menu->popup (1, ev->time);
1698 MixerStrip::number_button_button_press (GdkEventButton* ev)
1700 if ( ev->button == 3 ) {
1701 list_route_operations ();
1703 /* do not allow rename if the track is record-enabled */
1704 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1705 route_ops_menu->popup (1, ev->time);
1714 MixerStrip::list_route_operations ()
1716 delete route_ops_menu;
1717 build_route_ops_menu ();
1721 MixerStrip::set_selected (bool yn)
1723 AxisView::set_selected (yn);
1726 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1727 global_frame.set_name ("MixerStripSelectedFrame");
1729 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1730 global_frame.set_name ("MixerStripFrame");
1733 global_frame.queue_draw ();
1736 // processor_box.deselect_all_processors();
1740 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1742 if (what_changed.contains (ARDOUR::Properties::name)) {
1748 MixerStrip::name_changed ()
1752 name_button.set_text (_route->name());
1755 name_button.set_text (PBD::short_version (_route->name(), 5));
1759 set_tooltip (name_button, _route->name());
1761 if (_session->config.get_track_name_number()) {
1762 const int64_t track_number = _route->track_number ();
1763 if (track_number == 0) {
1764 number_label.set_text ("-");
1766 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1769 number_label.set_text ("");
1774 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1776 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1780 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1782 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1786 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1788 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1792 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1794 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1798 MixerStrip::width_button_pressed (GdkEventButton* ev)
1800 if (ev->button != 1) {
1804 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1807 _mixer.set_strip_width (Narrow, true);
1811 _mixer.set_strip_width (Wide, true);
1817 set_width_enum (Narrow, this);
1820 set_width_enum (Wide, this);
1829 MixerStrip::hide_clicked ()
1831 // LAME fix to reset the button status for when it is redisplayed (part 1)
1832 hide_button.set_sensitive(false);
1835 Hiding(); /* EMIT_SIGNAL */
1837 _mixer.hide_strip (this);
1841 hide_button.set_sensitive(true);
1845 MixerStrip::set_embedded (bool yn)
1851 MixerStrip::map_frozen ()
1853 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1855 boost::shared_ptr<AudioTrack> at = audio_track();
1858 switch (at->freeze_state()) {
1859 case AudioTrack::Frozen:
1860 processor_box.set_sensitive (false);
1861 hide_redirect_editors ();
1864 processor_box.set_sensitive (true);
1865 // XXX need some way, maybe, to retoggle redirect editors
1869 processor_box.set_sensitive (true);
1871 RouteUI::map_frozen ();
1875 MixerStrip::hide_redirect_editors ()
1877 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1881 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1883 boost::shared_ptr<Processor> processor (p.lock ());
1888 Gtk::Window* w = processor_box.get_processor_ui (processor);
1896 MixerStrip::reset_strip_style ()
1898 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1900 gpm.set_fader_name ("SendStripBase");
1904 if (is_midi_track()) {
1905 if (_route->active()) {
1906 set_name ("MidiTrackStripBase");
1908 set_name ("MidiTrackStripBaseInactive");
1910 gpm.set_fader_name ("MidiTrackFader");
1911 } else if (is_audio_track()) {
1912 if (_route->active()) {
1913 set_name ("AudioTrackStripBase");
1915 set_name ("AudioTrackStripBaseInactive");
1917 gpm.set_fader_name ("AudioTrackFader");
1919 if (_route->active()) {
1920 set_name ("AudioBusStripBase");
1922 set_name ("AudioBusStripBaseInactive");
1924 gpm.set_fader_name ("AudioBusFader");
1926 /* (no MIDI busses yet) */
1933 MixerStrip::engine_stopped ()
1938 MixerStrip::engine_running ()
1943 MixerStrip::meter_point_string (MeterPoint mp)
1956 case MeterPostFader:
1973 return S_("Meter|In");
1977 return S_("Meter|Pr");
1980 case MeterPostFader:
1981 return S_("Meter|Po");
1985 return S_("Meter|O");
1990 return S_("Meter|C");
1999 /** Called when the monitor-section state */
2001 MixerStrip::monitor_changed ()
2003 assert (monitor_section_button);
2004 if (_session->monitor_active()) {
2005 monitor_section_button->set_name ("master monitor section button active");
2007 monitor_section_button->set_name ("master monitor section button normal");
2011 /** Called when the metering point has changed */
2013 MixerStrip::meter_changed ()
2015 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2016 gpm.setup_meters ();
2017 // reset peak when meter point changes
2018 gpm.reset_peak_display();
2021 /** The bus that we are displaying sends to has changed, or been turned off.
2022 * @param send_to New bus that we are displaying sends to, or 0.
2025 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2027 RouteUI::bus_send_display_changed (send_to);
2030 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2035 revert_to_default_display ();
2038 revert_to_default_display ();
2043 MixerStrip::drop_send ()
2045 boost::shared_ptr<Send> current_send;
2047 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2048 current_send->set_metering (false);
2051 send_gone_connection.disconnect ();
2052 input_button.set_sensitive (true);
2053 output_button.set_sensitive (true);
2054 group_button.set_sensitive (true);
2055 set_invert_sensitive (true);
2056 meter_point_button.set_sensitive (true);
2057 mute_button->set_sensitive (true);
2058 solo_button->set_sensitive (true);
2059 solo_isolated_led->set_sensitive (true);
2060 solo_safe_led->set_sensitive (true);
2061 monitor_input_button->set_sensitive (true);
2062 monitor_disk_button->set_sensitive (true);
2063 _comment_button.set_sensitive (true);
2064 RouteUI::check_rec_enable_sensitivity ();
2065 set_button_names (); // update solo button visual state
2069 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2071 _current_delivery = d;
2072 DeliveryChanged (_current_delivery);
2076 MixerStrip::show_send (boost::shared_ptr<Send> send)
2082 set_current_delivery (send);
2084 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2085 send->set_metering (true);
2086 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2088 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2089 gain_meter().setup_meters ();
2091 uint32_t const in = _current_delivery->pans_required();
2092 uint32_t const out = _current_delivery->pan_outs();
2094 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2095 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2096 panner_ui().setup_pan ();
2097 panner_ui().set_send_drawing_mode (true);
2098 panner_ui().show_all ();
2100 input_button.set_sensitive (false);
2101 group_button.set_sensitive (false);
2102 set_invert_sensitive (false);
2103 meter_point_button.set_sensitive (false);
2104 mute_button->set_sensitive (false);
2105 solo_button->set_sensitive (false);
2106 rec_enable_button->set_sensitive (false);
2107 solo_isolated_led->set_sensitive (false);
2108 solo_safe_led->set_sensitive (false);
2109 monitor_input_button->set_sensitive (false);
2110 monitor_disk_button->set_sensitive (false);
2111 _comment_button.set_sensitive (false);
2113 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2114 output_button.set_sensitive (false);
2117 reset_strip_style ();
2121 MixerStrip::revert_to_default_display ()
2125 set_current_delivery (_route->main_outs ());
2127 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2128 gain_meter().setup_meters ();
2130 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2131 update_panner_choices();
2132 panner_ui().setup_pan ();
2133 panner_ui().set_send_drawing_mode (false);
2135 if (has_audio_outputs ()) {
2136 panners.show_all ();
2138 panners.hide_all ();
2141 reset_strip_style ();
2145 MixerStrip::set_button_names ()
2149 mute_button->set_text (_("Mute"));
2150 monitor_input_button->set_text (_("In"));
2151 monitor_disk_button->set_text (_("Disk"));
2152 if (monitor_section_button) {
2153 monitor_section_button->set_text (_("Mon"));
2156 if (_route && _route->solo_safe_control()->solo_safe()) {
2157 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2159 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2161 if (!Config->get_solo_control_is_listen_control()) {
2162 solo_button->set_text (_("Solo"));
2164 switch (Config->get_listen_position()) {
2165 case AfterFaderListen:
2166 solo_button->set_text (_("AFL"));
2168 case PreFaderListen:
2169 solo_button->set_text (_("PFL"));
2173 solo_isolated_led->set_text (_("Iso"));
2174 solo_safe_led->set_text (S_("SoloLock|Lock"));
2178 mute_button->set_text (S_("Mute|M"));
2179 monitor_input_button->set_text (S_("MonitorInput|I"));
2180 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2181 if (monitor_section_button) {
2182 monitor_section_button->set_text (S_("Mon|O"));
2185 if (_route && _route->solo_safe_control()->solo_safe()) {
2186 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2188 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2190 if (!Config->get_solo_control_is_listen_control()) {
2191 solo_button->set_text (S_("Solo|S"));
2193 switch (Config->get_listen_position()) {
2194 case AfterFaderListen:
2195 solo_button->set_text (S_("AfterFader|A"));
2197 case PreFaderListen:
2198 solo_button->set_text (S_("Prefader|P"));
2203 solo_isolated_led->set_text (S_("SoloIso|I"));
2204 solo_safe_led->set_text (S_("SoloLock|L"));
2209 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2211 meter_point_button.set_text ("");
2216 MixerStrip::plugin_selector()
2218 return _mixer.plugin_selector();
2222 MixerStrip::hide_things ()
2224 processor_box.hide_things ();
2228 MixerStrip::input_active_button_press (GdkEventButton*)
2230 /* nothing happens on press */
2235 MixerStrip::input_active_button_release (GdkEventButton* ev)
2237 boost::shared_ptr<MidiTrack> mt = midi_track ();
2243 boost::shared_ptr<RouteList> rl (new RouteList);
2245 rl->push_back (route());
2247 _session->set_exclusive_input_active (rl, !mt->input_active(),
2248 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2254 MixerStrip::midi_input_status_changed ()
2256 if (midi_input_enable_button) {
2257 boost::shared_ptr<MidiTrack> mt = midi_track ();
2259 midi_input_enable_button->set_active (mt->input_active ());
2264 MixerStrip::state_id () const
2266 return string_compose ("strip %1", _route->id().to_s());
2270 MixerStrip::parameter_changed (string p)
2272 if (p == _visibility.get_state_name()) {
2273 /* The user has made changes to the mixer strip visibility, so get
2274 our VisibilityGroup to reflect these changes in our widgets.
2276 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2277 } else if (p == "track-name-number") {
2279 } else if (p == "use-monitor-bus") {
2280 if (monitor_section_button) {
2281 if (mute_button->get_parent()) {
2282 mute_button->get_parent()->remove(*mute_button);
2284 if (monitor_section_button->get_parent()) {
2285 monitor_section_button->get_parent()->remove(*monitor_section_button);
2287 if (Config->get_use_monitor_bus ()) {
2288 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2289 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2290 mute_button->show();
2291 monitor_section_button->show();
2293 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2294 mute_button->show();
2297 } else if (p == "track-name-number") {
2298 update_track_number_visibility();
2302 /** Called to decide whether the solo isolate / solo lock button visibility should
2303 * be overridden from that configured by the user. We do this for the master bus.
2305 * @return optional value that is present if visibility state should be overridden.
2307 boost::optional<bool>
2308 MixerStrip::override_solo_visibility () const
2310 if (_route && _route->is_master ()) {
2311 return boost::optional<bool> (false);
2314 return boost::optional<bool> ();
2318 MixerStrip::add_input_port (DataType t)
2320 _route->input()->add_port ("", this, t);
2324 MixerStrip::add_output_port (DataType t)
2326 _route->output()->add_port ("", this, t);
2330 MixerStrip::route_active_changed ()
2332 reset_strip_style ();
2336 MixerStrip::copy_processors ()
2338 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2342 MixerStrip::cut_processors ()
2344 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2348 MixerStrip::paste_processors ()
2350 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2354 MixerStrip::select_all_processors ()
2356 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2360 MixerStrip::deselect_all_processors ()
2362 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2366 MixerStrip::delete_processors ()
2368 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2372 MixerStrip::toggle_processors ()
2374 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2378 MixerStrip::ab_plugins ()
2380 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2384 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2386 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2389 if (ev->button == 3) {
2390 popup_level_meter_menu (ev);
2398 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2400 using namespace Gtk::Menu_Helpers;
2402 Gtk::Menu* m = manage (new Menu);
2403 MenuList& items = m->items ();
2405 RadioMenuItem::Group group;
2407 _suspend_menu_callbacks = true;
2408 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2409 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2410 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2411 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2412 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2414 if (gpm.meter_channels().n_audio() == 0) {
2415 m->popup (ev->button, ev->time);
2416 _suspend_menu_callbacks = false;
2420 RadioMenuItem::Group tgroup;
2421 items.push_back (SeparatorElem());
2423 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2424 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2425 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2426 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2427 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2428 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2429 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2430 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2431 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2432 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2433 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2436 if (_route->is_master()) {
2439 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2440 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2441 /* non-master bus */
2444 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2451 MeterType cmt = _route->meter_type();
2452 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2454 items.push_back (SeparatorElem());
2455 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2456 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2457 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2458 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2459 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2460 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2462 m->popup (ev->button, ev->time);
2463 _suspend_menu_callbacks = false;
2467 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2468 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2470 using namespace Menu_Helpers;
2472 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2473 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2474 i->set_active (_route->meter_point() == point);
2478 MixerStrip::set_meter_point (MeterPoint p)
2480 if (_suspend_menu_callbacks) return;
2481 _route->set_meter_point (p);
2485 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2486 RadioMenuItem::Group& group, string const & name, MeterType type)
2488 using namespace Menu_Helpers;
2490 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2491 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2492 i->set_active (_route->meter_type() == type);
2496 MixerStrip::set_meter_type (MeterType t)
2498 if (_suspend_menu_callbacks) return;
2503 MixerStrip::update_track_number_visibility ()
2505 DisplaySuspender ds;
2506 bool show_label = _session->config.get_track_name_number();
2508 if (_route && _route->is_master()) {
2513 number_label.show ();
2514 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2515 // except the width of the number label is subtracted from the name-hbox, so we
2516 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2517 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2519 number_label.set_size_request(tnw, -1);
2520 number_label.show ();
2522 number_label.hide ();
2527 MixerStrip::color () const
2529 return route_color ();
2533 MixerStrip::marked_for_display () const
2535 return !_route->presentation_info().hidden();
2539 MixerStrip::set_marked_for_display (bool yn)
2541 return RouteUI::mark_hidden (!yn);