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/meter.h"
42 #include "ardour/midi_track.h"
43 #include "ardour/pannable.h"
44 #include "ardour/panner.h"
45 #include "ardour/panner_shell.h"
46 #include "ardour/panner_manager.h"
47 #include "ardour/port.h"
48 #include "ardour/profile.h"
49 #include "ardour/route.h"
50 #include "ardour/route_group.h"
51 #include "ardour/send.h"
52 #include "ardour/session.h"
53 #include "ardour/types.h"
54 #include "ardour/user_bundle.h"
55 #include "ardour/vca.h"
56 #include "ardour/vca_manager.h"
58 #include "ardour_window.h"
59 #include "mixer_strip.h"
62 #include "ardour_button.h"
63 #include "public_editor.h"
65 #include "io_selector.h"
67 #include "gui_thread.h"
68 #include "route_group_menu.h"
69 #include "meter_patterns.h"
71 #include "ui_config.h"
75 using namespace ARDOUR;
76 using namespace ARDOUR_UI_UTILS;
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 , meter_point_button (_("pre"))
100 , monitor_section_button (0)
101 , midi_input_enable_button (0)
102 , _plugin_insert_cnt (0)
103 , _comment_button (_("Comments"))
104 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
105 , _visibility (X_("mixer-element-visibility"))
106 , control_slave_ui (sess)
111 /* the editor mixer strip: don't destroy it every time
112 the underlying route goes away.
115 self_destruct = false;
119 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
120 : SessionHandlePtr (sess)
123 , _mixer_owned (in_mixer)
124 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
127 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
128 , rec_mon_table (2, 2)
129 , solo_iso_table (1, 2)
130 , mute_solo_table (1, 2)
131 , bottom_button_table (1, 3)
132 , meter_point_button (_("pre"))
133 , monitor_section_button (0)
134 , midi_input_enable_button (0)
135 , _comment_button (_("Comments"))
136 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
137 , _visibility (X_("mixer-element-visibility"))
138 , control_slave_ui (sess)
147 _entered_mixer_strip= 0;
150 ignore_comment_edit = false;
151 ignore_toggle = false;
156 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
157 longest_label = "longest label";
159 string t = _("Click to toggle the width of this mixer strip.");
161 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
164 width_button.set_icon (ArdourIcon::StripWidth);
165 hide_button.set_tweaks (ArdourButton::Square);
166 set_tooltip (width_button, t);
168 hide_button.set_icon (ArdourIcon::CloseCross);
169 hide_button.set_tweaks (ArdourButton::Square);
170 set_tooltip (&hide_button, _("Hide this mixer strip"));
172 input_button_box.set_spacing(2);
174 input_button.set_text (_("Input"));
175 input_button.set_name ("mixer strip button");
176 input_button_box.pack_start (input_button, true, true);
178 output_button.set_text (_("Output"));
179 output_button.set_name ("mixer strip button");
181 set_tooltip (&meter_point_button, _("Click to select metering point"));
182 meter_point_button.set_name ("mixer strip button");
184 bottom_button_table.attach (meter_point_button, 2, 3, 0, 1);
186 meter_point_button.signal_button_press_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_press), false);
187 meter_point_button.signal_button_release_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_release), false);
189 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
191 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
192 solo_isolated_led->show ();
193 solo_isolated_led->set_no_show_all (true);
194 solo_isolated_led->set_name (X_("solo isolate"));
195 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
196 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
197 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
199 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
200 solo_safe_led->show ();
201 solo_safe_led->set_no_show_all (true);
202 solo_safe_led->set_name (X_("solo safe"));
203 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
204 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
205 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
207 solo_safe_led->set_text (S_("SoloLock|Lock"));
208 solo_isolated_led->set_text (_("Iso"));
210 solo_iso_table.set_homogeneous (true);
211 solo_iso_table.set_spacings (2);
212 if (!ARDOUR::Profile->get_trx()) {
213 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
214 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
216 solo_iso_table.show ();
218 rec_mon_table.set_homogeneous (true);
219 rec_mon_table.set_row_spacings (2);
220 rec_mon_table.set_col_spacings (2);
221 if (ARDOUR::Profile->get_mixbus()) {
222 rec_mon_table.resize (1, 3);
223 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
224 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
225 } else if (!ARDOUR::Profile->get_trx()) {
226 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
227 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
229 rec_mon_table.show ();
231 if (solo_isolated_led) {
232 button_size_group->add_widget (*solo_isolated_led);
235 button_size_group->add_widget (*solo_safe_led);
238 if (!ARDOUR::Profile->get_mixbus()) {
239 if (rec_enable_button) {
240 button_size_group->add_widget (*rec_enable_button);
242 if (monitor_disk_button) {
243 button_size_group->add_widget (*monitor_disk_button);
245 if (monitor_input_button) {
246 button_size_group->add_widget (*monitor_input_button);
250 mute_solo_table.set_homogeneous (true);
251 mute_solo_table.set_spacings (2);
253 bottom_button_table.set_spacings (2);
254 bottom_button_table.set_homogeneous (true);
255 bottom_button_table.attach (group_button, 1, 2, 0, 1);
256 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
258 name_button.set_name ("mixer strip button");
259 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
260 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
262 set_tooltip (&group_button, _("Mix group"));
263 group_button.set_name ("mixer strip button");
265 _comment_button.set_name (X_("mixer strip button"));
266 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
268 // TODO implement ArdourKnob::on_size_request properly
269 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
270 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
272 trim_control.set_tooltip_prefix (_("Trim: "));
273 trim_control.set_name ("trim knob");
274 trim_control.set_no_show_all (true);
275 input_button_box.pack_start (trim_control, false, false);
277 global_vpacker.set_border_width (1);
278 global_vpacker.set_spacing (0);
280 width_button.set_name ("mixer strip button");
281 hide_button.set_name ("mixer strip button");
283 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
284 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
286 width_hide_box.set_spacing (2);
287 width_hide_box.pack_start (width_button, false, true);
288 width_hide_box.pack_start (number_label, true, true);
289 width_hide_box.pack_end (hide_button, false, true);
291 number_label.set_text ("-");
292 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
293 number_label.set_no_show_all ();
294 number_label.set_name ("tracknumber label");
295 number_label.set_fixed_colors (0x80808080, 0x80808080);
296 number_label.set_alignment (.5, .5);
297 number_label.set_fallthrough_to_parent (true);
299 global_vpacker.set_spacing (2);
300 if (!ARDOUR::Profile->get_trx()) {
301 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
302 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
303 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (processor_box, true, true);
307 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
314 if (!ARDOUR::Profile->get_trx()) {
315 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
318 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
321 global_frame.add (global_vpacker);
322 global_frame.set_shadow_type (Gtk::SHADOW_IN);
323 global_frame.set_name ("BaseFrame");
327 /* force setting of visible selected status */
330 set_selected (false);
335 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
336 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
338 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
339 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
340 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
342 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
343 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
345 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
346 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
347 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
349 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
351 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
352 name_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_release), false);
354 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
358 /* start off as a passthru strip. we'll correct this, if necessary,
359 in update_diskstream_display().
362 /* start off as a passthru strip. we'll correct this, if necessary,
363 in update_diskstream_display().
366 if (is_midi_track()) {
367 set_name ("MidiTrackStripBase");
369 set_name ("AudioTrackStripBase");
372 add_events (Gdk::BUTTON_RELEASE_MASK|
373 Gdk::ENTER_NOTIFY_MASK|
374 Gdk::LEAVE_NOTIFY_MASK|
376 Gdk::KEY_RELEASE_MASK);
378 set_flags (get_flags() | Gtk::CAN_FOCUS);
380 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
381 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
384 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
385 must be the same as those used in RCOptionEditor so that the configuration changes
386 are recognised when they occur.
388 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
389 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
390 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
391 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
392 _visibility.add (&output_button, X_("Output"), _("Output"), false);
393 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
394 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
396 parameter_changed (X_("mixer-element-visibility"));
397 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
398 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
399 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
401 //watch for mouse enter/exit so we can do some stuff
402 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
403 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
405 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
408 MixerStrip::~MixerStrip ()
410 CatchDeletion (this);
412 if (this ==_entered_mixer_strip)
413 _entered_mixer_strip = NULL;
417 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
419 _entered_mixer_strip = this;
421 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
422 //because the mixerstrip control is a parent that encompasses the strip
423 deselect_all_processors();
429 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
431 //if we have moved outside our strip, but not into a child view, then deselect ourselves
432 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
433 _entered_mixer_strip= 0;
435 //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
436 gpm.gain_display.set_sensitive(false);
438 gpm.gain_display.set_sensitive(true);
440 //if we leave this mixer strip we need to clear out any selections
441 //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
448 MixerStrip::name() const
451 return _route->name();
457 MixerStrip::set_route (boost::shared_ptr<Route> rt)
459 //the rec/monitor stuff only shows up for tracks.
460 //the show_sends only shows up for buses.
461 //remove them all here, and we may add them back later
462 if (show_sends_button->get_parent()) {
463 rec_mon_table.remove (*show_sends_button);
465 if (rec_enable_button->get_parent()) {
466 rec_mon_table.remove (*rec_enable_button);
468 if (monitor_input_button->get_parent()) {
469 rec_mon_table.remove (*monitor_input_button);
471 if (monitor_disk_button->get_parent()) {
472 rec_mon_table.remove (*monitor_disk_button);
474 if (group_button.get_parent()) {
475 bottom_button_table.remove (group_button);
478 RouteUI::set_route (rt);
480 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
482 /* ProcessorBox needs access to _route so that it can read
485 processor_box.set_route (rt);
487 revert_to_default_display ();
489 /* unpack these from the parent and stuff them into our own
493 if (gpm.peak_display.get_parent()) {
494 gpm.peak_display.get_parent()->remove (gpm.peak_display);
496 if (gpm.gain_display.get_parent()) {
497 gpm.gain_display.get_parent()->remove (gpm.gain_display);
500 gpm.set_type (rt->meter_type());
502 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
503 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
505 if (solo_button->get_parent()) {
506 mute_solo_table.remove (*solo_button);
509 if (mute_button->get_parent()) {
510 mute_solo_table.remove (*mute_button);
513 if (route()->is_master()) {
514 solo_button->hide ();
515 mute_button->show ();
516 rec_mon_table.hide ();
517 if (solo_iso_table.get_parent()) {
518 solo_iso_table.get_parent()->remove(solo_iso_table);
520 if (monitor_section_button == 0) {
521 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
522 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
524 monitor_section_button = manage (new ArdourButton);
526 monitor_section_button->set_related_action (act);
527 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
528 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
529 monitor_section_button->show();
530 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
532 parameter_changed ("use-monitor-bus");
534 bottom_button_table.attach (group_button, 1, 2, 0, 1);
535 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
536 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
537 mute_button->show ();
538 solo_button->show ();
539 rec_mon_table.show ();
542 if (_mixer_owned && route()->is_master() ) {
544 HScrollbar scrollbar;
545 Gtk::Requisition requisition(scrollbar.size_request ());
546 int scrollbar_height = requisition.height;
548 spacer = manage (new EventBox);
549 spacer->set_size_request (-1, scrollbar_height+2);
550 global_vpacker.pack_start (*spacer, false, false);
555 monitor_input_button->show ();
556 monitor_disk_button->show ();
558 monitor_input_button->hide();
559 monitor_disk_button->hide ();
562 if (route()->trim() && route()->trim()->active()) {
563 trim_control.show ();
564 trim_control.set_controllable (route()->trim()->gain_control());
566 trim_control.hide ();
567 boost::shared_ptr<Controllable> none;
568 trim_control.set_controllable (none);
571 if (is_midi_track()) {
572 if (midi_input_enable_button == 0) {
573 midi_input_enable_button = manage (new ArdourButton);
574 midi_input_enable_button->set_name ("midi input button");
575 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
576 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
577 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
578 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
579 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
581 input_button_box.remove (*midi_input_enable_button);
583 /* get current state */
584 midi_input_status_changed ();
585 input_button_box.pack_start (*midi_input_enable_button, false, false);
587 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
589 if (midi_input_enable_button) {
590 /* removal from the container will delete it */
591 input_button_box.remove (*midi_input_enable_button);
592 midi_input_enable_button = 0;
596 if (is_audio_track()) {
597 boost::shared_ptr<AudioTrack> at = audio_track();
598 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
603 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
604 rec_enable_button->show();
606 if (ARDOUR::Profile->get_mixbus()) {
607 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
608 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
609 } else if (ARDOUR::Profile->get_trx()) {
610 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
612 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
613 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
620 if (!_route->is_master()) {
621 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
622 show_sends_button->show();
626 meter_point_button.set_text (meter_point_string (_route->meter_point()));
628 delete route_ops_menu;
631 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
632 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
633 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
634 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
636 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
638 if (_route->panner_shell()) {
639 update_panner_choices();
640 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
643 if (is_audio_track()) {
644 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
647 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
649 set_stuff_from_route ();
651 /* now force an update of all the various elements */
653 update_mute_display ();
654 update_solo_display ();
657 route_group_changed ();
658 update_track_number_visibility ();
661 panners.setup_pan ();
663 if (has_audio_outputs ()) {
669 update_diskstream_display ();
670 update_input_display ();
671 update_output_display ();
673 add_events (Gdk::BUTTON_RELEASE_MASK);
675 processor_box.show ();
677 if (!route()->is_master() && !route()->is_monitor()) {
678 /* we don't allow master or control routes to be hidden */
683 gpm.reset_peak_display ();
684 gpm.gain_display.show ();
685 gpm.peak_display.show ();
688 width_hide_box.show();
690 global_vpacker.show();
691 mute_solo_table.show();
692 bottom_button_table.show();
694 meter_point_button.show();
695 input_button_box.show_all();
696 output_button.show();
698 _comment_button.show();
700 gpm.gain_automation_state_button.show();
702 parameter_changed ("mixer-element-visibility");
709 MixerStrip::set_stuff_from_route ()
711 /* if width is not set, it will be set by the MixerUI or editor */
713 string str = gui_property ("strip-width");
715 set_width_enum (Width (string_2_enum (str, _width)), this);
720 MixerStrip::set_width_enum (Width w, void* owner)
722 /* always set the gpm width again, things may be hidden */
725 panners.set_width (w);
727 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
729 _width_owner = owner;
733 if (_width_owner == this) {
734 set_gui_property ("strip-width", enum_2_string (_width));
739 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
744 if (show_sends_button) {
745 show_sends_button->set_text (_("Aux"));
748 gpm.gain_automation_style_button.set_text (
749 gpm.astyle_string(gain_automation->automation_style()));
750 gpm.gain_automation_state_button.set_text (
751 gpm.astate_string(gain_automation->automation_state()));
753 if (_route->panner()) {
754 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
755 panners.astyle_string(_route->panner()->automation_style()));
756 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
757 panners.astate_string(_route->panner()->automation_state()));
761 // panners expect an even number of horiz. pixels
762 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
764 set_size_request (width, -1);
770 if (show_sends_button) {
771 show_sends_button->set_text (_("Snd"));
774 gpm.gain_automation_style_button.set_text (
775 gpm.short_astyle_string(gain_automation->automation_style()));
776 gpm.gain_automation_state_button.set_text (
777 gpm.short_astate_string(gain_automation->automation_state()));
778 gain_meter().setup_meters (); // recalc meter width
780 if (_route->panner()) {
781 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
782 panners.short_astyle_string(_route->panner()->automation_style()));
783 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
784 panners.short_astate_string(_route->panner()->automation_state()));
788 // panners expect an even number of horiz. pixels
789 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
791 set_size_request (width, -1);
796 processor_box.set_width (w);
798 update_input_display ();
799 update_output_display ();
800 setup_comment_button ();
801 route_group_changed ();
807 MixerStrip::set_packed (bool yn)
812 set_gui_property ("visible", true);
814 set_gui_property ("visible", false);
819 struct RouteCompareByName {
820 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
821 return a->name().compare (b->name()) < 0;
826 MixerStrip::output_release (GdkEventButton *ev)
828 switch (ev->button) {
830 edit_output_configuration ();
838 MixerStrip::output_press (GdkEventButton *ev)
840 using namespace Menu_Helpers;
841 if (!_session->engine().connected()) {
842 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
847 MenuList& citems = output_menu.items();
848 switch (ev->button) {
851 return false; //wait for the mouse-up to pop the dialog
855 output_menu.set_name ("ArdourContextMenu");
857 output_menu_bundles.clear ();
859 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
861 citems.push_back (SeparatorElem());
862 uint32_t const n_with_separator = citems.size ();
864 ARDOUR::BundleList current = _route->output()->bundles_connected ();
866 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
868 /* give user bundles first chance at being in the menu */
870 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
871 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
872 maybe_add_bundle_to_output_menu (*i, current);
876 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
877 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
878 maybe_add_bundle_to_output_menu (*i, current);
882 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
883 RouteList copy = *routes;
884 copy.sort (RouteCompareByName ());
885 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
886 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
889 if (citems.size() == n_with_separator) {
890 /* no routes added; remove the separator */
894 if (!ARDOUR::Profile->get_mixbus()) {
895 citems.push_back (SeparatorElem());
897 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
900 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
901 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
907 citems.push_back (SeparatorElem());
908 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
910 output_menu.popup (1, ev->time);
921 MixerStrip::input_release (GdkEventButton *ev)
923 switch (ev->button) {
926 edit_input_configuration ();
938 MixerStrip::input_press (GdkEventButton *ev)
940 using namespace Menu_Helpers;
942 MenuList& citems = input_menu.items();
943 input_menu.set_name ("ArdourContextMenu");
946 if (!_session->engine().connected()) {
947 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
952 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
955 switch (ev->button) {
958 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
962 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
964 citems.push_back (SeparatorElem());
965 uint32_t const n_with_separator = citems.size ();
967 input_menu_bundles.clear ();
969 ARDOUR::BundleList current = _route->input()->bundles_connected ();
971 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
973 /* give user bundles first chance at being in the menu */
975 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
976 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
977 maybe_add_bundle_to_input_menu (*i, current);
981 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
982 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
983 maybe_add_bundle_to_input_menu (*i, current);
987 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
988 RouteList copy = *routes;
989 copy.sort (RouteCompareByName ());
990 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
991 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
994 if (citems.size() == n_with_separator) {
995 /* no routes added; remove the separator */
999 citems.push_back (SeparatorElem());
1000 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1003 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1004 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1009 citems.push_back (SeparatorElem());
1010 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1012 input_menu.popup (1, ev->time);
1023 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1025 if (ignore_toggle) {
1029 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1031 if (std::find (current.begin(), current.end(), c) == current.end()) {
1032 _route->input()->connect_ports_to_bundle (c, true, this);
1034 _route->input()->disconnect_ports_from_bundle (c, this);
1039 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1041 if (ignore_toggle) {
1045 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1047 if (std::find (current.begin(), current.end(), c) == current.end()) {
1048 _route->output()->connect_ports_to_bundle (c, true, this);
1050 _route->output()->disconnect_ports_from_bundle (c, this);
1055 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1057 using namespace Menu_Helpers;
1059 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1063 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1064 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1068 if (i != input_menu_bundles.end()) {
1072 input_menu_bundles.push_back (b);
1074 MenuList& citems = input_menu.items();
1076 std::string n = b->name ();
1077 replace_all (n, "_", " ");
1079 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1083 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1085 using namespace Menu_Helpers;
1087 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1091 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1092 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1096 if (i != output_menu_bundles.end()) {
1100 output_menu_bundles.push_back (b);
1102 MenuList& citems = output_menu.items();
1104 std::string n = b->name ();
1105 replace_all (n, "_", " ");
1107 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1111 MixerStrip::update_diskstream_display ()
1113 if (is_track() && input_selector) {
1114 input_selector->hide_all ();
1117 route_color_changed ();
1121 MixerStrip::connect_to_pan ()
1123 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1125 panstate_connection.disconnect ();
1126 panstyle_connection.disconnect ();
1128 if (!_route->panner()) {
1132 boost::shared_ptr<Pannable> p = _route->pannable ();
1134 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1135 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1137 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1138 * However, that only works a panner was previously set.
1140 * PannerUI must remain subscribed to _panshell->Changed() in case
1141 * we switch the panner eg. AUX-Send and back
1142 * _route->panner_shell()->Changed() vs _panshell->Changed
1144 if (panners._panner == 0) {
1145 panners.panshell_changed ();
1147 update_panner_choices();
1151 MixerStrip::update_panner_choices ()
1153 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1154 if (!_route->panner_shell()) { return; }
1156 uint32_t in = _route->output()->n_ports().n_audio();
1158 if (_route->panner()) {
1159 in = _route->panner()->in().n_audio();
1162 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1166 * Output port labelling
1167 * =====================
1169 * Case 1: Each output has one connection, all connections are to system:playback_%i
1170 * out 1 -> system:playback_1
1171 * out 2 -> system:playback_2
1172 * out 3 -> system:playback_3
1175 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1176 * out 1 -> ardour:track_x/in 1
1177 * out 2 -> ardour:track_x/in 2
1178 * Display as: track_x
1180 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1181 * out 1 -> program x:foo
1182 * out 2 -> program x:foo
1183 * Display as: program x
1185 * Case 4: No connections (Disconnected)
1188 * Default case (unusual routing):
1189 * Display as: *number of connections*
1193 * .-----------------------------------------------.
1195 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1196 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1197 * '-----------------------------------------------'
1198 * .-----------------------------------------------.
1201 * '-----------------------------------------------'
1205 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1209 boost::shared_ptr<Port> port;
1210 vector<string> port_connections;
1212 uint32_t total_connection_count = 0;
1213 uint32_t io_connection_count = 0;
1214 uint32_t ardour_connection_count = 0;
1215 uint32_t system_connection_count = 0;
1216 uint32_t other_connection_count = 0;
1217 uint32_t typed_connection_count = 0;
1219 ostringstream label;
1221 bool have_label = false;
1222 bool each_io_has_one_connection = true;
1224 string connection_name;
1225 string ardour_track_name;
1226 string other_connection_type;
1227 string system_ports;
1230 ostringstream tooltip;
1231 char * tooltip_cstr;
1233 //to avoid confusion, the button caption should only show connections that match the datatype of the track
1234 DataType dt = DataType::AUDIO;
1235 if ( boost::dynamic_pointer_cast<MidiTrack>(route) != 0 ) {
1236 dt = DataType::MIDI;
1237 // avoid further confusion with Midi-tracks that have a synth.
1238 // Audio-ports may be connected, but button says "Disconnected"
1239 tooltip << _("MIDI ");
1243 io_count = route->n_inputs().n_total();
1244 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1246 io_count = route->n_outputs().n_total();
1247 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1251 for (io_index = 0; io_index < io_count; ++io_index) {
1253 port = route->input()->nth (io_index);
1255 port = route->output()->nth (io_index);
1258 port_connections.clear ();
1259 port->get_connections(port_connections);
1261 //ignore any port connections that don't match our DataType
1262 if (port->type() != dt) {
1263 if (!port_connections.empty()) {
1264 ++typed_connection_count;
1269 io_connection_count = 0;
1271 if (!port_connections.empty()) {
1272 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1274 string& connection_name (*i);
1276 if (connection_name.find("system:") == 0) {
1277 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1280 if (io_connection_count == 0) {
1281 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1283 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1286 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1289 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1290 if (ardour_track_name.empty()) {
1291 // "ardour:Master/in 1" -> "ardour:Master/"
1292 string::size_type slash = connection_name.find("/");
1293 if (slash != string::npos) {
1294 ardour_track_name = connection_name.substr(0, slash + 1);
1298 if (connection_name.find(ardour_track_name) == 0) {
1299 ++ardour_connection_count;
1301 } else if (!pn.empty()) {
1302 if (system_ports.empty()) {
1305 system_ports += "/" + pn;
1307 if (connection_name.find("system:") == 0) {
1308 ++system_connection_count;
1310 } else if (connection_name.find("system:midi_") == 0) {
1312 // "system:midi_capture_123" -> "123"
1313 system_port = "M " + connection_name.substr(20);
1315 // "system:midi_playback_123" -> "123"
1316 system_port = "M " + connection_name.substr(21);
1319 if (system_ports.empty()) {
1320 system_ports += system_port;
1322 system_ports += "/" + system_port;
1325 ++system_connection_count;
1327 } else if (connection_name.find("system:") == 0) {
1329 // "system:capture_123" -> "123"
1330 system_port = connection_name.substr(15);
1332 // "system:playback_123" -> "123"
1333 system_port = connection_name.substr(16);
1336 if (system_ports.empty()) {
1337 system_ports += system_port;
1339 system_ports += "/" + system_port;
1342 ++system_connection_count;
1344 if (other_connection_type.empty()) {
1345 // "jamin:in 1" -> "jamin:"
1346 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1349 if (connection_name.find(other_connection_type) == 0) {
1350 ++other_connection_count;
1354 ++total_connection_count;
1355 ++io_connection_count;
1359 if (io_connection_count != 1) {
1360 each_io_has_one_connection = false;
1364 if (total_connection_count == 0) {
1365 tooltip << endl << _("Disconnected");
1368 tooltip_cstr = new char[tooltip.str().size() + 1];
1369 strcpy(tooltip_cstr, tooltip.str().c_str());
1372 set_tooltip (&input_button, tooltip_cstr);
1374 set_tooltip (&output_button, tooltip_cstr);
1377 delete [] tooltip_cstr;
1379 if (each_io_has_one_connection) {
1380 if (total_connection_count == ardour_connection_count) {
1381 // all connections are to the same track in ardour
1382 // "ardour:Master/" -> "Master"
1383 string::size_type slash = ardour_track_name.find("/");
1384 if (slash != string::npos) {
1385 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1386 label << ardour_track_name.substr (ppps, slash - ppps);
1390 else if (total_connection_count == system_connection_count) {
1391 // all connections are to system ports
1392 label << system_ports;
1395 else if (total_connection_count == other_connection_count) {
1396 // all connections are to the same external program eg jamin
1397 // "jamin:" -> "jamin"
1398 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1404 if (total_connection_count == 0) {
1408 // Odd configuration
1409 label << "*" << total_connection_count << "*";
1411 if (typed_connection_count > 0) {
1412 label << "\u2295"; // circled plus
1417 input_button.set_text (label.str());
1419 output_button.set_text (label.str());
1424 MixerStrip::update_input_display ()
1426 update_io_button (_route, _width, true);
1427 panners.setup_pan ();
1429 if (has_audio_outputs ()) {
1430 panners.show_all ();
1432 panners.hide_all ();
1438 MixerStrip::update_output_display ()
1440 update_io_button (_route, _width, false);
1441 gpm.setup_meters ();
1442 panners.setup_pan ();
1444 if (has_audio_outputs ()) {
1445 panners.show_all ();
1447 panners.hide_all ();
1452 MixerStrip::fast_update ()
1454 gpm.update_meters ();
1458 MixerStrip::diskstream_changed ()
1460 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1464 MixerStrip::io_changed_proxy ()
1466 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1470 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1472 boost::shared_ptr<Port> a = wa.lock ();
1473 boost::shared_ptr<Port> b = wb.lock ();
1475 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1476 update_input_display ();
1477 set_width_enum (_width, this);
1480 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1481 update_output_display ();
1482 set_width_enum (_width, this);
1487 MixerStrip::setup_comment_button ()
1492 if (_route->comment().empty ()) {
1493 _comment_button.unset_bg (STATE_NORMAL);
1494 _comment_button.set_text (_("Comments"));
1496 _comment_button.modify_bg (STATE_NORMAL, color ());
1497 _comment_button.set_text (_("*Comments*"));
1502 if (_route->comment().empty ()) {
1503 _comment_button.unset_bg (STATE_NORMAL);
1504 _comment_button.set_text (_("Cmt"));
1506 _comment_button.modify_bg (STATE_NORMAL, color ());
1507 _comment_button.set_text (_("*Cmt*"));
1513 _comment_button, _route->comment().empty() ? _("Click to add/edit comments") : _route->comment()
1519 MixerStrip::select_route_group (GdkEventButton *ev)
1521 using namespace Menu_Helpers;
1523 if (ev->button == 1) {
1525 if (group_menu == 0) {
1527 PropertyList* plist = new PropertyList();
1529 plist->add (Properties::group_gain, true);
1530 plist->add (Properties::group_mute, true);
1531 plist->add (Properties::group_solo, true);
1533 group_menu = new RouteGroupMenu (_session, plist);
1537 r.push_back (route ());
1538 group_menu->build (r);
1539 group_menu->menu()->popup (1, ev->time);
1546 MixerStrip::route_group_changed ()
1548 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1550 RouteGroup *rg = _route->route_group();
1553 group_button.set_text (PBD::short_version (rg->name(), 5));
1557 group_button.set_text (_("Grp"));
1560 group_button.set_text (_("~G"));
1567 MixerStrip::route_color_changed ()
1569 name_button.modify_bg (STATE_NORMAL, color());
1570 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1571 reset_strip_style ();
1575 MixerStrip::show_passthru_color ()
1577 reset_strip_style ();
1582 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1584 boost::shared_ptr<Processor> processor (p.lock ());
1585 if (!processor || !processor->display_to_user()) {
1588 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1589 ++_plugin_insert_cnt;
1593 MixerStrip::build_route_ops_menu ()
1595 using namespace Menu_Helpers;
1596 route_ops_menu = new Menu;
1597 route_ops_menu->set_name ("ArdourContextMenu");
1599 MenuList& items = route_ops_menu->items();
1601 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1603 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1605 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1607 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1609 items.push_back (SeparatorElem());
1611 if (!_route->is_master()) {
1612 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1614 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1615 rename_menu_item = &items.back();
1617 items.push_back (SeparatorElem());
1618 items.push_back (CheckMenuElem (_("Active")));
1619 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1620 i->set_active (_route->active());
1621 i->set_sensitive(! _session->transport_rolling());
1622 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1624 if (!Profile->get_mixbus ()) {
1625 items.push_back (SeparatorElem());
1626 items.push_back (CheckMenuElem (_("Strict I/O")));
1627 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1628 i->set_active (_route->strict_io());
1629 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1632 _plugin_insert_cnt = 0;
1633 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1634 if (_plugin_insert_cnt > 0) {
1635 items.push_back (SeparatorElem());
1636 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1639 items.push_back (SeparatorElem());
1640 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1642 items.push_back (SeparatorElem());
1643 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1644 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1645 denormal_menu_item->set_active (_route->denormal_protection());
1648 /* note that this relies on selection being shared across editor and
1649 mixer (or global to the backend, in the future), which is the only
1650 sane thing for users anyway.
1653 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1655 Selection& selection (PublicEditor::instance().get_selection());
1656 if (!selection.selected (rtav)) {
1657 selection.set (rtav);
1660 if (!_route->is_master()) {
1661 items.push_back (SeparatorElem());
1662 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1665 items.push_back (SeparatorElem());
1666 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1672 MixerStrip::name_button_button_press (GdkEventButton* ev)
1674 if (ev->button == 3) {
1675 list_route_operations ();
1677 /* do not allow rename if the track is record-enabled */
1678 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1679 route_ops_menu->popup (1, ev->time);
1688 MixerStrip::name_button_button_release (GdkEventButton* ev)
1690 if (ev->button == 1) {
1691 list_route_operations ();
1693 /* do not allow rename if the track is record-enabled */
1694 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1695 route_ops_menu->popup (1, ev->time);
1702 MixerStrip::number_button_button_press (GdkEventButton* ev)
1704 if ( ev->button == 3 ) {
1705 list_route_operations ();
1707 /* do not allow rename if the track is record-enabled */
1708 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1709 route_ops_menu->popup (1, ev->time);
1718 MixerStrip::list_route_operations ()
1720 delete route_ops_menu;
1721 build_route_ops_menu ();
1725 MixerStrip::show_selected ()
1728 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1729 global_frame.set_name ("MixerStripSelectedFrame");
1731 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1732 global_frame.set_name ("MixerStripFrame");
1735 global_frame.queue_draw ();
1738 // processor_box.deselect_all_processors();
1742 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1744 if (what_changed.contains (ARDOUR::Properties::name)) {
1750 MixerStrip::name_changed ()
1754 name_button.set_text (_route->name());
1757 name_button.set_text (PBD::short_version (_route->name(), 5));
1761 set_tooltip (name_button, _route->name());
1763 if (_session->config.get_track_name_number()) {
1764 const int64_t track_number = _route->track_number ();
1765 if (track_number == 0) {
1766 number_label.set_text ("-");
1768 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1771 number_label.set_text ("");
1776 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1778 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1782 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1784 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1788 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1790 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1794 MixerStrip::width_button_pressed (GdkEventButton* ev)
1796 if (ev->button != 1) {
1800 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1803 _mixer.set_strip_width (Narrow, true);
1807 _mixer.set_strip_width (Wide, true);
1813 set_width_enum (Narrow, this);
1816 set_width_enum (Wide, this);
1825 MixerStrip::hide_clicked ()
1827 // LAME fix to reset the button status for when it is redisplayed (part 1)
1828 hide_button.set_sensitive(false);
1831 Hiding(); /* EMIT_SIGNAL */
1833 _mixer.hide_strip (this);
1837 hide_button.set_sensitive(true);
1841 MixerStrip::set_embedded (bool yn)
1847 MixerStrip::map_frozen ()
1849 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1851 boost::shared_ptr<AudioTrack> at = audio_track();
1854 switch (at->freeze_state()) {
1855 case AudioTrack::Frozen:
1856 processor_box.set_sensitive (false);
1857 hide_redirect_editors ();
1860 processor_box.set_sensitive (true);
1861 // XXX need some way, maybe, to retoggle redirect editors
1865 processor_box.set_sensitive (true);
1867 RouteUI::map_frozen ();
1871 MixerStrip::hide_redirect_editors ()
1873 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1877 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1879 boost::shared_ptr<Processor> processor (p.lock ());
1884 Gtk::Window* w = processor_box.get_processor_ui (processor);
1892 MixerStrip::reset_strip_style ()
1894 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1896 gpm.set_fader_name ("SendStripBase");
1900 if (is_midi_track()) {
1901 if (_route->active()) {
1902 set_name ("MidiTrackStripBase");
1904 set_name ("MidiTrackStripBaseInactive");
1906 gpm.set_fader_name ("MidiTrackFader");
1907 } else if (is_audio_track()) {
1908 if (_route->active()) {
1909 set_name ("AudioTrackStripBase");
1911 set_name ("AudioTrackStripBaseInactive");
1913 gpm.set_fader_name ("AudioTrackFader");
1915 if (_route->active()) {
1916 set_name ("AudioBusStripBase");
1918 set_name ("AudioBusStripBaseInactive");
1920 gpm.set_fader_name ("AudioBusFader");
1922 /* (no MIDI busses yet) */
1929 MixerStrip::engine_stopped ()
1934 MixerStrip::engine_running ()
1939 MixerStrip::meter_point_string (MeterPoint mp)
1952 case MeterPostFader:
1969 return S_("Meter|In");
1973 return S_("Meter|Pr");
1976 case MeterPostFader:
1977 return S_("Meter|Po");
1981 return S_("Meter|O");
1986 return S_("Meter|C");
1995 /** Called when the monitor-section state */
1997 MixerStrip::monitor_changed ()
1999 assert (monitor_section_button);
2000 if (_session->monitor_active()) {
2001 monitor_section_button->set_name ("master monitor section button active");
2003 monitor_section_button->set_name ("master monitor section button normal");
2007 /** Called when the metering point has changed */
2009 MixerStrip::meter_changed ()
2011 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2012 gpm.setup_meters ();
2013 // reset peak when meter point changes
2014 gpm.reset_peak_display();
2017 /** The bus that we are displaying sends to has changed, or been turned off.
2018 * @param send_to New bus that we are displaying sends to, or 0.
2021 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2023 RouteUI::bus_send_display_changed (send_to);
2026 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2031 revert_to_default_display ();
2034 revert_to_default_display ();
2039 MixerStrip::drop_send ()
2041 boost::shared_ptr<Send> current_send;
2043 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2044 current_send->set_metering (false);
2047 send_gone_connection.disconnect ();
2048 input_button.set_sensitive (true);
2049 output_button.set_sensitive (true);
2050 group_button.set_sensitive (true);
2051 set_invert_sensitive (true);
2052 meter_point_button.set_sensitive (true);
2053 mute_button->set_sensitive (true);
2054 solo_button->set_sensitive (true);
2055 solo_isolated_led->set_sensitive (true);
2056 solo_safe_led->set_sensitive (true);
2057 monitor_input_button->set_sensitive (true);
2058 monitor_disk_button->set_sensitive (true);
2059 _comment_button.set_sensitive (true);
2060 RouteUI::check_rec_enable_sensitivity ();
2061 set_button_names (); // update solo button visual state
2065 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2067 _current_delivery = d;
2068 DeliveryChanged (_current_delivery);
2072 MixerStrip::show_send (boost::shared_ptr<Send> send)
2078 set_current_delivery (send);
2080 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2081 send->set_metering (true);
2082 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2084 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2085 gain_meter().setup_meters ();
2087 uint32_t const in = _current_delivery->pans_required();
2088 uint32_t const out = _current_delivery->pan_outs();
2090 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2091 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2092 panner_ui().setup_pan ();
2093 panner_ui().set_send_drawing_mode (true);
2094 panner_ui().show_all ();
2096 input_button.set_sensitive (false);
2097 group_button.set_sensitive (false);
2098 set_invert_sensitive (false);
2099 meter_point_button.set_sensitive (false);
2100 mute_button->set_sensitive (false);
2101 solo_button->set_sensitive (false);
2102 rec_enable_button->set_sensitive (false);
2103 solo_isolated_led->set_sensitive (false);
2104 solo_safe_led->set_sensitive (false);
2105 monitor_input_button->set_sensitive (false);
2106 monitor_disk_button->set_sensitive (false);
2107 _comment_button.set_sensitive (false);
2109 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2110 output_button.set_sensitive (false);
2113 reset_strip_style ();
2117 MixerStrip::revert_to_default_display ()
2121 set_current_delivery (_route->main_outs ());
2123 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2124 gain_meter().setup_meters ();
2126 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2127 update_panner_choices();
2128 panner_ui().setup_pan ();
2129 panner_ui().set_send_drawing_mode (false);
2131 if (has_audio_outputs ()) {
2132 panners.show_all ();
2134 panners.hide_all ();
2137 reset_strip_style ();
2141 MixerStrip::set_button_names ()
2145 mute_button->set_text (_("Mute"));
2146 monitor_input_button->set_text (_("In"));
2147 monitor_disk_button->set_text (_("Disk"));
2148 if (monitor_section_button) {
2149 monitor_section_button->set_text (_("Mon"));
2152 if (_route && _route->solo_safe_control()->solo_safe()) {
2153 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2155 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2157 if (!Config->get_solo_control_is_listen_control()) {
2158 solo_button->set_text (_("Solo"));
2160 switch (Config->get_listen_position()) {
2161 case AfterFaderListen:
2162 solo_button->set_text (_("AFL"));
2164 case PreFaderListen:
2165 solo_button->set_text (_("PFL"));
2169 solo_isolated_led->set_text (_("Iso"));
2170 solo_safe_led->set_text (S_("SoloLock|Lock"));
2174 mute_button->set_text (S_("Mute|M"));
2175 monitor_input_button->set_text (S_("MonitorInput|I"));
2176 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2177 if (monitor_section_button) {
2178 monitor_section_button->set_text (S_("Mon|O"));
2181 if (_route && _route->solo_safe_control()->solo_safe()) {
2182 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2184 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2186 if (!Config->get_solo_control_is_listen_control()) {
2187 solo_button->set_text (S_("Solo|S"));
2189 switch (Config->get_listen_position()) {
2190 case AfterFaderListen:
2191 solo_button->set_text (S_("AfterFader|A"));
2193 case PreFaderListen:
2194 solo_button->set_text (S_("Prefader|P"));
2199 solo_isolated_led->set_text (S_("SoloIso|I"));
2200 solo_safe_led->set_text (S_("SoloLock|L"));
2205 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2207 meter_point_button.set_text ("");
2212 MixerStrip::plugin_selector()
2214 return _mixer.plugin_selector();
2218 MixerStrip::hide_things ()
2220 processor_box.hide_things ();
2224 MixerStrip::input_active_button_press (GdkEventButton*)
2226 /* nothing happens on press */
2231 MixerStrip::input_active_button_release (GdkEventButton* ev)
2233 boost::shared_ptr<MidiTrack> mt = midi_track ();
2239 boost::shared_ptr<RouteList> rl (new RouteList);
2241 rl->push_back (route());
2243 _session->set_exclusive_input_active (rl, !mt->input_active(),
2244 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2250 MixerStrip::midi_input_status_changed ()
2252 if (midi_input_enable_button) {
2253 boost::shared_ptr<MidiTrack> mt = midi_track ();
2255 midi_input_enable_button->set_active (mt->input_active ());
2260 MixerStrip::state_id () const
2262 return string_compose ("strip %1", _route->id().to_s());
2266 MixerStrip::parameter_changed (string p)
2268 if (p == _visibility.get_state_name()) {
2269 /* The user has made changes to the mixer strip visibility, so get
2270 our VisibilityGroup to reflect these changes in our widgets.
2272 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2273 } else if (p == "track-name-number") {
2275 } else if (p == "use-monitor-bus") {
2276 if (monitor_section_button) {
2277 if (mute_button->get_parent()) {
2278 mute_button->get_parent()->remove(*mute_button);
2280 if (monitor_section_button->get_parent()) {
2281 monitor_section_button->get_parent()->remove(*monitor_section_button);
2283 if (Config->get_use_monitor_bus ()) {
2284 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2285 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2286 mute_button->show();
2287 monitor_section_button->show();
2289 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2290 mute_button->show();
2293 } else if (p == "track-name-number") {
2294 update_track_number_visibility();
2298 /** Called to decide whether the solo isolate / solo lock button visibility should
2299 * be overridden from that configured by the user. We do this for the master bus.
2301 * @return optional value that is present if visibility state should be overridden.
2303 boost::optional<bool>
2304 MixerStrip::override_solo_visibility () const
2306 if (_route && _route->is_master ()) {
2307 return boost::optional<bool> (false);
2310 return boost::optional<bool> ();
2314 MixerStrip::add_input_port (DataType t)
2316 _route->input()->add_port ("", this, t);
2320 MixerStrip::add_output_port (DataType t)
2322 _route->output()->add_port ("", this, t);
2326 MixerStrip::route_active_changed ()
2328 reset_strip_style ();
2332 MixerStrip::copy_processors ()
2334 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2338 MixerStrip::cut_processors ()
2340 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2344 MixerStrip::paste_processors ()
2346 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2350 MixerStrip::select_all_processors ()
2352 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2356 MixerStrip::deselect_all_processors ()
2358 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2362 MixerStrip::delete_processors ()
2364 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2368 MixerStrip::toggle_processors ()
2370 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2374 MixerStrip::ab_plugins ()
2376 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2380 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2382 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2385 if (ev->button == 3) {
2386 popup_level_meter_menu (ev);
2394 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2396 using namespace Gtk::Menu_Helpers;
2398 Gtk::Menu* m = manage (new Menu);
2399 MenuList& items = m->items ();
2401 RadioMenuItem::Group group;
2403 _suspend_menu_callbacks = true;
2404 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2405 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2406 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2407 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2408 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2410 if (gpm.meter_channels().n_audio() == 0) {
2411 m->popup (ev->button, ev->time);
2412 _suspend_menu_callbacks = false;
2416 RadioMenuItem::Group tgroup;
2417 items.push_back (SeparatorElem());
2419 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2420 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2421 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2422 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2423 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2424 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2425 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2426 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2427 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2428 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2429 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2432 if (_route->is_master()) {
2435 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2436 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2437 /* non-master bus */
2440 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2447 MeterType cmt = _route->meter_type();
2448 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2450 items.push_back (SeparatorElem());
2451 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2452 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2453 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2454 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2455 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2456 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2458 m->popup (ev->button, ev->time);
2459 _suspend_menu_callbacks = false;
2463 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2464 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2466 using namespace Menu_Helpers;
2468 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2469 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2470 i->set_active (_route->meter_point() == point);
2474 MixerStrip::set_meter_point (MeterPoint p)
2476 if (_suspend_menu_callbacks) return;
2477 _route->set_meter_point (p);
2481 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2482 RadioMenuItem::Group& group, string const & name, MeterType type)
2484 using namespace Menu_Helpers;
2486 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2487 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2488 i->set_active (_route->meter_type() == type);
2492 MixerStrip::set_meter_type (MeterType t)
2494 if (_suspend_menu_callbacks) return;
2499 MixerStrip::update_track_number_visibility ()
2501 DisplaySuspender ds;
2502 bool show_label = _session->config.get_track_name_number();
2504 if (_route && _route->is_master()) {
2509 number_label.show ();
2510 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2511 // except the width of the number label is subtracted from the name-hbox, so we
2512 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2513 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2515 number_label.set_size_request(tnw, -1);
2516 number_label.show ();
2518 number_label.hide ();
2523 MixerStrip::color () const
2525 return route_color ();
2529 MixerStrip::marked_for_display () const
2531 return !_route->presentation_info().hidden();
2535 MixerStrip::set_marked_for_display (bool yn)
2537 return RouteUI::mark_hidden (!yn);