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);
298 number_label.set_tweaks (ArdourButton::OccasionalText);
300 global_vpacker.set_spacing (2);
301 if (!ARDOUR::Profile->get_trx()) {
302 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
303 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (processor_box, true, true);
308 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
315 if (!ARDOUR::Profile->get_trx()) {
316 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
322 global_frame.add (global_vpacker);
323 global_frame.set_shadow_type (Gtk::SHADOW_IN);
324 global_frame.set_name ("BaseFrame");
328 /* force setting of visible selected status */
331 set_selected (false);
336 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
337 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
339 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
340 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
341 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
343 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
344 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
346 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
347 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
348 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
350 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
352 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
353 name_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_release), false);
355 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
359 /* start off as a passthru strip. we'll correct this, if necessary,
360 in update_diskstream_display().
363 /* start off as a passthru strip. we'll correct this, if necessary,
364 in update_diskstream_display().
367 if (is_midi_track()) {
368 set_name ("MidiTrackStripBase");
370 set_name ("AudioTrackStripBase");
373 add_events (Gdk::BUTTON_RELEASE_MASK|
374 Gdk::ENTER_NOTIFY_MASK|
375 Gdk::LEAVE_NOTIFY_MASK|
377 Gdk::KEY_RELEASE_MASK);
379 set_flags (get_flags() | Gtk::CAN_FOCUS);
381 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
382 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
385 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
386 must be the same as those used in RCOptionEditor so that the configuration changes
387 are recognised when they occur.
389 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
390 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
391 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
392 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
393 _visibility.add (&output_button, X_("Output"), _("Output"), false);
394 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
395 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
397 parameter_changed (X_("mixer-element-visibility"));
398 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
399 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
400 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
402 //watch for mouse enter/exit so we can do some stuff
403 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
404 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
406 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
409 MixerStrip::~MixerStrip ()
411 CatchDeletion (this);
413 if (this ==_entered_mixer_strip)
414 _entered_mixer_strip = NULL;
418 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
420 _entered_mixer_strip = this;
422 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
423 //because the mixerstrip control is a parent that encompasses the strip
424 deselect_all_processors();
430 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
432 //if we have moved outside our strip, but not into a child view, then deselect ourselves
433 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
434 _entered_mixer_strip= 0;
436 //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
437 gpm.gain_display.set_sensitive(false);
439 gpm.gain_display.set_sensitive(true);
441 //if we leave this mixer strip we need to clear out any selections
442 //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
449 MixerStrip::name() const
452 return _route->name();
458 MixerStrip::set_route (boost::shared_ptr<Route> rt)
460 //the rec/monitor stuff only shows up for tracks.
461 //the show_sends only shows up for buses.
462 //remove them all here, and we may add them back later
463 if (show_sends_button->get_parent()) {
464 rec_mon_table.remove (*show_sends_button);
466 if (rec_enable_button->get_parent()) {
467 rec_mon_table.remove (*rec_enable_button);
469 if (monitor_input_button->get_parent()) {
470 rec_mon_table.remove (*monitor_input_button);
472 if (monitor_disk_button->get_parent()) {
473 rec_mon_table.remove (*monitor_disk_button);
475 if (group_button.get_parent()) {
476 bottom_button_table.remove (group_button);
479 RouteUI::set_route (rt);
481 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
483 /* ProcessorBox needs access to _route so that it can read
486 processor_box.set_route (rt);
488 revert_to_default_display ();
490 /* unpack these from the parent and stuff them into our own
494 if (gpm.peak_display.get_parent()) {
495 gpm.peak_display.get_parent()->remove (gpm.peak_display);
497 if (gpm.gain_display.get_parent()) {
498 gpm.gain_display.get_parent()->remove (gpm.gain_display);
501 gpm.set_type (rt->meter_type());
503 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
504 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
506 if (solo_button->get_parent()) {
507 mute_solo_table.remove (*solo_button);
510 if (mute_button->get_parent()) {
511 mute_solo_table.remove (*mute_button);
514 if (route()->is_master()) {
515 solo_button->hide ();
516 mute_button->show ();
517 rec_mon_table.hide ();
518 if (solo_iso_table.get_parent()) {
519 solo_iso_table.get_parent()->remove(solo_iso_table);
521 if (monitor_section_button == 0) {
522 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
523 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
525 monitor_section_button = manage (new ArdourButton);
527 monitor_section_button->set_related_action (act);
528 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
529 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
530 monitor_section_button->show();
531 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
533 parameter_changed ("use-monitor-bus");
535 bottom_button_table.attach (group_button, 1, 2, 0, 1);
536 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
537 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
538 mute_button->show ();
539 solo_button->show ();
540 rec_mon_table.show ();
543 if (_mixer_owned && route()->is_master() ) {
545 HScrollbar scrollbar;
546 Gtk::Requisition requisition(scrollbar.size_request ());
547 int scrollbar_height = requisition.height;
549 spacer = manage (new EventBox);
550 spacer->set_size_request (-1, scrollbar_height+2);
551 global_vpacker.pack_start (*spacer, false, false);
556 monitor_input_button->show ();
557 monitor_disk_button->show ();
559 monitor_input_button->hide();
560 monitor_disk_button->hide ();
563 if (route()->trim() && route()->trim()->active()) {
564 trim_control.show ();
565 trim_control.set_controllable (route()->trim()->gain_control());
567 trim_control.hide ();
568 boost::shared_ptr<Controllable> none;
569 trim_control.set_controllable (none);
572 if (is_midi_track()) {
573 if (midi_input_enable_button == 0) {
574 midi_input_enable_button = manage (new ArdourButton);
575 midi_input_enable_button->set_name ("midi input button");
576 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
577 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
578 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
579 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
580 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
582 input_button_box.remove (*midi_input_enable_button);
584 /* get current state */
585 midi_input_status_changed ();
586 input_button_box.pack_start (*midi_input_enable_button, false, false);
588 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
590 if (midi_input_enable_button) {
591 /* removal from the container will delete it */
592 input_button_box.remove (*midi_input_enable_button);
593 midi_input_enable_button = 0;
597 if (is_audio_track()) {
598 boost::shared_ptr<AudioTrack> at = audio_track();
599 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
604 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
605 rec_enable_button->show();
607 if (ARDOUR::Profile->get_mixbus()) {
608 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
609 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
610 } else if (ARDOUR::Profile->get_trx()) {
611 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
613 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
614 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
621 if (!_route->is_master()) {
622 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
623 show_sends_button->show();
627 meter_point_button.set_text (meter_point_string (_route->meter_point()));
629 delete route_ops_menu;
632 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
633 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
634 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
635 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
637 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
639 if (_route->panner_shell()) {
640 update_panner_choices();
641 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
644 if (is_audio_track()) {
645 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
648 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
650 set_stuff_from_route ();
652 /* now force an update of all the various elements */
654 update_mute_display ();
655 update_solo_display ();
658 route_group_changed ();
659 update_track_number_visibility ();
662 panners.setup_pan ();
664 if (has_audio_outputs ()) {
670 update_diskstream_display ();
671 update_input_display ();
672 update_output_display ();
674 add_events (Gdk::BUTTON_RELEASE_MASK);
676 processor_box.show ();
678 if (!route()->is_master() && !route()->is_monitor()) {
679 /* we don't allow master or control routes to be hidden */
684 gpm.reset_peak_display ();
685 gpm.gain_display.show ();
686 gpm.peak_display.show ();
689 width_hide_box.show();
691 global_vpacker.show();
692 mute_solo_table.show();
693 bottom_button_table.show();
695 meter_point_button.show();
696 input_button_box.show_all();
697 output_button.show();
699 _comment_button.show();
701 gpm.gain_automation_state_button.show();
703 parameter_changed ("mixer-element-visibility");
710 MixerStrip::set_stuff_from_route ()
712 /* if width is not set, it will be set by the MixerUI or editor */
714 string str = gui_property ("strip-width");
716 set_width_enum (Width (string_2_enum (str, _width)), this);
721 MixerStrip::set_width_enum (Width w, void* owner)
723 /* always set the gpm width again, things may be hidden */
726 panners.set_width (w);
728 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
730 _width_owner = owner;
734 if (_width_owner == this) {
735 set_gui_property ("strip-width", enum_2_string (_width));
740 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
745 if (show_sends_button) {
746 show_sends_button->set_text (_("Aux"));
749 gpm.gain_automation_style_button.set_text (
750 gpm.astyle_string(gain_automation->automation_style()));
751 gpm.gain_automation_state_button.set_text (
752 gpm.astate_string(gain_automation->automation_state()));
754 if (_route->panner()) {
755 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
756 panners.astyle_string(_route->panner()->automation_style()));
757 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
758 panners.astate_string(_route->panner()->automation_state()));
762 // panners expect an even number of horiz. pixels
763 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
765 set_size_request (width, -1);
771 if (show_sends_button) {
772 show_sends_button->set_text (_("Snd"));
775 gpm.gain_automation_style_button.set_text (
776 gpm.short_astyle_string(gain_automation->automation_style()));
777 gpm.gain_automation_state_button.set_text (
778 gpm.short_astate_string(gain_automation->automation_state()));
779 gain_meter().setup_meters (); // recalc meter width
781 if (_route->panner()) {
782 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
783 panners.short_astyle_string(_route->panner()->automation_style()));
784 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
785 panners.short_astate_string(_route->panner()->automation_state()));
789 // panners expect an even number of horiz. pixels
790 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
792 set_size_request (width, -1);
797 processor_box.set_width (w);
799 update_input_display ();
800 update_output_display ();
801 setup_comment_button ();
802 route_group_changed ();
808 MixerStrip::set_packed (bool yn)
813 set_gui_property ("visible", true);
815 set_gui_property ("visible", false);
820 struct RouteCompareByName {
821 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
822 return a->name().compare (b->name()) < 0;
827 MixerStrip::output_release (GdkEventButton *ev)
829 switch (ev->button) {
831 edit_output_configuration ();
839 MixerStrip::output_press (GdkEventButton *ev)
841 using namespace Menu_Helpers;
842 if (!_session->engine().connected()) {
843 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
848 MenuList& citems = output_menu.items();
849 switch (ev->button) {
852 return false; //wait for the mouse-up to pop the dialog
856 output_menu.set_name ("ArdourContextMenu");
858 output_menu_bundles.clear ();
860 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
862 citems.push_back (SeparatorElem());
863 uint32_t const n_with_separator = citems.size ();
865 ARDOUR::BundleList current = _route->output()->bundles_connected ();
867 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
869 /* give user bundles first chance at being in the menu */
871 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
872 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
873 maybe_add_bundle_to_output_menu (*i, current);
877 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
878 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
879 maybe_add_bundle_to_output_menu (*i, current);
883 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
884 RouteList copy = *routes;
885 copy.sort (RouteCompareByName ());
886 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
887 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
890 if (citems.size() == n_with_separator) {
891 /* no routes added; remove the separator */
895 if (!ARDOUR::Profile->get_mixbus()) {
896 citems.push_back (SeparatorElem());
898 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
901 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
902 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
908 citems.push_back (SeparatorElem());
909 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
911 output_menu.popup (1, ev->time);
922 MixerStrip::input_release (GdkEventButton *ev)
924 switch (ev->button) {
927 edit_input_configuration ();
939 MixerStrip::input_press (GdkEventButton *ev)
941 using namespace Menu_Helpers;
943 MenuList& citems = input_menu.items();
944 input_menu.set_name ("ArdourContextMenu");
947 if (!_session->engine().connected()) {
948 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
953 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
956 switch (ev->button) {
959 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
963 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
965 citems.push_back (SeparatorElem());
966 uint32_t const n_with_separator = citems.size ();
968 input_menu_bundles.clear ();
970 ARDOUR::BundleList current = _route->input()->bundles_connected ();
972 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
974 /* give user bundles first chance at being in the menu */
976 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
977 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
978 maybe_add_bundle_to_input_menu (*i, current);
982 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
983 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
984 maybe_add_bundle_to_input_menu (*i, current);
988 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
989 RouteList copy = *routes;
990 copy.sort (RouteCompareByName ());
991 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
992 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
995 if (citems.size() == n_with_separator) {
996 /* no routes added; remove the separator */
1000 citems.push_back (SeparatorElem());
1001 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1004 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1005 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1010 citems.push_back (SeparatorElem());
1011 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1013 input_menu.popup (1, ev->time);
1024 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1026 if (ignore_toggle) {
1030 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1032 if (std::find (current.begin(), current.end(), c) == current.end()) {
1033 _route->input()->connect_ports_to_bundle (c, true, this);
1035 _route->input()->disconnect_ports_from_bundle (c, this);
1040 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1042 if (ignore_toggle) {
1046 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1048 if (std::find (current.begin(), current.end(), c) == current.end()) {
1049 _route->output()->connect_ports_to_bundle (c, true, this);
1051 _route->output()->disconnect_ports_from_bundle (c, this);
1056 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1058 using namespace Menu_Helpers;
1060 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1064 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1065 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1069 if (i != input_menu_bundles.end()) {
1073 input_menu_bundles.push_back (b);
1075 MenuList& citems = input_menu.items();
1077 std::string n = b->name ();
1078 replace_all (n, "_", " ");
1080 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1084 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1086 using namespace Menu_Helpers;
1088 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1092 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1093 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1097 if (i != output_menu_bundles.end()) {
1101 output_menu_bundles.push_back (b);
1103 MenuList& citems = output_menu.items();
1105 std::string n = b->name ();
1106 replace_all (n, "_", " ");
1108 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1112 MixerStrip::update_diskstream_display ()
1114 if (is_track() && input_selector) {
1115 input_selector->hide_all ();
1118 route_color_changed ();
1122 MixerStrip::connect_to_pan ()
1124 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1126 panstate_connection.disconnect ();
1127 panstyle_connection.disconnect ();
1129 if (!_route->panner()) {
1133 boost::shared_ptr<Pannable> p = _route->pannable ();
1135 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1136 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1138 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1139 * However, that only works a panner was previously set.
1141 * PannerUI must remain subscribed to _panshell->Changed() in case
1142 * we switch the panner eg. AUX-Send and back
1143 * _route->panner_shell()->Changed() vs _panshell->Changed
1145 if (panners._panner == 0) {
1146 panners.panshell_changed ();
1148 update_panner_choices();
1152 MixerStrip::update_panner_choices ()
1154 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1155 if (!_route->panner_shell()) { return; }
1157 uint32_t in = _route->output()->n_ports().n_audio();
1159 if (_route->panner()) {
1160 in = _route->panner()->in().n_audio();
1163 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1167 * Output port labelling
1168 * =====================
1170 * Case 1: Each output has one connection, all connections are to system:playback_%i
1171 * out 1 -> system:playback_1
1172 * out 2 -> system:playback_2
1173 * out 3 -> system:playback_3
1176 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1177 * out 1 -> ardour:track_x/in 1
1178 * out 2 -> ardour:track_x/in 2
1179 * Display as: track_x
1181 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1182 * out 1 -> program x:foo
1183 * out 2 -> program x:foo
1184 * Display as: program x
1186 * Case 4: No connections (Disconnected)
1189 * Default case (unusual routing):
1190 * Display as: *number of connections*
1194 * .-----------------------------------------------.
1196 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1197 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1198 * '-----------------------------------------------'
1199 * .-----------------------------------------------.
1202 * '-----------------------------------------------'
1206 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1210 boost::shared_ptr<Port> port;
1211 vector<string> port_connections;
1213 uint32_t total_connection_count = 0;
1214 uint32_t io_connection_count = 0;
1215 uint32_t ardour_connection_count = 0;
1216 uint32_t system_connection_count = 0;
1217 uint32_t other_connection_count = 0;
1218 uint32_t typed_connection_count = 0;
1220 ostringstream label;
1222 bool have_label = false;
1223 bool each_io_has_one_connection = true;
1225 string connection_name;
1226 string ardour_track_name;
1227 string other_connection_type;
1228 string system_ports;
1231 ostringstream tooltip;
1232 char * tooltip_cstr;
1234 //to avoid confusion, the button caption should only show connections that match the datatype of the track
1235 DataType dt = DataType::AUDIO;
1236 if ( boost::dynamic_pointer_cast<MidiTrack>(route) != 0 ) {
1237 dt = DataType::MIDI;
1238 // avoid further confusion with Midi-tracks that have a synth.
1239 // Audio-ports may be connected, but button says "Disconnected"
1240 tooltip << _("MIDI ");
1244 io_count = route->n_inputs().n_total();
1245 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1247 io_count = route->n_outputs().n_total();
1248 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1252 for (io_index = 0; io_index < io_count; ++io_index) {
1254 port = route->input()->nth (io_index);
1256 port = route->output()->nth (io_index);
1259 port_connections.clear ();
1260 port->get_connections(port_connections);
1262 //ignore any port connections that don't match our DataType
1263 if (port->type() != dt) {
1264 if (!port_connections.empty()) {
1265 ++typed_connection_count;
1270 io_connection_count = 0;
1272 if (!port_connections.empty()) {
1273 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1275 string& connection_name (*i);
1277 if (connection_name.find("system:") == 0) {
1278 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1281 if (io_connection_count == 0) {
1282 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1284 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1287 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1290 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1291 if (ardour_track_name.empty()) {
1292 // "ardour:Master/in 1" -> "ardour:Master/"
1293 string::size_type slash = connection_name.find("/");
1294 if (slash != string::npos) {
1295 ardour_track_name = connection_name.substr(0, slash + 1);
1299 if (connection_name.find(ardour_track_name) == 0) {
1300 ++ardour_connection_count;
1302 } else if (!pn.empty()) {
1303 if (system_ports.empty()) {
1306 system_ports += "/" + pn;
1308 if (connection_name.find("system:") == 0) {
1309 ++system_connection_count;
1311 } else if (connection_name.find("system:midi_") == 0) {
1313 // "system:midi_capture_123" -> "123"
1314 system_port = "M " + connection_name.substr(20);
1316 // "system:midi_playback_123" -> "123"
1317 system_port = "M " + connection_name.substr(21);
1320 if (system_ports.empty()) {
1321 system_ports += system_port;
1323 system_ports += "/" + system_port;
1326 ++system_connection_count;
1328 } else if (connection_name.find("system:") == 0) {
1330 // "system:capture_123" -> "123"
1331 system_port = connection_name.substr(15);
1333 // "system:playback_123" -> "123"
1334 system_port = connection_name.substr(16);
1337 if (system_ports.empty()) {
1338 system_ports += system_port;
1340 system_ports += "/" + system_port;
1343 ++system_connection_count;
1345 if (other_connection_type.empty()) {
1346 // "jamin:in 1" -> "jamin:"
1347 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1350 if (connection_name.find(other_connection_type) == 0) {
1351 ++other_connection_count;
1355 ++total_connection_count;
1356 ++io_connection_count;
1360 if (io_connection_count != 1) {
1361 each_io_has_one_connection = false;
1365 if (total_connection_count == 0) {
1366 tooltip << endl << _("Disconnected");
1369 tooltip_cstr = new char[tooltip.str().size() + 1];
1370 strcpy(tooltip_cstr, tooltip.str().c_str());
1373 set_tooltip (&input_button, tooltip_cstr);
1375 set_tooltip (&output_button, tooltip_cstr);
1378 delete [] tooltip_cstr;
1380 if (each_io_has_one_connection) {
1381 if (total_connection_count == ardour_connection_count) {
1382 // all connections are to the same track in ardour
1383 // "ardour:Master/" -> "Master"
1384 string::size_type slash = ardour_track_name.find("/");
1385 if (slash != string::npos) {
1386 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1387 label << ardour_track_name.substr (ppps, slash - ppps);
1391 else if (total_connection_count == system_connection_count) {
1392 // all connections are to system ports
1393 label << system_ports;
1396 else if (total_connection_count == other_connection_count) {
1397 // all connections are to the same external program eg jamin
1398 // "jamin:" -> "jamin"
1399 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1405 if (total_connection_count == 0) {
1409 // Odd configuration
1410 label << "*" << total_connection_count << "*";
1412 if (typed_connection_count > 0) {
1413 label << "\u2295"; // circled plus
1418 input_button.set_text (label.str());
1420 output_button.set_text (label.str());
1425 MixerStrip::update_input_display ()
1427 update_io_button (_route, _width, true);
1428 panners.setup_pan ();
1430 if (has_audio_outputs ()) {
1431 panners.show_all ();
1433 panners.hide_all ();
1439 MixerStrip::update_output_display ()
1441 update_io_button (_route, _width, false);
1442 gpm.setup_meters ();
1443 panners.setup_pan ();
1445 if (has_audio_outputs ()) {
1446 panners.show_all ();
1448 panners.hide_all ();
1453 MixerStrip::fast_update ()
1455 gpm.update_meters ();
1459 MixerStrip::diskstream_changed ()
1461 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1465 MixerStrip::io_changed_proxy ()
1467 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1471 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1473 boost::shared_ptr<Port> a = wa.lock ();
1474 boost::shared_ptr<Port> b = wb.lock ();
1476 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1477 update_input_display ();
1478 set_width_enum (_width, this);
1481 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1482 update_output_display ();
1483 set_width_enum (_width, this);
1488 MixerStrip::setup_comment_button ()
1493 if (_route->comment().empty ()) {
1494 _comment_button.unset_bg (STATE_NORMAL);
1495 _comment_button.set_text (_("Comments"));
1497 _comment_button.modify_bg (STATE_NORMAL, color ());
1498 _comment_button.set_text (_("*Comments*"));
1503 if (_route->comment().empty ()) {
1504 _comment_button.unset_bg (STATE_NORMAL);
1505 _comment_button.set_text (_("Cmt"));
1507 _comment_button.modify_bg (STATE_NORMAL, color ());
1508 _comment_button.set_text (_("*Cmt*"));
1514 _comment_button, _route->comment().empty() ? _("Click to add/edit comments") : _route->comment()
1520 MixerStrip::select_route_group (GdkEventButton *ev)
1522 using namespace Menu_Helpers;
1524 if (ev->button == 1) {
1526 if (group_menu == 0) {
1528 PropertyList* plist = new PropertyList();
1530 plist->add (Properties::group_gain, true);
1531 plist->add (Properties::group_mute, true);
1532 plist->add (Properties::group_solo, true);
1534 group_menu = new RouteGroupMenu (_session, plist);
1538 r.push_back (route ());
1539 group_menu->build (r);
1540 group_menu->menu()->popup (1, ev->time);
1547 MixerStrip::route_group_changed ()
1549 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1551 RouteGroup *rg = _route->route_group();
1554 group_button.set_text (PBD::short_version (rg->name(), 5));
1558 group_button.set_text (_("Grp"));
1561 group_button.set_text (_("~G"));
1568 MixerStrip::route_color_changed ()
1570 name_button.modify_bg (STATE_NORMAL, color());
1571 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1572 reset_strip_style ();
1576 MixerStrip::show_passthru_color ()
1578 reset_strip_style ();
1583 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1585 boost::shared_ptr<Processor> processor (p.lock ());
1586 if (!processor || !processor->display_to_user()) {
1589 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1590 ++_plugin_insert_cnt;
1594 MixerStrip::build_route_ops_menu ()
1596 using namespace Menu_Helpers;
1597 route_ops_menu = new Menu;
1598 route_ops_menu->set_name ("ArdourContextMenu");
1600 MenuList& items = route_ops_menu->items();
1602 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1604 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1606 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1608 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1610 items.push_back (SeparatorElem());
1612 if (!_route->is_master()) {
1613 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1615 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1616 rename_menu_item = &items.back();
1618 items.push_back (SeparatorElem());
1619 items.push_back (CheckMenuElem (_("Active")));
1620 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1621 i->set_active (_route->active());
1622 i->set_sensitive(! _session->transport_rolling());
1623 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1625 if (!Profile->get_mixbus ()) {
1626 items.push_back (SeparatorElem());
1627 items.push_back (CheckMenuElem (_("Strict I/O")));
1628 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1629 i->set_active (_route->strict_io());
1630 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1633 _plugin_insert_cnt = 0;
1634 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1635 if (_plugin_insert_cnt > 0) {
1636 items.push_back (SeparatorElem());
1637 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1640 items.push_back (SeparatorElem());
1641 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1643 items.push_back (SeparatorElem());
1644 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1645 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1646 denormal_menu_item->set_active (_route->denormal_protection());
1649 /* note that this relies on selection being shared across editor and
1650 mixer (or global to the backend, in the future), which is the only
1651 sane thing for users anyway.
1654 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1656 Selection& selection (PublicEditor::instance().get_selection());
1657 if (!selection.selected (rtav)) {
1658 selection.set (rtav);
1661 if (!_route->is_master()) {
1662 items.push_back (SeparatorElem());
1663 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1666 items.push_back (SeparatorElem());
1667 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1673 MixerStrip::name_button_button_press (GdkEventButton* ev)
1675 if (ev->button == 3) {
1676 list_route_operations ();
1678 /* do not allow rename if the track is record-enabled */
1679 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1680 route_ops_menu->popup (1, ev->time);
1689 MixerStrip::name_button_button_release (GdkEventButton* ev)
1691 if (ev->button == 1) {
1692 list_route_operations ();
1694 /* do not allow rename if the track is record-enabled */
1695 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1696 route_ops_menu->popup (1, ev->time);
1703 MixerStrip::number_button_button_press (GdkEventButton* ev)
1705 if ( ev->button == 3 ) {
1706 list_route_operations ();
1708 /* do not allow rename if the track is record-enabled */
1709 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1710 route_ops_menu->popup (1, ev->time);
1719 MixerStrip::list_route_operations ()
1721 delete route_ops_menu;
1722 build_route_ops_menu ();
1726 MixerStrip::show_selected ()
1729 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1730 global_frame.set_name ("MixerStripSelectedFrame");
1732 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1733 global_frame.set_name ("MixerStripFrame");
1736 global_frame.queue_draw ();
1739 // processor_box.deselect_all_processors();
1743 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1745 if (what_changed.contains (ARDOUR::Properties::name)) {
1751 MixerStrip::name_changed ()
1755 name_button.set_text (_route->name());
1758 name_button.set_text (PBD::short_version (_route->name(), 5));
1762 set_tooltip (name_button, _route->name());
1764 if (_session->config.get_track_name_number()) {
1765 const int64_t track_number = _route->track_number ();
1766 if (track_number == 0) {
1767 number_label.set_text ("-");
1769 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1772 number_label.set_text ("");
1777 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1779 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1783 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1785 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1789 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1791 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1795 MixerStrip::width_button_pressed (GdkEventButton* ev)
1797 if (ev->button != 1) {
1801 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1804 _mixer.set_strip_width (Narrow, true);
1808 _mixer.set_strip_width (Wide, true);
1814 set_width_enum (Narrow, this);
1817 set_width_enum (Wide, this);
1826 MixerStrip::hide_clicked ()
1828 // LAME fix to reset the button status for when it is redisplayed (part 1)
1829 hide_button.set_sensitive(false);
1832 Hiding(); /* EMIT_SIGNAL */
1834 _mixer.hide_strip (this);
1838 hide_button.set_sensitive(true);
1842 MixerStrip::set_embedded (bool yn)
1848 MixerStrip::map_frozen ()
1850 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1852 boost::shared_ptr<AudioTrack> at = audio_track();
1855 switch (at->freeze_state()) {
1856 case AudioTrack::Frozen:
1857 processor_box.set_sensitive (false);
1858 hide_redirect_editors ();
1861 processor_box.set_sensitive (true);
1862 // XXX need some way, maybe, to retoggle redirect editors
1866 processor_box.set_sensitive (true);
1868 RouteUI::map_frozen ();
1872 MixerStrip::hide_redirect_editors ()
1874 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1878 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1880 boost::shared_ptr<Processor> processor (p.lock ());
1885 Gtk::Window* w = processor_box.get_processor_ui (processor);
1893 MixerStrip::reset_strip_style ()
1895 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1897 gpm.set_fader_name ("SendStripBase");
1901 if (is_midi_track()) {
1902 if (_route->active()) {
1903 set_name ("MidiTrackStripBase");
1905 set_name ("MidiTrackStripBaseInactive");
1907 gpm.set_fader_name ("MidiTrackFader");
1908 } else if (is_audio_track()) {
1909 if (_route->active()) {
1910 set_name ("AudioTrackStripBase");
1912 set_name ("AudioTrackStripBaseInactive");
1914 gpm.set_fader_name ("AudioTrackFader");
1916 if (_route->active()) {
1917 set_name ("AudioBusStripBase");
1919 set_name ("AudioBusStripBaseInactive");
1921 gpm.set_fader_name ("AudioBusFader");
1923 /* (no MIDI busses yet) */
1930 MixerStrip::engine_stopped ()
1935 MixerStrip::engine_running ()
1940 MixerStrip::meter_point_string (MeterPoint mp)
1953 case MeterPostFader:
1970 return S_("Meter|In");
1974 return S_("Meter|Pr");
1977 case MeterPostFader:
1978 return S_("Meter|Po");
1982 return S_("Meter|O");
1987 return S_("Meter|C");
1996 /** Called when the monitor-section state */
1998 MixerStrip::monitor_changed ()
2000 assert (monitor_section_button);
2001 if (_session->monitor_active()) {
2002 monitor_section_button->set_name ("master monitor section button active");
2004 monitor_section_button->set_name ("master monitor section button normal");
2008 /** Called when the metering point has changed */
2010 MixerStrip::meter_changed ()
2012 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2013 gpm.setup_meters ();
2014 // reset peak when meter point changes
2015 gpm.reset_peak_display();
2018 /** The bus that we are displaying sends to has changed, or been turned off.
2019 * @param send_to New bus that we are displaying sends to, or 0.
2022 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2024 RouteUI::bus_send_display_changed (send_to);
2027 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2032 revert_to_default_display ();
2035 revert_to_default_display ();
2040 MixerStrip::drop_send ()
2042 boost::shared_ptr<Send> current_send;
2044 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2045 current_send->set_metering (false);
2048 send_gone_connection.disconnect ();
2049 input_button.set_sensitive (true);
2050 output_button.set_sensitive (true);
2051 group_button.set_sensitive (true);
2052 set_invert_sensitive (true);
2053 meter_point_button.set_sensitive (true);
2054 mute_button->set_sensitive (true);
2055 solo_button->set_sensitive (true);
2056 solo_isolated_led->set_sensitive (true);
2057 solo_safe_led->set_sensitive (true);
2058 monitor_input_button->set_sensitive (true);
2059 monitor_disk_button->set_sensitive (true);
2060 _comment_button.set_sensitive (true);
2061 RouteUI::check_rec_enable_sensitivity ();
2062 set_button_names (); // update solo button visual state
2066 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2068 _current_delivery = d;
2069 DeliveryChanged (_current_delivery);
2073 MixerStrip::show_send (boost::shared_ptr<Send> send)
2079 set_current_delivery (send);
2081 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2082 send->set_metering (true);
2083 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2085 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2086 gain_meter().setup_meters ();
2088 uint32_t const in = _current_delivery->pans_required();
2089 uint32_t const out = _current_delivery->pan_outs();
2091 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2092 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2093 panner_ui().setup_pan ();
2094 panner_ui().set_send_drawing_mode (true);
2095 panner_ui().show_all ();
2097 input_button.set_sensitive (false);
2098 group_button.set_sensitive (false);
2099 set_invert_sensitive (false);
2100 meter_point_button.set_sensitive (false);
2101 mute_button->set_sensitive (false);
2102 solo_button->set_sensitive (false);
2103 rec_enable_button->set_sensitive (false);
2104 solo_isolated_led->set_sensitive (false);
2105 solo_safe_led->set_sensitive (false);
2106 monitor_input_button->set_sensitive (false);
2107 monitor_disk_button->set_sensitive (false);
2108 _comment_button.set_sensitive (false);
2110 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2111 output_button.set_sensitive (false);
2114 reset_strip_style ();
2118 MixerStrip::revert_to_default_display ()
2122 set_current_delivery (_route->main_outs ());
2124 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2125 gain_meter().setup_meters ();
2127 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2128 update_panner_choices();
2129 panner_ui().setup_pan ();
2130 panner_ui().set_send_drawing_mode (false);
2132 if (has_audio_outputs ()) {
2133 panners.show_all ();
2135 panners.hide_all ();
2138 reset_strip_style ();
2142 MixerStrip::set_button_names ()
2146 mute_button->set_text (_("Mute"));
2147 monitor_input_button->set_text (_("In"));
2148 monitor_disk_button->set_text (_("Disk"));
2149 if (monitor_section_button) {
2150 monitor_section_button->set_text (_("Mon"));
2153 if (_route && _route->solo_safe_control()->solo_safe()) {
2154 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2156 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2158 if (!Config->get_solo_control_is_listen_control()) {
2159 solo_button->set_text (_("Solo"));
2161 switch (Config->get_listen_position()) {
2162 case AfterFaderListen:
2163 solo_button->set_text (_("AFL"));
2165 case PreFaderListen:
2166 solo_button->set_text (_("PFL"));
2170 solo_isolated_led->set_text (_("Iso"));
2171 solo_safe_led->set_text (S_("SoloLock|Lock"));
2175 mute_button->set_text (S_("Mute|M"));
2176 monitor_input_button->set_text (S_("MonitorInput|I"));
2177 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2178 if (monitor_section_button) {
2179 monitor_section_button->set_text (S_("Mon|O"));
2182 if (_route && _route->solo_safe_control()->solo_safe()) {
2183 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2185 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2187 if (!Config->get_solo_control_is_listen_control()) {
2188 solo_button->set_text (S_("Solo|S"));
2190 switch (Config->get_listen_position()) {
2191 case AfterFaderListen:
2192 solo_button->set_text (S_("AfterFader|A"));
2194 case PreFaderListen:
2195 solo_button->set_text (S_("Prefader|P"));
2200 solo_isolated_led->set_text (S_("SoloIso|I"));
2201 solo_safe_led->set_text (S_("SoloLock|L"));
2206 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2208 meter_point_button.set_text ("");
2213 MixerStrip::plugin_selector()
2215 return _mixer.plugin_selector();
2219 MixerStrip::hide_things ()
2221 processor_box.hide_things ();
2225 MixerStrip::input_active_button_press (GdkEventButton*)
2227 /* nothing happens on press */
2232 MixerStrip::input_active_button_release (GdkEventButton* ev)
2234 boost::shared_ptr<MidiTrack> mt = midi_track ();
2240 boost::shared_ptr<RouteList> rl (new RouteList);
2242 rl->push_back (route());
2244 _session->set_exclusive_input_active (rl, !mt->input_active(),
2245 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2251 MixerStrip::midi_input_status_changed ()
2253 if (midi_input_enable_button) {
2254 boost::shared_ptr<MidiTrack> mt = midi_track ();
2256 midi_input_enable_button->set_active (mt->input_active ());
2261 MixerStrip::state_id () const
2263 return string_compose ("strip %1", _route->id().to_s());
2267 MixerStrip::parameter_changed (string p)
2269 if (p == _visibility.get_state_name()) {
2270 /* The user has made changes to the mixer strip visibility, so get
2271 our VisibilityGroup to reflect these changes in our widgets.
2273 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2274 } else if (p == "track-name-number") {
2276 } else if (p == "use-monitor-bus") {
2277 if (monitor_section_button) {
2278 if (mute_button->get_parent()) {
2279 mute_button->get_parent()->remove(*mute_button);
2281 if (monitor_section_button->get_parent()) {
2282 monitor_section_button->get_parent()->remove(*monitor_section_button);
2284 if (Config->get_use_monitor_bus ()) {
2285 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2286 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2287 mute_button->show();
2288 monitor_section_button->show();
2290 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2291 mute_button->show();
2294 } else if (p == "track-name-number") {
2295 update_track_number_visibility();
2299 /** Called to decide whether the solo isolate / solo lock button visibility should
2300 * be overridden from that configured by the user. We do this for the master bus.
2302 * @return optional value that is present if visibility state should be overridden.
2304 boost::optional<bool>
2305 MixerStrip::override_solo_visibility () const
2307 if (_route && _route->is_master ()) {
2308 return boost::optional<bool> (false);
2311 return boost::optional<bool> ();
2315 MixerStrip::add_input_port (DataType t)
2317 _route->input()->add_port ("", this, t);
2321 MixerStrip::add_output_port (DataType t)
2323 _route->output()->add_port ("", this, t);
2327 MixerStrip::route_active_changed ()
2329 reset_strip_style ();
2333 MixerStrip::copy_processors ()
2335 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2339 MixerStrip::cut_processors ()
2341 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2345 MixerStrip::paste_processors ()
2347 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2351 MixerStrip::select_all_processors ()
2353 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2357 MixerStrip::deselect_all_processors ()
2359 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2363 MixerStrip::delete_processors ()
2365 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2369 MixerStrip::toggle_processors ()
2371 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2375 MixerStrip::ab_plugins ()
2377 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2381 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2383 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2386 if (ev->button == 3) {
2387 popup_level_meter_menu (ev);
2395 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2397 using namespace Gtk::Menu_Helpers;
2399 Gtk::Menu* m = manage (new Menu);
2400 MenuList& items = m->items ();
2402 RadioMenuItem::Group group;
2404 _suspend_menu_callbacks = true;
2405 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2406 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2407 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2408 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2409 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2411 if (gpm.meter_channels().n_audio() == 0) {
2412 m->popup (ev->button, ev->time);
2413 _suspend_menu_callbacks = false;
2417 RadioMenuItem::Group tgroup;
2418 items.push_back (SeparatorElem());
2420 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2421 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2422 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2423 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2424 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2425 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2426 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2427 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2428 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2429 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2430 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2433 if (_route->is_master()) {
2436 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2437 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2438 /* non-master bus */
2441 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2448 MeterType cmt = _route->meter_type();
2449 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2451 items.push_back (SeparatorElem());
2452 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2453 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2454 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2455 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2456 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2457 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2459 m->popup (ev->button, ev->time);
2460 _suspend_menu_callbacks = false;
2464 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2465 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2467 using namespace Menu_Helpers;
2469 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2470 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2471 i->set_active (_route->meter_point() == point);
2475 MixerStrip::set_meter_point (MeterPoint p)
2477 if (_suspend_menu_callbacks) return;
2478 _route->set_meter_point (p);
2482 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2483 RadioMenuItem::Group& group, string const & name, MeterType type)
2485 using namespace Menu_Helpers;
2487 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2488 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2489 i->set_active (_route->meter_type() == type);
2493 MixerStrip::set_meter_type (MeterType t)
2495 if (_suspend_menu_callbacks) return;
2500 MixerStrip::update_track_number_visibility ()
2502 DisplaySuspender ds;
2503 bool show_label = _session->config.get_track_name_number();
2505 if (_route && _route->is_master()) {
2510 number_label.show ();
2511 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2512 // except the width of the number label is subtracted from the name-hbox, so we
2513 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2514 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2516 number_label.set_size_request(tnw, -1);
2517 number_label.show ();
2519 number_label.hide ();
2524 MixerStrip::color () const
2526 return route_color ();
2530 MixerStrip::marked_for_display () const
2532 return !_route->presentation_info().hidden();
2536 MixerStrip::set_marked_for_display (bool yn)
2538 return RouteUI::mark_hidden (!yn);