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/menu_elems.h"
32 #include "gtkmm2ext/utils.h"
33 #include "gtkmm2ext/doi.h"
35 #include "widgets/tooltips.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 "enums_convert.h"
61 #include "mixer_strip.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"
71 #include "ui_config.h"
75 using namespace ARDOUR;
76 using namespace ArdourWidgets;
79 using namespace Gtkmm2ext;
81 using namespace ArdourMeter;
83 MixerStrip* MixerStrip::_entered_mixer_strip;
84 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
86 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
87 : SessionHandlePtr (sess)
90 , _mixer_owned (in_mixer)
91 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
94 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
95 , rec_mon_table (2, 2)
96 , solo_iso_table (1, 2)
97 , mute_solo_table (1, 2)
98 , bottom_button_table (1, 3)
99 , monitor_section_button (0)
100 , midi_input_enable_button (0)
101 , _plugin_insert_cnt (0)
102 , _comment_button (_("Comments"))
103 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
104 , _visibility (X_("mixer-element-visibility"))
105 , control_slave_ui (sess)
110 /* the editor mixer strip: don't destroy it every time
111 the underlying route goes away.
114 self_destruct = false;
118 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
119 : SessionHandlePtr (sess)
122 , _mixer_owned (in_mixer)
123 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
126 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
127 , rec_mon_table (2, 2)
128 , solo_iso_table (1, 2)
129 , mute_solo_table (1, 2)
130 , bottom_button_table (1, 3)
131 , monitor_section_button (0)
132 , midi_input_enable_button (0)
133 , _plugin_insert_cnt (0)
134 , _comment_button (_("Comments"))
135 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
136 , _visibility (X_("mixer-element-visibility"))
137 , control_slave_ui (sess)
146 _entered_mixer_strip= 0;
149 ignore_comment_edit = false;
150 ignore_toggle = false;
154 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
155 longest_label = "longest label";
157 string t = _("Click to toggle the width of this mixer strip.");
159 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
162 width_button.set_icon (ArdourIcon::StripWidth);
163 hide_button.set_tweaks (ArdourButton::Square);
164 set_tooltip (width_button, t);
166 hide_button.set_icon (ArdourIcon::CloseCross);
167 hide_button.set_tweaks (ArdourButton::Square);
168 set_tooltip (&hide_button, _("Hide this mixer strip"));
170 input_button_box.set_spacing(2);
172 input_button.set_text (_("Input"));
173 input_button.set_name ("mixer strip button");
174 input_button_box.pack_start (input_button, true, true);
176 output_button.set_text (_("Output"));
177 output_button.set_name ("mixer strip button");
179 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
181 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
183 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
184 solo_isolated_led->show ();
185 solo_isolated_led->set_no_show_all (true);
186 solo_isolated_led->set_name (X_("solo isolate"));
187 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
188 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
189 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
191 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
192 solo_safe_led->show ();
193 solo_safe_led->set_no_show_all (true);
194 solo_safe_led->set_name (X_("solo safe"));
195 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
196 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
197 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
199 solo_safe_led->set_text (S_("SoloLock|Lock"));
200 solo_isolated_led->set_text (_("Iso"));
202 solo_iso_table.set_homogeneous (true);
203 solo_iso_table.set_spacings (2);
204 if (!ARDOUR::Profile->get_trx()) {
205 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
206 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
208 solo_iso_table.show ();
210 rec_mon_table.set_homogeneous (true);
211 rec_mon_table.set_row_spacings (2);
212 rec_mon_table.set_col_spacings (2);
213 if (ARDOUR::Profile->get_mixbus()) {
214 rec_mon_table.resize (1, 3);
215 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
216 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
217 } else if (!ARDOUR::Profile->get_trx()) {
218 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
219 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
221 rec_mon_table.show ();
223 if (solo_isolated_led) {
224 button_size_group->add_widget (*solo_isolated_led);
227 button_size_group->add_widget (*solo_safe_led);
230 if (!ARDOUR::Profile->get_mixbus()) {
231 if (rec_enable_button) {
232 button_size_group->add_widget (*rec_enable_button);
234 if (monitor_disk_button) {
235 button_size_group->add_widget (*monitor_disk_button);
237 if (monitor_input_button) {
238 button_size_group->add_widget (*monitor_input_button);
242 mute_solo_table.set_homogeneous (true);
243 mute_solo_table.set_spacings (2);
245 bottom_button_table.set_spacings (2);
246 bottom_button_table.set_homogeneous (true);
247 bottom_button_table.attach (group_button, 1, 2, 0, 1);
248 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
250 name_button.set_name ("mixer strip button");
251 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
252 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
254 set_tooltip (&group_button, _("Mix group"));
255 group_button.set_name ("mixer strip button");
257 _comment_button.set_name (X_("mixer strip button"));
258 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
259 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
260 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
262 // TODO implement ArdourKnob::on_size_request properly
263 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
264 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
266 trim_control.set_tooltip_prefix (_("Trim: "));
267 trim_control.set_name ("trim knob");
268 trim_control.set_no_show_all (true);
269 input_button_box.pack_start (trim_control, false, false);
271 global_vpacker.set_border_width (1);
272 global_vpacker.set_spacing (0);
274 width_button.set_name ("mixer strip button");
275 hide_button.set_name ("mixer strip button");
277 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
278 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
280 width_hide_box.set_spacing (2);
281 width_hide_box.pack_start (width_button, false, true);
282 width_hide_box.pack_start (number_label, true, true);
283 width_hide_box.pack_end (hide_button, false, true);
285 number_label.set_text ("-");
286 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
287 number_label.set_no_show_all ();
288 number_label.set_name ("tracknumber label");
289 number_label.set_fixed_colors (0x80808080, 0x80808080);
290 number_label.set_alignment (.5, .5);
291 number_label.set_fallthrough_to_parent (true);
292 number_label.set_tweaks (ArdourButton::OccasionalText);
294 global_vpacker.set_spacing (2);
295 if (!ARDOUR::Profile->get_trx()) {
296 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
297 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
298 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
299 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
300 global_vpacker.pack_start (processor_box, true, true);
302 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
303 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
309 if (!ARDOUR::Profile->get_trx()) {
310 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
317 //add a spacer underneath the master bus;
318 //this fills the area that is taken up by the scrollbar on the tracks;
319 //and therefore keeps the faders "even" across the bottom
320 int scrollbar_height = 0;
322 Gtk::Window window (WINDOW_TOPLEVEL);
323 HScrollbar scrollbar;
324 window.add (scrollbar);
325 scrollbar.set_name ("MixerWindow");
326 scrollbar.ensure_style();
327 Gtk::Requisition requisition(scrollbar.size_request ());
328 scrollbar_height = requisition.height;
330 spacer.set_size_request (-1, scrollbar_height);
331 global_vpacker.pack_end (spacer, false, false);
334 global_frame.add (global_vpacker);
335 global_frame.set_shadow_type (Gtk::SHADOW_IN);
336 global_frame.set_name ("BaseFrame");
340 /* force setting of visible selected status */
343 set_selected (false);
348 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
349 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
351 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
352 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
353 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
355 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
356 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
358 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
359 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
360 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
362 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
364 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
366 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
370 /* start off as a passthru strip. we'll correct this, if necessary,
371 in update_diskstream_display().
374 /* start off as a passthru strip. we'll correct this, if necessary,
375 in update_diskstream_display().
378 if (is_midi_track()) {
379 set_name ("MidiTrackStripBase");
381 set_name ("AudioTrackStripBase");
384 add_events (Gdk::BUTTON_RELEASE_MASK|
385 Gdk::ENTER_NOTIFY_MASK|
386 Gdk::LEAVE_NOTIFY_MASK|
388 Gdk::KEY_RELEASE_MASK);
390 set_flags (get_flags() | Gtk::CAN_FOCUS);
392 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
393 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
396 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
397 must be the same as those used in RCOptionEditor so that the configuration changes
398 are recognised when they occur.
400 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
401 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
402 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
403 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
404 _visibility.add (&output_button, X_("Output"), _("Output"), false);
405 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
406 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
408 parameter_changed (X_("mixer-element-visibility"));
409 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
410 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
411 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
413 //watch for mouse enter/exit so we can do some stuff
414 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
415 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
417 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
420 MixerStrip::~MixerStrip ()
422 CatchDeletion (this);
424 if (this ==_entered_mixer_strip)
425 _entered_mixer_strip = NULL;
429 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
431 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
437 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
439 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
445 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
447 _entered_mixer_strip = this;
449 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
450 //because the mixerstrip control is a parent that encompasses the strip
451 deselect_all_processors();
457 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
459 //if we have moved outside our strip, but not into a child view, then deselect ourselves
460 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
461 _entered_mixer_strip= 0;
463 //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
464 gpm.gain_display.set_sensitive(false);
466 gpm.gain_display.set_sensitive(true);
468 //if we leave this mixer strip we need to clear out any selections
469 //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
476 MixerStrip::name() const
479 return _route->name();
485 MixerStrip::update_trim_control ()
487 if (route()->trim() && route()->trim()->active() &&
488 route()->n_inputs().n_audio() > 0) {
489 trim_control.show ();
490 trim_control.set_controllable (route()->trim()->gain_control());
492 trim_control.hide ();
493 boost::shared_ptr<Controllable> none;
494 trim_control.set_controllable (none);
499 MixerStrip::set_route (boost::shared_ptr<Route> rt)
501 //the rec/monitor stuff only shows up for tracks.
502 //the show_sends only shows up for buses.
503 //remove them all here, and we may add them back later
504 if (show_sends_button->get_parent()) {
505 rec_mon_table.remove (*show_sends_button);
507 if (rec_enable_button->get_parent()) {
508 rec_mon_table.remove (*rec_enable_button);
510 if (monitor_input_button->get_parent()) {
511 rec_mon_table.remove (*monitor_input_button);
513 if (monitor_disk_button->get_parent()) {
514 rec_mon_table.remove (*monitor_disk_button);
516 if (group_button.get_parent()) {
517 bottom_button_table.remove (group_button);
520 RouteUI::set_route (rt);
522 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
524 /* ProcessorBox needs access to _route so that it can read
527 processor_box.set_route (rt);
529 revert_to_default_display ();
531 /* unpack these from the parent and stuff them into our own
535 if (gpm.peak_display.get_parent()) {
536 gpm.peak_display.get_parent()->remove (gpm.peak_display);
538 if (gpm.gain_display.get_parent()) {
539 gpm.gain_display.get_parent()->remove (gpm.gain_display);
542 gpm.set_type (rt->meter_type());
544 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
545 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
547 if (solo_button->get_parent()) {
548 mute_solo_table.remove (*solo_button);
551 if (mute_button->get_parent()) {
552 mute_solo_table.remove (*mute_button);
555 if (route()->is_master()) {
556 solo_button->hide ();
557 mute_button->show ();
558 rec_mon_table.hide ();
559 solo_iso_table.set_sensitive(false);
560 control_slave_ui.set_sensitive(false);
561 if (monitor_section_button == 0) {
562 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
563 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
565 monitor_section_button = manage (new ArdourButton);
567 monitor_section_button->set_related_action (act);
568 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
569 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
570 monitor_section_button->show();
571 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
573 parameter_changed ("use-monitor-bus");
575 bottom_button_table.attach (group_button, 1, 2, 0, 1);
576 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
577 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
578 mute_button->show ();
579 solo_button->show ();
580 rec_mon_table.show ();
581 solo_iso_table.set_sensitive(true);
582 control_slave_ui.set_sensitive(true);
585 if (_mixer_owned && route()->is_master() ) {
592 monitor_input_button->show ();
593 monitor_disk_button->show ();
595 monitor_input_button->hide();
596 monitor_disk_button->hide ();
599 update_trim_control();
601 if (is_midi_track()) {
602 if (midi_input_enable_button == 0) {
603 midi_input_enable_button = manage (new ArdourButton);
604 midi_input_enable_button->set_name ("midi input button");
605 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
606 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
607 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
608 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
609 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
611 input_button_box.remove (*midi_input_enable_button);
613 /* get current state */
614 midi_input_status_changed ();
615 input_button_box.pack_start (*midi_input_enable_button, false, false);
617 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
619 if (midi_input_enable_button) {
620 /* removal from the container will delete it */
621 input_button_box.remove (*midi_input_enable_button);
622 midi_input_enable_button = 0;
626 if (is_audio_track()) {
627 boost::shared_ptr<AudioTrack> at = audio_track();
628 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
633 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
634 rec_enable_button->show();
636 if (ARDOUR::Profile->get_mixbus()) {
637 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
638 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
639 } else if (ARDOUR::Profile->get_trx()) {
640 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
642 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
643 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
650 if (!_route->is_master()) {
651 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
652 show_sends_button->show();
656 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
658 delete route_ops_menu;
661 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
662 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
663 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
664 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
666 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
668 if (_route->panner_shell()) {
669 update_panner_choices();
670 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
673 if (is_audio_track()) {
674 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
677 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
679 set_stuff_from_route ();
681 /* now force an update of all the various elements */
683 update_mute_display ();
684 update_solo_display ();
687 route_group_changed ();
688 update_track_number_visibility ();
691 panners.setup_pan ();
693 if (has_audio_outputs ()) {
699 update_diskstream_display ();
700 update_input_display ();
701 update_output_display ();
703 add_events (Gdk::BUTTON_RELEASE_MASK);
705 processor_box.show ();
707 if (!route()->is_master() && !route()->is_monitor()) {
708 /* we don't allow master or control routes to be hidden */
713 gpm.reset_peak_display ();
714 gpm.gain_display.show ();
715 gpm.peak_display.show ();
718 width_hide_box.show();
720 global_vpacker.show();
721 mute_solo_table.show();
722 bottom_button_table.show();
724 gpm.meter_point_button.show();
725 input_button_box.show_all();
726 output_button.show();
728 _comment_button.show();
730 gpm.gain_automation_state_button.show();
732 parameter_changed ("mixer-element-visibility");
739 MixerStrip::set_stuff_from_route ()
741 /* if width is not set, it will be set by the MixerUI or editor */
744 if (get_gui_property ("strip-width", width)) {
745 set_width_enum (width, this);
750 MixerStrip::set_width_enum (Width w, void* owner)
752 /* always set the gpm width again, things may be hidden */
755 panners.set_width (w);
757 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
759 _width_owner = owner;
763 if (_width_owner == this) {
764 set_gui_property ("strip-width", _width);
769 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
774 if (show_sends_button) {
775 show_sends_button->set_text (_("Aux"));
778 gpm.gain_automation_state_button.set_text (
779 gpm.astate_string(gain_automation->automation_state()));
781 if (_route->panner()) {
782 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
783 panners.astate_string(_route->panner()->automation_state()));
787 // panners expect an even number of horiz. pixels
788 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
790 set_size_request (width, -1);
796 if (show_sends_button) {
797 show_sends_button->set_text (_("Snd"));
800 gpm.gain_automation_state_button.set_text (
801 gpm.short_astate_string(gain_automation->automation_state()));
802 gain_meter().setup_meters (); // recalc meter width
804 if (_route->panner()) {
805 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
806 panners.short_astate_string(_route->panner()->automation_state()));
810 // panners expect an even number of horiz. pixels
811 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
813 set_size_request (width, -1);
818 processor_box.set_width (w);
820 update_input_display ();
821 update_output_display ();
822 setup_comment_button ();
823 route_group_changed ();
829 MixerStrip::set_packed (bool yn)
832 set_gui_property ("visible", _packed);
836 struct RouteCompareByName {
837 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
838 return a->name().compare (b->name()) < 0;
843 MixerStrip::output_release (GdkEventButton *ev)
845 switch (ev->button) {
847 edit_output_configuration ();
855 MixerStrip::output_press (GdkEventButton *ev)
857 using namespace Menu_Helpers;
858 if (!_session->engine().connected()) {
859 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
864 MenuList& citems = output_menu.items();
865 switch (ev->button) {
868 return false; //wait for the mouse-up to pop the dialog
872 output_menu.set_name ("ArdourContextMenu");
874 output_menu_bundles.clear ();
876 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
878 citems.push_back (SeparatorElem());
879 uint32_t const n_with_separator = citems.size ();
881 ARDOUR::BundleList current = _route->output()->bundles_connected ();
883 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
885 /* give user bundles first chance at being in the menu */
887 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
888 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
889 maybe_add_bundle_to_output_menu (*i, current);
893 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
894 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
895 maybe_add_bundle_to_output_menu (*i, current);
899 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
900 RouteList copy = *routes;
901 copy.sort (RouteCompareByName ());
902 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
903 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
906 if (citems.size() == n_with_separator) {
907 /* no routes added; remove the separator */
911 if (!ARDOUR::Profile->get_mixbus()) {
912 citems.push_back (SeparatorElem());
914 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
917 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
918 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
924 citems.push_back (SeparatorElem());
925 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
927 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
940 MixerStrip::input_release (GdkEventButton *ev)
942 switch (ev->button) {
945 edit_input_configuration ();
957 MixerStrip::input_press (GdkEventButton *ev)
959 using namespace Menu_Helpers;
961 MenuList& citems = input_menu.items();
962 input_menu.set_name ("ArdourContextMenu");
965 if (!_session->engine().connected()) {
966 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
971 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
974 switch (ev->button) {
977 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
981 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
983 citems.push_back (SeparatorElem());
984 uint32_t const n_with_separator = citems.size ();
986 input_menu_bundles.clear ();
988 ARDOUR::BundleList current = _route->input()->bundles_connected ();
990 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
992 /* give user bundles first chance at being in the menu */
994 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
995 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
996 maybe_add_bundle_to_input_menu (*i, current);
1000 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1001 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1002 maybe_add_bundle_to_input_menu (*i, current);
1006 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1007 RouteList copy = *routes;
1008 copy.sort (RouteCompareByName ());
1009 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1010 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1013 if (citems.size() == n_with_separator) {
1014 /* no routes added; remove the separator */
1018 citems.push_back (SeparatorElem());
1019 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1022 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1023 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1028 citems.push_back (SeparatorElem());
1029 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1031 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1043 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1045 if (ignore_toggle) {
1049 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1051 if (std::find (current.begin(), current.end(), c) == current.end()) {
1052 _route->input()->connect_ports_to_bundle (c, true, this);
1054 _route->input()->disconnect_ports_from_bundle (c, this);
1059 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1061 if (ignore_toggle) {
1065 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1067 if (std::find (current.begin(), current.end(), c) == current.end()) {
1068 _route->output()->connect_ports_to_bundle (c, true, this);
1070 _route->output()->disconnect_ports_from_bundle (c, this);
1075 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1077 using namespace Menu_Helpers;
1079 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1083 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1084 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1088 if (i != input_menu_bundles.end()) {
1092 input_menu_bundles.push_back (b);
1094 MenuList& citems = input_menu.items();
1095 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1099 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1101 using namespace Menu_Helpers;
1103 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1107 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1108 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1112 if (i != output_menu_bundles.end()) {
1116 output_menu_bundles.push_back (b);
1118 MenuList& citems = output_menu.items();
1119 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1123 MixerStrip::update_diskstream_display ()
1125 if (is_track() && input_selector) {
1126 input_selector->hide_all ();
1129 route_color_changed ();
1133 MixerStrip::connect_to_pan ()
1135 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1137 panstate_connection.disconnect ();
1138 panstyle_connection.disconnect ();
1140 if (!_route->panner()) {
1144 boost::shared_ptr<Pannable> p = _route->pannable ();
1146 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1148 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1149 * However, that only works a panner was previously set.
1151 * PannerUI must remain subscribed to _panshell->Changed() in case
1152 * we switch the panner eg. AUX-Send and back
1153 * _route->panner_shell()->Changed() vs _panshell->Changed
1155 if (panners._panner == 0) {
1156 panners.panshell_changed ();
1158 update_panner_choices();
1162 MixerStrip::update_panner_choices ()
1164 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1165 if (!_route->panner_shell()) { return; }
1167 uint32_t in = _route->output()->n_ports().n_audio();
1169 if (_route->panner()) {
1170 in = _route->panner()->in().n_audio();
1173 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1177 * Output port labelling
1178 * =====================
1180 * Case 1: Each output has one connection, all connections are to system:playback_%i
1181 * out 1 -> system:playback_1
1182 * out 2 -> system:playback_2
1183 * out 3 -> system:playback_3
1186 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1187 * out 1 -> ardour:track_x/in 1
1188 * out 2 -> ardour:track_x/in 2
1189 * Display as: track_x
1191 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1192 * out 1 -> program x:foo
1193 * out 2 -> program x:foo
1194 * Display as: program x
1196 * Case 4: No connections (Disconnected)
1199 * Default case (unusual routing):
1200 * Display as: *number of connections*
1204 * .-----------------------------------------------.
1206 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1207 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1208 * '-----------------------------------------------'
1209 * .-----------------------------------------------.
1212 * '-----------------------------------------------'
1216 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1220 boost::shared_ptr<IO> io;
1221 boost::shared_ptr<Port> port;
1222 vector<string> port_connections;
1224 uint32_t total_connection_count = 0;
1225 uint32_t io_connection_count = 0;
1226 uint32_t ardour_connection_count = 0;
1227 uint32_t system_connection_count = 0;
1228 uint32_t other_connection_count = 0;
1229 uint32_t typed_connection_count = 0;
1231 ostringstream label;
1233 bool have_label = false;
1234 bool each_io_has_one_connection = true;
1236 string connection_name;
1237 string ardour_track_name;
1238 string other_connection_type;
1239 string system_ports;
1242 ostringstream tooltip;
1243 char * tooltip_cstr;
1245 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1247 * First of all, if the user made only connections to a given type, we should use that one since
1248 * it is very probably what the user expects. If there are several connections types, then show
1249 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1250 * synthesisers. This first heuristic can be expressed with these two rules:
1251 * A) If there are connected audio ports, consider audio as primary type.
1252 * B) Else, if there are connected midi ports, consider midi as primary type.
1254 * If there are no connected ports, then we choose the primary type based on the type of existing
1255 * but unconnected ports. Again:
1256 * C) If there are audio ports, consider audio as primary type.
1257 * D) Else, if there are midi ports, consider midi as primary type. */
1259 DataType dt = DataType::AUDIO;
1263 io = route->input();
1265 io = route->output();
1268 io_count = io->n_ports().n_total();
1269 for (io_index = 0; io_index < io_count; ++io_index) {
1270 port = io->nth (io_index);
1271 if (port->connected()) {
1273 if (port->type() == DataType::AUDIO) {
1274 /* Rule A) applies no matter the remaining ports */
1275 dt = DataType::AUDIO;
1278 if (port->type() == DataType::MIDI) {
1279 /* Rule B) is a good candidate... */
1280 dt = DataType::MIDI;
1281 /* ...but continue the loop to check remaining ports for rule A) */
1287 /* Neither rule A) nor rule B) matched */
1288 if ( io->n_ports().n_audio() > 0 ) {
1290 dt = DataType::AUDIO;
1291 } else if ( io->n_ports().n_midi() > 0 ) {
1293 dt = DataType::MIDI;
1297 if ( dt == DataType::MIDI ) {
1298 tooltip << _("MIDI ");
1302 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1304 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1307 for (io_index = 0; io_index < io_count; ++io_index) {
1308 port = io->nth (io_index);
1310 port_connections.clear ();
1311 port->get_connections(port_connections);
1313 //ignore any port connections that don't match our DataType
1314 if (port->type() != dt) {
1315 if (!port_connections.empty()) {
1316 ++typed_connection_count;
1321 io_connection_count = 0;
1323 if (!port_connections.empty()) {
1324 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1326 string& connection_name (*i);
1328 if (connection_name.find("system:") == 0) {
1329 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1332 if (io_connection_count == 0) {
1333 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1335 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1338 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1341 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1342 if (ardour_track_name.empty()) {
1343 // "ardour:Master/in 1" -> "ardour:Master/"
1344 string::size_type slash = connection_name.find("/");
1345 if (slash != string::npos) {
1346 ardour_track_name = connection_name.substr(0, slash + 1);
1350 if (connection_name.find(ardour_track_name) == 0) {
1351 ++ardour_connection_count;
1353 } else if (!pn.empty()) {
1354 if (system_ports.empty()) {
1357 system_ports += "/" + pn;
1359 if (connection_name.find("system:") == 0) {
1360 ++system_connection_count;
1362 } else if (connection_name.find("system:midi_") == 0) {
1364 // "system:midi_capture_123" -> "123"
1365 system_port = "M " + connection_name.substr(20);
1367 // "system:midi_playback_123" -> "123"
1368 system_port = "M " + connection_name.substr(21);
1371 if (system_ports.empty()) {
1372 system_ports += system_port;
1374 system_ports += "/" + system_port;
1377 ++system_connection_count;
1379 } else if (connection_name.find("system:") == 0) {
1381 // "system:capture_123" -> "123"
1382 system_port = connection_name.substr(15);
1384 // "system:playback_123" -> "123"
1385 system_port = connection_name.substr(16);
1388 if (system_ports.empty()) {
1389 system_ports += system_port;
1391 system_ports += "/" + system_port;
1394 ++system_connection_count;
1396 if (other_connection_type.empty()) {
1397 // "jamin:in 1" -> "jamin:"
1398 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1401 if (connection_name.find(other_connection_type) == 0) {
1402 ++other_connection_count;
1406 ++total_connection_count;
1407 ++io_connection_count;
1411 if (io_connection_count != 1) {
1412 each_io_has_one_connection = false;
1416 if (total_connection_count == 0) {
1417 tooltip << endl << _("Disconnected");
1420 tooltip_cstr = new char[tooltip.str().size() + 1];
1421 strcpy(tooltip_cstr, tooltip.str().c_str());
1424 set_tooltip (&input_button, tooltip_cstr);
1426 set_tooltip (&output_button, tooltip_cstr);
1429 delete [] tooltip_cstr;
1431 if (each_io_has_one_connection) {
1432 if (total_connection_count == ardour_connection_count) {
1433 // all connections are to the same track in ardour
1434 // "ardour:Master/" -> "Master"
1435 string::size_type slash = ardour_track_name.find("/");
1436 if (slash != string::npos) {
1437 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1438 label << ardour_track_name.substr (ppps, slash - ppps);
1442 else if (total_connection_count == system_connection_count) {
1443 // all connections are to system ports
1444 label << system_ports;
1447 else if (total_connection_count == other_connection_count) {
1448 // all connections are to the same external program eg jamin
1449 // "jamin:" -> "jamin"
1450 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1456 if (total_connection_count == 0) {
1460 // Odd configuration
1461 label << "*" << total_connection_count << "*";
1463 if (typed_connection_count > 0) {
1464 label << "\u2295"; // circled plus
1469 input_button.set_text (label.str());
1471 output_button.set_text (label.str());
1476 MixerStrip::update_input_display ()
1478 update_io_button (_route, _width, true);
1479 panners.setup_pan ();
1481 if (has_audio_outputs ()) {
1482 panners.show_all ();
1484 panners.hide_all ();
1490 MixerStrip::update_output_display ()
1492 update_io_button (_route, _width, false);
1493 gpm.setup_meters ();
1494 panners.setup_pan ();
1496 if (has_audio_outputs ()) {
1497 panners.show_all ();
1499 panners.hide_all ();
1504 MixerStrip::fast_update ()
1506 gpm.update_meters ();
1510 MixerStrip::diskstream_changed ()
1512 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1516 MixerStrip::io_changed_proxy ()
1518 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1519 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1523 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1525 boost::shared_ptr<Port> a = wa.lock ();
1526 boost::shared_ptr<Port> b = wb.lock ();
1528 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1529 update_input_display ();
1530 set_width_enum (_width, this);
1533 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1534 update_output_display ();
1535 set_width_enum (_width, this);
1540 MixerStrip::setup_comment_button ()
1542 std::string comment = _route->comment();
1544 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1546 if (comment.empty ()) {
1547 _comment_button.set_name ("generic button");
1548 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1552 _comment_button.set_name ("comment button");
1554 string::size_type pos = comment.find_first_of (" \t\n");
1555 if (pos != string::npos) {
1556 comment = comment.substr (0, pos);
1558 if (comment.empty()) {
1559 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1561 _comment_button.set_text (comment);
1566 MixerStrip::select_route_group (GdkEventButton *ev)
1568 using namespace Menu_Helpers;
1570 if (ev->button == 1) {
1572 if (group_menu == 0) {
1574 PropertyList* plist = new PropertyList();
1576 plist->add (Properties::group_gain, true);
1577 plist->add (Properties::group_mute, true);
1578 plist->add (Properties::group_solo, true);
1580 group_menu = new RouteGroupMenu (_session, plist);
1584 r.push_back (route ());
1585 group_menu->build (r);
1587 RouteGroup *rg = _route->route_group();
1589 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1590 rg ? rg->name() : _("No Group"),
1598 MixerStrip::route_group_changed ()
1600 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1602 RouteGroup *rg = _route->route_group();
1605 group_button.set_text (PBD::short_version (rg->name(), 5));
1609 group_button.set_text (_("Grp"));
1612 group_button.set_text (_("~G"));
1619 MixerStrip::route_color_changed ()
1621 using namespace ARDOUR_UI_UTILS;
1622 name_button.modify_bg (STATE_NORMAL, color());
1623 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1624 reset_strip_style ();
1628 MixerStrip::show_passthru_color ()
1630 reset_strip_style ();
1635 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1637 boost::shared_ptr<Processor> processor (p.lock ());
1638 if (!processor || !processor->display_to_user()) {
1641 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1643 if (pi && pi->is_channelstrip ()) {
1648 ++_plugin_insert_cnt;
1652 MixerStrip::build_route_ops_menu ()
1654 using namespace Menu_Helpers;
1655 route_ops_menu = new Menu;
1656 route_ops_menu->set_name ("ArdourContextMenu");
1658 MenuList& items = route_ops_menu->items();
1660 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1662 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1664 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1666 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1668 if (!Profile->get_mixbus()) {
1669 items.push_back (SeparatorElem());
1672 if (!_route->is_master()
1674 && !_route->mixbus()
1677 if (Profile->get_mixbus()) {
1678 items.push_back (SeparatorElem());
1680 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1683 if (!Profile->get_mixbus()) {
1684 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1685 /* do not allow rename if the track is record-enabled */
1686 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1689 items.push_back (SeparatorElem());
1690 items.push_back (CheckMenuElem (_("Active")));
1691 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1692 i->set_active (_route->active());
1693 i->set_sensitive(! _session->transport_rolling());
1694 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1696 if (!Profile->get_mixbus ()) {
1697 items.push_back (SeparatorElem());
1698 items.push_back (CheckMenuElem (_("Strict I/O")));
1699 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1700 i->set_active (_route->strict_io());
1701 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1704 _plugin_insert_cnt = 0;
1705 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1706 if (_plugin_insert_cnt > 0) {
1707 items.push_back (SeparatorElem());
1708 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1711 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1712 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1713 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1714 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1717 items.push_back (SeparatorElem());
1718 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1720 items.push_back (SeparatorElem());
1721 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1722 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1723 denormal_menu_item->set_active (_route->denormal_protection());
1726 /* note that this relies on selection being shared across editor and
1727 mixer (or global to the backend, in the future), which is the only
1728 sane thing for users anyway.
1731 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1733 Selection& selection (PublicEditor::instance().get_selection());
1734 if (!selection.selected (rtav)) {
1735 selection.set (rtav);
1738 if (!_route->is_master()) {
1739 items.push_back (SeparatorElem());
1740 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1743 items.push_back (SeparatorElem());
1744 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1750 MixerStrip::name_button_button_press (GdkEventButton* ev)
1752 if (ev->button == 1 || ev->button == 3) {
1753 list_route_operations ();
1755 if (ev->button == 1) {
1756 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1759 route_ops_menu->popup (3, ev->time);
1769 MixerStrip::number_button_button_press (GdkEventButton* ev)
1771 if ( ev->button == 3 ) {
1772 list_route_operations ();
1774 route_ops_menu->popup (1, ev->time);
1783 MixerStrip::list_route_operations ()
1785 delete route_ops_menu;
1786 build_route_ops_menu ();
1790 MixerStrip::set_selected (bool yn)
1792 AxisView::set_selected (yn);
1795 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1796 global_frame.set_name ("MixerStripSelectedFrame");
1798 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1799 global_frame.set_name ("MixerStripFrame");
1802 global_frame.queue_draw ();
1805 // processor_box.deselect_all_processors();
1809 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1811 if (what_changed.contains (ARDOUR::Properties::name)) {
1817 MixerStrip::name_changed ()
1821 name_button.set_text (_route->name());
1824 name_button.set_text (PBD::short_version (_route->name(), 5));
1828 set_tooltip (name_button, _route->name());
1830 if (_session->config.get_track_name_number()) {
1831 const int64_t track_number = _route->track_number ();
1832 if (track_number == 0) {
1833 number_label.set_text ("-");
1835 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1838 number_label.set_text ("");
1843 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1845 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1849 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1851 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1855 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1857 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1861 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1863 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1867 MixerStrip::width_button_pressed (GdkEventButton* ev)
1869 if (ev->button != 1) {
1873 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1876 _mixer.set_strip_width (Narrow, true);
1880 _mixer.set_strip_width (Wide, true);
1886 set_width_enum (Narrow, this);
1889 set_width_enum (Wide, this);
1898 MixerStrip::hide_clicked ()
1900 // LAME fix to reset the button status for when it is redisplayed (part 1)
1901 hide_button.set_sensitive(false);
1904 Hiding(); /* EMIT_SIGNAL */
1906 _mixer.hide_strip (this);
1910 hide_button.set_sensitive(true);
1914 MixerStrip::set_embedded (bool yn)
1920 MixerStrip::map_frozen ()
1922 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1924 boost::shared_ptr<AudioTrack> at = audio_track();
1927 switch (at->freeze_state()) {
1928 case AudioTrack::Frozen:
1929 processor_box.set_sensitive (false);
1930 hide_redirect_editors ();
1933 processor_box.set_sensitive (true);
1934 // XXX need some way, maybe, to retoggle redirect editors
1938 processor_box.set_sensitive (true);
1940 RouteUI::map_frozen ();
1944 MixerStrip::hide_redirect_editors ()
1946 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1950 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1952 boost::shared_ptr<Processor> processor (p.lock ());
1957 Gtk::Window* w = processor_box.get_processor_ui (processor);
1965 MixerStrip::reset_strip_style ()
1967 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1969 gpm.set_fader_name ("SendStripBase");
1973 if (is_midi_track()) {
1974 if (_route->active()) {
1975 set_name ("MidiTrackStripBase");
1977 set_name ("MidiTrackStripBaseInactive");
1979 gpm.set_fader_name ("MidiTrackFader");
1980 } else if (is_audio_track()) {
1981 if (_route->active()) {
1982 set_name ("AudioTrackStripBase");
1984 set_name ("AudioTrackStripBaseInactive");
1986 gpm.set_fader_name ("AudioTrackFader");
1988 if (_route->active()) {
1989 set_name ("AudioBusStripBase");
1991 set_name ("AudioBusStripBaseInactive");
1993 gpm.set_fader_name ("AudioBusFader");
1995 /* (no MIDI busses yet) */
2002 MixerStrip::engine_stopped ()
2007 MixerStrip::engine_running ()
2012 MixerStrip::meter_point_string (MeterPoint mp)
2025 case MeterPostFader:
2042 return S_("Meter|In");
2046 return S_("Meter|Pr");
2049 case MeterPostFader:
2050 return S_("Meter|Po");
2054 return S_("Meter|O");
2059 return S_("Meter|C");
2068 /** Called when the monitor-section state */
2070 MixerStrip::monitor_changed ()
2072 assert (monitor_section_button);
2073 if (_session->monitor_active()) {
2074 monitor_section_button->set_name ("master monitor section button active");
2076 monitor_section_button->set_name ("master monitor section button normal");
2080 /** Called when the metering point has changed */
2082 MixerStrip::meter_changed ()
2084 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2085 gpm.setup_meters ();
2086 // reset peak when meter point changes
2087 gpm.reset_peak_display();
2090 /** The bus that we are displaying sends to has changed, or been turned off.
2091 * @param send_to New bus that we are displaying sends to, or 0.
2094 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2096 RouteUI::bus_send_display_changed (send_to);
2099 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2104 revert_to_default_display ();
2107 revert_to_default_display ();
2112 MixerStrip::drop_send ()
2114 boost::shared_ptr<Send> current_send;
2116 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2117 current_send->set_metering (false);
2120 send_gone_connection.disconnect ();
2121 input_button.set_sensitive (true);
2122 output_button.set_sensitive (true);
2123 group_button.set_sensitive (true);
2124 set_invert_sensitive (true);
2125 gpm.meter_point_button.set_sensitive (true);
2126 mute_button->set_sensitive (true);
2127 solo_button->set_sensitive (true);
2128 solo_isolated_led->set_sensitive (true);
2129 solo_safe_led->set_sensitive (true);
2130 monitor_input_button->set_sensitive (true);
2131 monitor_disk_button->set_sensitive (true);
2132 _comment_button.set_sensitive (true);
2133 RouteUI::check_rec_enable_sensitivity ();
2134 set_button_names (); // update solo button visual state
2138 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2140 _current_delivery = d;
2141 DeliveryChanged (_current_delivery);
2145 MixerStrip::show_send (boost::shared_ptr<Send> send)
2151 set_current_delivery (send);
2153 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2154 send->set_metering (true);
2155 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2157 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2158 gain_meter().setup_meters ();
2160 uint32_t const in = _current_delivery->pans_required();
2161 uint32_t const out = _current_delivery->pan_outs();
2163 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2164 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2165 panner_ui().setup_pan ();
2166 panner_ui().set_send_drawing_mode (true);
2167 panner_ui().show_all ();
2169 input_button.set_sensitive (false);
2170 group_button.set_sensitive (false);
2171 set_invert_sensitive (false);
2172 gpm.meter_point_button.set_sensitive (false);
2173 mute_button->set_sensitive (false);
2174 solo_button->set_sensitive (false);
2175 rec_enable_button->set_sensitive (false);
2176 solo_isolated_led->set_sensitive (false);
2177 solo_safe_led->set_sensitive (false);
2178 monitor_input_button->set_sensitive (false);
2179 monitor_disk_button->set_sensitive (false);
2180 _comment_button.set_sensitive (false);
2182 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2183 output_button.set_sensitive (false);
2186 reset_strip_style ();
2190 MixerStrip::revert_to_default_display ()
2194 set_current_delivery (_route->main_outs ());
2196 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2197 gain_meter().setup_meters ();
2199 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2200 update_panner_choices();
2201 panner_ui().setup_pan ();
2202 panner_ui().set_send_drawing_mode (false);
2204 if (has_audio_outputs ()) {
2205 panners.show_all ();
2207 panners.hide_all ();
2210 reset_strip_style ();
2214 MixerStrip::set_button_names ()
2218 mute_button->set_text (_("Mute"));
2219 monitor_input_button->set_text (_("In"));
2220 monitor_disk_button->set_text (_("Disk"));
2221 if (monitor_section_button) {
2222 monitor_section_button->set_text (_("Mon"));
2225 if (_route && _route->solo_safe_control()->solo_safe()) {
2226 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2228 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2230 if (!Config->get_solo_control_is_listen_control()) {
2231 solo_button->set_text (_("Solo"));
2233 switch (Config->get_listen_position()) {
2234 case AfterFaderListen:
2235 solo_button->set_text (_("AFL"));
2237 case PreFaderListen:
2238 solo_button->set_text (_("PFL"));
2242 solo_isolated_led->set_text (_("Iso"));
2243 solo_safe_led->set_text (S_("SoloLock|Lock"));
2247 mute_button->set_text (S_("Mute|M"));
2248 monitor_input_button->set_text (S_("MonitorInput|I"));
2249 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2250 if (monitor_section_button) {
2251 monitor_section_button->set_text (S_("Mon|O"));
2254 if (_route && _route->solo_safe_control()->solo_safe()) {
2255 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2257 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2259 if (!Config->get_solo_control_is_listen_control()) {
2260 solo_button->set_text (S_("Solo|S"));
2262 switch (Config->get_listen_position()) {
2263 case AfterFaderListen:
2264 solo_button->set_text (S_("AfterFader|A"));
2266 case PreFaderListen:
2267 solo_button->set_text (S_("Prefader|P"));
2272 solo_isolated_led->set_text (S_("SoloIso|I"));
2273 solo_safe_led->set_text (S_("SoloLock|L"));
2278 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2280 gpm.meter_point_button.set_text ("");
2285 MixerStrip::plugin_selector()
2287 return _mixer.plugin_selector();
2291 MixerStrip::hide_things ()
2293 processor_box.hide_things ();
2297 MixerStrip::input_active_button_press (GdkEventButton*)
2299 /* nothing happens on press */
2304 MixerStrip::input_active_button_release (GdkEventButton* ev)
2306 boost::shared_ptr<MidiTrack> mt = midi_track ();
2312 boost::shared_ptr<RouteList> rl (new RouteList);
2314 rl->push_back (route());
2316 _session->set_exclusive_input_active (rl, !mt->input_active(),
2317 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2323 MixerStrip::midi_input_status_changed ()
2325 if (midi_input_enable_button) {
2326 boost::shared_ptr<MidiTrack> mt = midi_track ();
2328 midi_input_enable_button->set_active (mt->input_active ());
2333 MixerStrip::state_id () const
2335 return string_compose ("strip %1", _route->id().to_s());
2339 MixerStrip::parameter_changed (string p)
2341 if (p == _visibility.get_state_name()) {
2342 /* The user has made changes to the mixer strip visibility, so get
2343 our VisibilityGroup to reflect these changes in our widgets.
2345 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2346 } else if (p == "track-name-number") {
2348 } else if (p == "use-monitor-bus") {
2349 if (monitor_section_button) {
2350 if (mute_button->get_parent()) {
2351 mute_button->get_parent()->remove(*mute_button);
2353 if (monitor_section_button->get_parent()) {
2354 monitor_section_button->get_parent()->remove(*monitor_section_button);
2356 if (Config->get_use_monitor_bus ()) {
2357 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2358 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2359 mute_button->show();
2360 monitor_section_button->show();
2362 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2363 mute_button->show();
2366 } else if (p == "track-name-number") {
2367 update_track_number_visibility();
2371 /** Called to decide whether the solo isolate / solo lock button visibility should
2372 * be overridden from that configured by the user. We do this for the master bus.
2374 * @return optional value that is present if visibility state should be overridden.
2376 boost::optional<bool>
2377 MixerStrip::override_solo_visibility () const
2379 if (_route && _route->is_master ()) {
2380 return boost::optional<bool> (false);
2383 return boost::optional<bool> ();
2387 MixerStrip::add_input_port (DataType t)
2389 _route->input()->add_port ("", this, t);
2393 MixerStrip::add_output_port (DataType t)
2395 _route->output()->add_port ("", this, t);
2399 MixerStrip::route_active_changed ()
2401 reset_strip_style ();
2405 MixerStrip::copy_processors ()
2407 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2411 MixerStrip::cut_processors ()
2413 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2417 MixerStrip::paste_processors ()
2419 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2423 MixerStrip::select_all_processors ()
2425 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2429 MixerStrip::deselect_all_processors ()
2431 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2435 MixerStrip::delete_processors ()
2437 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2441 MixerStrip::toggle_processors ()
2443 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2447 MixerStrip::ab_plugins ()
2449 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2453 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2455 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2458 if (ev->button == 3) {
2459 popup_level_meter_menu (ev);
2467 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2469 using namespace Gtk::Menu_Helpers;
2471 Gtk::Menu* m = manage (new Menu);
2472 MenuList& items = m->items ();
2474 RadioMenuItem::Group group;
2476 _suspend_menu_callbacks = true;
2477 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2478 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2479 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2480 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2481 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2483 if (gpm.meter_channels().n_audio() == 0) {
2484 m->popup (ev->button, ev->time);
2485 _suspend_menu_callbacks = false;
2489 RadioMenuItem::Group tgroup;
2490 items.push_back (SeparatorElem());
2492 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2493 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2494 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2495 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2496 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2497 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2498 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2499 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2500 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2501 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2502 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2505 if (_route->is_master()) {
2508 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2509 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2510 /* non-master bus */
2513 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2520 MeterType cmt = _route->meter_type();
2521 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2523 items.push_back (SeparatorElem());
2524 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2525 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2526 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2527 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2528 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2529 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2531 m->popup (ev->button, ev->time);
2532 _suspend_menu_callbacks = false;
2536 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2537 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2539 using namespace Menu_Helpers;
2541 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2542 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2543 i->set_active (_route->meter_point() == point);
2547 MixerStrip::set_meter_point (MeterPoint p)
2549 if (_suspend_menu_callbacks) return;
2550 _route->set_meter_point (p);
2554 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2555 RadioMenuItem::Group& group, string const & name, MeterType type)
2557 using namespace Menu_Helpers;
2559 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2560 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2561 i->set_active (_route->meter_type() == type);
2565 MixerStrip::set_meter_type (MeterType t)
2567 if (_suspend_menu_callbacks) return;
2572 MixerStrip::update_track_number_visibility ()
2574 DisplaySuspender ds;
2575 bool show_label = _session->config.get_track_name_number();
2577 if (_route && _route->is_master()) {
2582 number_label.show ();
2583 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2584 // except the width of the number label is subtracted from the name-hbox, so we
2585 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2586 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2588 number_label.set_size_request(tnw, -1);
2589 number_label.show ();
2591 number_label.hide ();
2596 MixerStrip::color () const
2598 return route_color ();
2602 MixerStrip::marked_for_display () const
2604 return !_route->presentation_info().hidden();
2608 MixerStrip::set_marked_for_display (bool yn)
2610 return RouteUI::mark_hidden (!yn);