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.set_text_ellipsize (Pango::ELLIPSIZE_END);
267 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
268 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
270 // TODO implement ArdourKnob::on_size_request properly
271 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
272 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
274 trim_control.set_tooltip_prefix (_("Trim: "));
275 trim_control.set_name ("trim knob");
276 trim_control.set_no_show_all (true);
277 input_button_box.pack_start (trim_control, false, false);
279 global_vpacker.set_border_width (1);
280 global_vpacker.set_spacing (0);
282 width_button.set_name ("mixer strip button");
283 hide_button.set_name ("mixer strip button");
285 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
286 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
288 width_hide_box.set_spacing (2);
289 width_hide_box.pack_start (width_button, false, true);
290 width_hide_box.pack_start (number_label, true, true);
291 width_hide_box.pack_end (hide_button, false, true);
293 number_label.set_text ("-");
294 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
295 number_label.set_no_show_all ();
296 number_label.set_name ("tracknumber label");
297 number_label.set_fixed_colors (0x80808080, 0x80808080);
298 number_label.set_alignment (.5, .5);
299 number_label.set_fallthrough_to_parent (true);
300 number_label.set_tweaks (ArdourButton::OccasionalText);
302 global_vpacker.set_spacing (2);
303 if (!ARDOUR::Profile->get_trx()) {
304 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (processor_box, true, true);
310 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
317 if (!ARDOUR::Profile->get_trx()) {
318 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
321 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
324 global_frame.add (global_vpacker);
325 global_frame.set_shadow_type (Gtk::SHADOW_IN);
326 global_frame.set_name ("BaseFrame");
330 /* force setting of visible selected status */
333 set_selected (false);
338 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
339 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
341 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
342 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
343 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
345 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
346 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
348 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
349 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
350 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
352 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
354 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
355 name_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_release), false);
357 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
361 /* start off as a passthru strip. we'll correct this, if necessary,
362 in update_diskstream_display().
365 /* start off as a passthru strip. we'll correct this, if necessary,
366 in update_diskstream_display().
369 if (is_midi_track()) {
370 set_name ("MidiTrackStripBase");
372 set_name ("AudioTrackStripBase");
375 add_events (Gdk::BUTTON_RELEASE_MASK|
376 Gdk::ENTER_NOTIFY_MASK|
377 Gdk::LEAVE_NOTIFY_MASK|
379 Gdk::KEY_RELEASE_MASK);
381 set_flags (get_flags() | Gtk::CAN_FOCUS);
383 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
384 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
387 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
388 must be the same as those used in RCOptionEditor so that the configuration changes
389 are recognised when they occur.
391 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
392 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
393 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
394 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
395 _visibility.add (&output_button, X_("Output"), _("Output"), false);
396 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
397 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
399 parameter_changed (X_("mixer-element-visibility"));
400 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
401 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
402 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
404 //watch for mouse enter/exit so we can do some stuff
405 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
406 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
408 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
411 MixerStrip::~MixerStrip ()
413 CatchDeletion (this);
415 if (this ==_entered_mixer_strip)
416 _entered_mixer_strip = NULL;
420 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
422 _entered_mixer_strip = this;
424 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
425 //because the mixerstrip control is a parent that encompasses the strip
426 deselect_all_processors();
432 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
434 //if we have moved outside our strip, but not into a child view, then deselect ourselves
435 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
436 _entered_mixer_strip= 0;
438 //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
439 gpm.gain_display.set_sensitive(false);
441 gpm.gain_display.set_sensitive(true);
443 //if we leave this mixer strip we need to clear out any selections
444 //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
451 MixerStrip::name() const
454 return _route->name();
460 MixerStrip::set_route (boost::shared_ptr<Route> rt)
462 //the rec/monitor stuff only shows up for tracks.
463 //the show_sends only shows up for buses.
464 //remove them all here, and we may add them back later
465 if (show_sends_button->get_parent()) {
466 rec_mon_table.remove (*show_sends_button);
468 if (rec_enable_button->get_parent()) {
469 rec_mon_table.remove (*rec_enable_button);
471 if (monitor_input_button->get_parent()) {
472 rec_mon_table.remove (*monitor_input_button);
474 if (monitor_disk_button->get_parent()) {
475 rec_mon_table.remove (*monitor_disk_button);
477 if (group_button.get_parent()) {
478 bottom_button_table.remove (group_button);
481 RouteUI::set_route (rt);
483 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
485 /* ProcessorBox needs access to _route so that it can read
488 processor_box.set_route (rt);
490 revert_to_default_display ();
492 /* unpack these from the parent and stuff them into our own
496 if (gpm.peak_display.get_parent()) {
497 gpm.peak_display.get_parent()->remove (gpm.peak_display);
499 if (gpm.gain_display.get_parent()) {
500 gpm.gain_display.get_parent()->remove (gpm.gain_display);
503 gpm.set_type (rt->meter_type());
505 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
506 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
508 if (solo_button->get_parent()) {
509 mute_solo_table.remove (*solo_button);
512 if (mute_button->get_parent()) {
513 mute_solo_table.remove (*mute_button);
516 if (route()->is_master()) {
517 solo_button->hide ();
518 mute_button->show ();
519 rec_mon_table.hide ();
520 if (solo_iso_table.get_parent()) {
521 solo_iso_table.get_parent()->remove(solo_iso_table);
523 if (monitor_section_button == 0) {
524 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
525 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
527 monitor_section_button = manage (new ArdourButton);
529 monitor_section_button->set_related_action (act);
530 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
531 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
532 monitor_section_button->show();
533 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
535 parameter_changed ("use-monitor-bus");
537 bottom_button_table.attach (group_button, 1, 2, 0, 1);
538 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
539 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
540 mute_button->show ();
541 solo_button->show ();
542 rec_mon_table.show ();
545 if (_mixer_owned && route()->is_master() ) {
547 HScrollbar scrollbar;
548 Gtk::Requisition requisition(scrollbar.size_request ());
549 int scrollbar_height = requisition.height;
551 spacer = manage (new EventBox);
552 spacer->set_size_request (-1, scrollbar_height+2);
553 global_vpacker.pack_start (*spacer, false, false);
558 monitor_input_button->show ();
559 monitor_disk_button->show ();
561 monitor_input_button->hide();
562 monitor_disk_button->hide ();
565 if (route()->trim() && route()->trim()->active()) {
566 trim_control.show ();
567 trim_control.set_controllable (route()->trim()->gain_control());
569 trim_control.hide ();
570 boost::shared_ptr<Controllable> none;
571 trim_control.set_controllable (none);
574 if (is_midi_track()) {
575 if (midi_input_enable_button == 0) {
576 midi_input_enable_button = manage (new ArdourButton);
577 midi_input_enable_button->set_name ("midi input button");
578 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
579 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
580 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
581 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
582 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
584 input_button_box.remove (*midi_input_enable_button);
586 /* get current state */
587 midi_input_status_changed ();
588 input_button_box.pack_start (*midi_input_enable_button, false, false);
590 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
592 if (midi_input_enable_button) {
593 /* removal from the container will delete it */
594 input_button_box.remove (*midi_input_enable_button);
595 midi_input_enable_button = 0;
599 if (is_audio_track()) {
600 boost::shared_ptr<AudioTrack> at = audio_track();
601 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
606 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
607 rec_enable_button->show();
609 if (ARDOUR::Profile->get_mixbus()) {
610 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
611 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
612 } else if (ARDOUR::Profile->get_trx()) {
613 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
615 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
616 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
623 if (!_route->is_master()) {
624 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
625 show_sends_button->show();
629 meter_point_button.set_text (meter_point_string (_route->meter_point()));
631 delete route_ops_menu;
634 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
635 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
636 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
637 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
639 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
641 if (_route->panner_shell()) {
642 update_panner_choices();
643 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
646 if (is_audio_track()) {
647 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
650 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
652 set_stuff_from_route ();
654 /* now force an update of all the various elements */
656 update_mute_display ();
657 update_solo_display ();
660 route_group_changed ();
661 update_track_number_visibility ();
664 panners.setup_pan ();
666 if (has_audio_outputs ()) {
672 update_diskstream_display ();
673 update_input_display ();
674 update_output_display ();
676 add_events (Gdk::BUTTON_RELEASE_MASK);
678 processor_box.show ();
680 if (!route()->is_master() && !route()->is_monitor()) {
681 /* we don't allow master or control routes to be hidden */
686 gpm.reset_peak_display ();
687 gpm.gain_display.show ();
688 gpm.peak_display.show ();
691 width_hide_box.show();
693 global_vpacker.show();
694 mute_solo_table.show();
695 bottom_button_table.show();
697 meter_point_button.show();
698 input_button_box.show_all();
699 output_button.show();
701 _comment_button.show();
703 gpm.gain_automation_state_button.show();
705 parameter_changed ("mixer-element-visibility");
712 MixerStrip::set_stuff_from_route ()
714 /* if width is not set, it will be set by the MixerUI or editor */
716 string str = gui_property ("strip-width");
718 set_width_enum (Width (string_2_enum (str, _width)), this);
723 MixerStrip::set_width_enum (Width w, void* owner)
725 /* always set the gpm width again, things may be hidden */
728 panners.set_width (w);
730 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
732 _width_owner = owner;
736 if (_width_owner == this) {
737 set_gui_property ("strip-width", enum_2_string (_width));
742 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
747 if (show_sends_button) {
748 show_sends_button->set_text (_("Aux"));
751 gpm.gain_automation_style_button.set_text (
752 gpm.astyle_string(gain_automation->automation_style()));
753 gpm.gain_automation_state_button.set_text (
754 gpm.astate_string(gain_automation->automation_state()));
756 if (_route->panner()) {
757 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
758 panners.astyle_string(_route->panner()->automation_style()));
759 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
760 panners.astate_string(_route->panner()->automation_state()));
764 // panners expect an even number of horiz. pixels
765 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
767 set_size_request (width, -1);
773 if (show_sends_button) {
774 show_sends_button->set_text (_("Snd"));
777 gpm.gain_automation_style_button.set_text (
778 gpm.short_astyle_string(gain_automation->automation_style()));
779 gpm.gain_automation_state_button.set_text (
780 gpm.short_astate_string(gain_automation->automation_state()));
781 gain_meter().setup_meters (); // recalc meter width
783 if (_route->panner()) {
784 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
785 panners.short_astyle_string(_route->panner()->automation_style()));
786 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
787 panners.short_astate_string(_route->panner()->automation_state()));
791 // panners expect an even number of horiz. pixels
792 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
794 set_size_request (width, -1);
799 processor_box.set_width (w);
801 update_input_display ();
802 update_output_display ();
803 setup_comment_button ();
804 route_group_changed ();
810 MixerStrip::set_packed (bool yn)
815 set_gui_property ("visible", true);
817 set_gui_property ("visible", false);
822 struct RouteCompareByName {
823 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
824 return a->name().compare (b->name()) < 0;
829 MixerStrip::output_release (GdkEventButton *ev)
831 switch (ev->button) {
833 edit_output_configuration ();
841 MixerStrip::output_press (GdkEventButton *ev)
843 using namespace Menu_Helpers;
844 if (!_session->engine().connected()) {
845 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
850 MenuList& citems = output_menu.items();
851 switch (ev->button) {
854 return false; //wait for the mouse-up to pop the dialog
858 output_menu.set_name ("ArdourContextMenu");
860 output_menu_bundles.clear ();
862 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
864 citems.push_back (SeparatorElem());
865 uint32_t const n_with_separator = citems.size ();
867 ARDOUR::BundleList current = _route->output()->bundles_connected ();
869 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
871 /* give user bundles first chance at being in the menu */
873 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
874 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
875 maybe_add_bundle_to_output_menu (*i, current);
879 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
880 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
881 maybe_add_bundle_to_output_menu (*i, current);
885 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
886 RouteList copy = *routes;
887 copy.sort (RouteCompareByName ());
888 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
889 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
892 if (citems.size() == n_with_separator) {
893 /* no routes added; remove the separator */
897 if (!ARDOUR::Profile->get_mixbus()) {
898 citems.push_back (SeparatorElem());
900 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
903 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
904 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
910 citems.push_back (SeparatorElem());
911 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
913 output_menu.popup (1, ev->time);
924 MixerStrip::input_release (GdkEventButton *ev)
926 switch (ev->button) {
929 edit_input_configuration ();
941 MixerStrip::input_press (GdkEventButton *ev)
943 using namespace Menu_Helpers;
945 MenuList& citems = input_menu.items();
946 input_menu.set_name ("ArdourContextMenu");
949 if (!_session->engine().connected()) {
950 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
955 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
958 switch (ev->button) {
961 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
965 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
967 citems.push_back (SeparatorElem());
968 uint32_t const n_with_separator = citems.size ();
970 input_menu_bundles.clear ();
972 ARDOUR::BundleList current = _route->input()->bundles_connected ();
974 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
976 /* give user bundles first chance at being in the menu */
978 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
979 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
980 maybe_add_bundle_to_input_menu (*i, current);
984 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
985 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
986 maybe_add_bundle_to_input_menu (*i, current);
990 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
991 RouteList copy = *routes;
992 copy.sort (RouteCompareByName ());
993 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
994 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
997 if (citems.size() == n_with_separator) {
998 /* no routes added; remove the separator */
1002 citems.push_back (SeparatorElem());
1003 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1006 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1007 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1012 citems.push_back (SeparatorElem());
1013 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1015 input_menu.popup (1, ev->time);
1026 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1028 if (ignore_toggle) {
1032 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1034 if (std::find (current.begin(), current.end(), c) == current.end()) {
1035 _route->input()->connect_ports_to_bundle (c, true, this);
1037 _route->input()->disconnect_ports_from_bundle (c, this);
1042 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1044 if (ignore_toggle) {
1048 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1050 if (std::find (current.begin(), current.end(), c) == current.end()) {
1051 _route->output()->connect_ports_to_bundle (c, true, this);
1053 _route->output()->disconnect_ports_from_bundle (c, this);
1058 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1060 using namespace Menu_Helpers;
1062 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1066 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1067 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1071 if (i != input_menu_bundles.end()) {
1075 input_menu_bundles.push_back (b);
1077 MenuList& citems = input_menu.items();
1079 std::string n = b->name ();
1080 replace_all (n, "_", " ");
1082 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1086 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1088 using namespace Menu_Helpers;
1090 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1094 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1095 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1099 if (i != output_menu_bundles.end()) {
1103 output_menu_bundles.push_back (b);
1105 MenuList& citems = output_menu.items();
1107 std::string n = b->name ();
1108 replace_all (n, "_", " ");
1110 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1114 MixerStrip::update_diskstream_display ()
1116 if (is_track() && input_selector) {
1117 input_selector->hide_all ();
1120 route_color_changed ();
1124 MixerStrip::connect_to_pan ()
1126 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1128 panstate_connection.disconnect ();
1129 panstyle_connection.disconnect ();
1131 if (!_route->panner()) {
1135 boost::shared_ptr<Pannable> p = _route->pannable ();
1137 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1138 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1140 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1141 * However, that only works a panner was previously set.
1143 * PannerUI must remain subscribed to _panshell->Changed() in case
1144 * we switch the panner eg. AUX-Send and back
1145 * _route->panner_shell()->Changed() vs _panshell->Changed
1147 if (panners._panner == 0) {
1148 panners.panshell_changed ();
1150 update_panner_choices();
1154 MixerStrip::update_panner_choices ()
1156 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1157 if (!_route->panner_shell()) { return; }
1159 uint32_t in = _route->output()->n_ports().n_audio();
1161 if (_route->panner()) {
1162 in = _route->panner()->in().n_audio();
1165 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1169 * Output port labelling
1170 * =====================
1172 * Case 1: Each output has one connection, all connections are to system:playback_%i
1173 * out 1 -> system:playback_1
1174 * out 2 -> system:playback_2
1175 * out 3 -> system:playback_3
1178 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1179 * out 1 -> ardour:track_x/in 1
1180 * out 2 -> ardour:track_x/in 2
1181 * Display as: track_x
1183 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1184 * out 1 -> program x:foo
1185 * out 2 -> program x:foo
1186 * Display as: program x
1188 * Case 4: No connections (Disconnected)
1191 * Default case (unusual routing):
1192 * Display as: *number of connections*
1196 * .-----------------------------------------------.
1198 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1199 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1200 * '-----------------------------------------------'
1201 * .-----------------------------------------------.
1204 * '-----------------------------------------------'
1208 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1212 boost::shared_ptr<Port> port;
1213 vector<string> port_connections;
1215 uint32_t total_connection_count = 0;
1216 uint32_t io_connection_count = 0;
1217 uint32_t ardour_connection_count = 0;
1218 uint32_t system_connection_count = 0;
1219 uint32_t other_connection_count = 0;
1220 uint32_t typed_connection_count = 0;
1222 ostringstream label;
1224 bool have_label = false;
1225 bool each_io_has_one_connection = true;
1227 string connection_name;
1228 string ardour_track_name;
1229 string other_connection_type;
1230 string system_ports;
1233 ostringstream tooltip;
1234 char * tooltip_cstr;
1236 //to avoid confusion, the button caption should only show connections that match the datatype of the track
1237 DataType dt = DataType::AUDIO;
1238 if ( boost::dynamic_pointer_cast<MidiTrack>(route) != 0 ) {
1239 dt = DataType::MIDI;
1240 // avoid further confusion with Midi-tracks that have a synth.
1241 // Audio-ports may be connected, but button says "Disconnected"
1242 tooltip << _("MIDI ");
1246 io_count = route->n_inputs().n_total();
1247 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1249 io_count = route->n_outputs().n_total();
1250 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1254 for (io_index = 0; io_index < io_count; ++io_index) {
1256 port = route->input()->nth (io_index);
1258 port = route->output()->nth (io_index);
1261 port_connections.clear ();
1262 port->get_connections(port_connections);
1264 //ignore any port connections that don't match our DataType
1265 if (port->type() != dt) {
1266 if (!port_connections.empty()) {
1267 ++typed_connection_count;
1272 io_connection_count = 0;
1274 if (!port_connections.empty()) {
1275 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1277 string& connection_name (*i);
1279 if (connection_name.find("system:") == 0) {
1280 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1283 if (io_connection_count == 0) {
1284 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1286 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1289 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1292 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1293 if (ardour_track_name.empty()) {
1294 // "ardour:Master/in 1" -> "ardour:Master/"
1295 string::size_type slash = connection_name.find("/");
1296 if (slash != string::npos) {
1297 ardour_track_name = connection_name.substr(0, slash + 1);
1301 if (connection_name.find(ardour_track_name) == 0) {
1302 ++ardour_connection_count;
1304 } else if (!pn.empty()) {
1305 if (system_ports.empty()) {
1308 system_ports += "/" + pn;
1310 if (connection_name.find("system:") == 0) {
1311 ++system_connection_count;
1313 } else if (connection_name.find("system:midi_") == 0) {
1315 // "system:midi_capture_123" -> "123"
1316 system_port = "M " + connection_name.substr(20);
1318 // "system:midi_playback_123" -> "123"
1319 system_port = "M " + connection_name.substr(21);
1322 if (system_ports.empty()) {
1323 system_ports += system_port;
1325 system_ports += "/" + system_port;
1328 ++system_connection_count;
1330 } else if (connection_name.find("system:") == 0) {
1332 // "system:capture_123" -> "123"
1333 system_port = connection_name.substr(15);
1335 // "system:playback_123" -> "123"
1336 system_port = connection_name.substr(16);
1339 if (system_ports.empty()) {
1340 system_ports += system_port;
1342 system_ports += "/" + system_port;
1345 ++system_connection_count;
1347 if (other_connection_type.empty()) {
1348 // "jamin:in 1" -> "jamin:"
1349 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1352 if (connection_name.find(other_connection_type) == 0) {
1353 ++other_connection_count;
1357 ++total_connection_count;
1358 ++io_connection_count;
1362 if (io_connection_count != 1) {
1363 each_io_has_one_connection = false;
1367 if (total_connection_count == 0) {
1368 tooltip << endl << _("Disconnected");
1371 tooltip_cstr = new char[tooltip.str().size() + 1];
1372 strcpy(tooltip_cstr, tooltip.str().c_str());
1375 set_tooltip (&input_button, tooltip_cstr);
1377 set_tooltip (&output_button, tooltip_cstr);
1380 delete [] tooltip_cstr;
1382 if (each_io_has_one_connection) {
1383 if (total_connection_count == ardour_connection_count) {
1384 // all connections are to the same track in ardour
1385 // "ardour:Master/" -> "Master"
1386 string::size_type slash = ardour_track_name.find("/");
1387 if (slash != string::npos) {
1388 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1389 label << ardour_track_name.substr (ppps, slash - ppps);
1393 else if (total_connection_count == system_connection_count) {
1394 // all connections are to system ports
1395 label << system_ports;
1398 else if (total_connection_count == other_connection_count) {
1399 // all connections are to the same external program eg jamin
1400 // "jamin:" -> "jamin"
1401 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1407 if (total_connection_count == 0) {
1411 // Odd configuration
1412 label << "*" << total_connection_count << "*";
1414 if (typed_connection_count > 0) {
1415 label << "\u2295"; // circled plus
1420 input_button.set_text (label.str());
1422 output_button.set_text (label.str());
1427 MixerStrip::update_input_display ()
1429 update_io_button (_route, _width, true);
1430 panners.setup_pan ();
1432 if (has_audio_outputs ()) {
1433 panners.show_all ();
1435 panners.hide_all ();
1441 MixerStrip::update_output_display ()
1443 update_io_button (_route, _width, false);
1444 gpm.setup_meters ();
1445 panners.setup_pan ();
1447 if (has_audio_outputs ()) {
1448 panners.show_all ();
1450 panners.hide_all ();
1455 MixerStrip::fast_update ()
1457 gpm.update_meters ();
1461 MixerStrip::diskstream_changed ()
1463 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1467 MixerStrip::io_changed_proxy ()
1469 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1473 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1475 boost::shared_ptr<Port> a = wa.lock ();
1476 boost::shared_ptr<Port> b = wb.lock ();
1478 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1479 update_input_display ();
1480 set_width_enum (_width, this);
1483 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1484 update_output_display ();
1485 set_width_enum (_width, this);
1490 MixerStrip::setup_comment_button ()
1492 std::string comment = _route->comment();
1494 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1496 if (comment.empty ()) {
1497 _comment_button.set_name ("generic button");
1498 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1502 _comment_button.set_name ("comment button");
1504 string::size_type pos = comment.find_first_of (" \t\n");
1505 if (pos != string::npos) {
1506 comment = comment.substr (0, pos);
1508 if (comment.empty()) {
1509 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1511 _comment_button.set_text (comment);
1516 MixerStrip::select_route_group (GdkEventButton *ev)
1518 using namespace Menu_Helpers;
1520 if (ev->button == 1) {
1522 if (group_menu == 0) {
1524 PropertyList* plist = new PropertyList();
1526 plist->add (Properties::group_gain, true);
1527 plist->add (Properties::group_mute, true);
1528 plist->add (Properties::group_solo, true);
1530 group_menu = new RouteGroupMenu (_session, plist);
1534 r.push_back (route ());
1535 group_menu->build (r);
1536 group_menu->menu()->popup (1, ev->time);
1543 MixerStrip::route_group_changed ()
1545 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1547 RouteGroup *rg = _route->route_group();
1550 group_button.set_text (PBD::short_version (rg->name(), 5));
1554 group_button.set_text (_("Grp"));
1557 group_button.set_text (_("~G"));
1564 MixerStrip::route_color_changed ()
1566 name_button.modify_bg (STATE_NORMAL, color());
1567 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1568 reset_strip_style ();
1572 MixerStrip::show_passthru_color ()
1574 reset_strip_style ();
1579 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1581 boost::shared_ptr<Processor> processor (p.lock ());
1582 if (!processor || !processor->display_to_user()) {
1585 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1586 ++_plugin_insert_cnt;
1590 MixerStrip::build_route_ops_menu ()
1592 using namespace Menu_Helpers;
1593 route_ops_menu = new Menu;
1594 route_ops_menu->set_name ("ArdourContextMenu");
1596 MenuList& items = route_ops_menu->items();
1598 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1600 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1602 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1604 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1606 items.push_back (SeparatorElem());
1608 if (!_route->is_master()) {
1609 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1611 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1612 rename_menu_item = &items.back();
1614 items.push_back (SeparatorElem());
1615 items.push_back (CheckMenuElem (_("Active")));
1616 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1617 i->set_active (_route->active());
1618 i->set_sensitive(! _session->transport_rolling());
1619 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1621 if (!Profile->get_mixbus ()) {
1622 items.push_back (SeparatorElem());
1623 items.push_back (CheckMenuElem (_("Strict I/O")));
1624 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1625 i->set_active (_route->strict_io());
1626 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1629 _plugin_insert_cnt = 0;
1630 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1631 if (_plugin_insert_cnt > 0) {
1632 items.push_back (SeparatorElem());
1633 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1636 items.push_back (SeparatorElem());
1637 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1639 items.push_back (SeparatorElem());
1640 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1641 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1642 denormal_menu_item->set_active (_route->denormal_protection());
1645 /* note that this relies on selection being shared across editor and
1646 mixer (or global to the backend, in the future), which is the only
1647 sane thing for users anyway.
1650 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1652 Selection& selection (PublicEditor::instance().get_selection());
1653 if (!selection.selected (rtav)) {
1654 selection.set (rtav);
1657 if (!_route->is_master()) {
1658 items.push_back (SeparatorElem());
1659 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1662 items.push_back (SeparatorElem());
1663 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1669 MixerStrip::name_button_button_press (GdkEventButton* ev)
1671 if (ev->button == 3) {
1672 list_route_operations ();
1674 /* do not allow rename if the track is record-enabled */
1675 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1676 route_ops_menu->popup (1, ev->time);
1685 MixerStrip::name_button_button_release (GdkEventButton* ev)
1687 if (ev->button == 1) {
1688 list_route_operations ();
1690 /* do not allow rename if the track is record-enabled */
1691 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1692 route_ops_menu->popup (1, ev->time);
1699 MixerStrip::number_button_button_press (GdkEventButton* ev)
1701 if ( ev->button == 3 ) {
1702 list_route_operations ();
1704 /* do not allow rename if the track is record-enabled */
1705 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1706 route_ops_menu->popup (1, ev->time);
1715 MixerStrip::list_route_operations ()
1717 delete route_ops_menu;
1718 build_route_ops_menu ();
1722 MixerStrip::set_selected (bool yn)
1724 AxisView::set_selected (yn);
1727 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1728 global_frame.set_name ("MixerStripSelectedFrame");
1730 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1731 global_frame.set_name ("MixerStripFrame");
1734 global_frame.queue_draw ();
1737 // processor_box.deselect_all_processors();
1741 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1743 if (what_changed.contains (ARDOUR::Properties::name)) {
1749 MixerStrip::name_changed ()
1753 name_button.set_text (_route->name());
1756 name_button.set_text (PBD::short_version (_route->name(), 5));
1760 set_tooltip (name_button, _route->name());
1762 if (_session->config.get_track_name_number()) {
1763 const int64_t track_number = _route->track_number ();
1764 if (track_number == 0) {
1765 number_label.set_text ("-");
1767 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1770 number_label.set_text ("");
1775 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1777 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1781 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1783 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1787 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1789 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1793 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1795 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1799 MixerStrip::width_button_pressed (GdkEventButton* ev)
1801 if (ev->button != 1) {
1805 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1808 _mixer.set_strip_width (Narrow, true);
1812 _mixer.set_strip_width (Wide, true);
1818 set_width_enum (Narrow, this);
1821 set_width_enum (Wide, this);
1830 MixerStrip::hide_clicked ()
1832 // LAME fix to reset the button status for when it is redisplayed (part 1)
1833 hide_button.set_sensitive(false);
1836 Hiding(); /* EMIT_SIGNAL */
1838 _mixer.hide_strip (this);
1842 hide_button.set_sensitive(true);
1846 MixerStrip::set_embedded (bool yn)
1852 MixerStrip::map_frozen ()
1854 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1856 boost::shared_ptr<AudioTrack> at = audio_track();
1859 switch (at->freeze_state()) {
1860 case AudioTrack::Frozen:
1861 processor_box.set_sensitive (false);
1862 hide_redirect_editors ();
1865 processor_box.set_sensitive (true);
1866 // XXX need some way, maybe, to retoggle redirect editors
1870 processor_box.set_sensitive (true);
1872 RouteUI::map_frozen ();
1876 MixerStrip::hide_redirect_editors ()
1878 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1882 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1884 boost::shared_ptr<Processor> processor (p.lock ());
1889 Gtk::Window* w = processor_box.get_processor_ui (processor);
1897 MixerStrip::reset_strip_style ()
1899 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1901 gpm.set_fader_name ("SendStripBase");
1905 if (is_midi_track()) {
1906 if (_route->active()) {
1907 set_name ("MidiTrackStripBase");
1909 set_name ("MidiTrackStripBaseInactive");
1911 gpm.set_fader_name ("MidiTrackFader");
1912 } else if (is_audio_track()) {
1913 if (_route->active()) {
1914 set_name ("AudioTrackStripBase");
1916 set_name ("AudioTrackStripBaseInactive");
1918 gpm.set_fader_name ("AudioTrackFader");
1920 if (_route->active()) {
1921 set_name ("AudioBusStripBase");
1923 set_name ("AudioBusStripBaseInactive");
1925 gpm.set_fader_name ("AudioBusFader");
1927 /* (no MIDI busses yet) */
1934 MixerStrip::engine_stopped ()
1939 MixerStrip::engine_running ()
1944 MixerStrip::meter_point_string (MeterPoint mp)
1957 case MeterPostFader:
1974 return S_("Meter|In");
1978 return S_("Meter|Pr");
1981 case MeterPostFader:
1982 return S_("Meter|Po");
1986 return S_("Meter|O");
1991 return S_("Meter|C");
2000 /** Called when the monitor-section state */
2002 MixerStrip::monitor_changed ()
2004 assert (monitor_section_button);
2005 if (_session->monitor_active()) {
2006 monitor_section_button->set_name ("master monitor section button active");
2008 monitor_section_button->set_name ("master monitor section button normal");
2012 /** Called when the metering point has changed */
2014 MixerStrip::meter_changed ()
2016 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2017 gpm.setup_meters ();
2018 // reset peak when meter point changes
2019 gpm.reset_peak_display();
2022 /** The bus that we are displaying sends to has changed, or been turned off.
2023 * @param send_to New bus that we are displaying sends to, or 0.
2026 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2028 RouteUI::bus_send_display_changed (send_to);
2031 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2036 revert_to_default_display ();
2039 revert_to_default_display ();
2044 MixerStrip::drop_send ()
2046 boost::shared_ptr<Send> current_send;
2048 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2049 current_send->set_metering (false);
2052 send_gone_connection.disconnect ();
2053 input_button.set_sensitive (true);
2054 output_button.set_sensitive (true);
2055 group_button.set_sensitive (true);
2056 set_invert_sensitive (true);
2057 meter_point_button.set_sensitive (true);
2058 mute_button->set_sensitive (true);
2059 solo_button->set_sensitive (true);
2060 solo_isolated_led->set_sensitive (true);
2061 solo_safe_led->set_sensitive (true);
2062 monitor_input_button->set_sensitive (true);
2063 monitor_disk_button->set_sensitive (true);
2064 _comment_button.set_sensitive (true);
2065 RouteUI::check_rec_enable_sensitivity ();
2066 set_button_names (); // update solo button visual state
2070 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2072 _current_delivery = d;
2073 DeliveryChanged (_current_delivery);
2077 MixerStrip::show_send (boost::shared_ptr<Send> send)
2083 set_current_delivery (send);
2085 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2086 send->set_metering (true);
2087 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2089 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2090 gain_meter().setup_meters ();
2092 uint32_t const in = _current_delivery->pans_required();
2093 uint32_t const out = _current_delivery->pan_outs();
2095 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2096 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2097 panner_ui().setup_pan ();
2098 panner_ui().set_send_drawing_mode (true);
2099 panner_ui().show_all ();
2101 input_button.set_sensitive (false);
2102 group_button.set_sensitive (false);
2103 set_invert_sensitive (false);
2104 meter_point_button.set_sensitive (false);
2105 mute_button->set_sensitive (false);
2106 solo_button->set_sensitive (false);
2107 rec_enable_button->set_sensitive (false);
2108 solo_isolated_led->set_sensitive (false);
2109 solo_safe_led->set_sensitive (false);
2110 monitor_input_button->set_sensitive (false);
2111 monitor_disk_button->set_sensitive (false);
2112 _comment_button.set_sensitive (false);
2114 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2115 output_button.set_sensitive (false);
2118 reset_strip_style ();
2122 MixerStrip::revert_to_default_display ()
2126 set_current_delivery (_route->main_outs ());
2128 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2129 gain_meter().setup_meters ();
2131 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2132 update_panner_choices();
2133 panner_ui().setup_pan ();
2134 panner_ui().set_send_drawing_mode (false);
2136 if (has_audio_outputs ()) {
2137 panners.show_all ();
2139 panners.hide_all ();
2142 reset_strip_style ();
2146 MixerStrip::set_button_names ()
2150 mute_button->set_text (_("Mute"));
2151 monitor_input_button->set_text (_("In"));
2152 monitor_disk_button->set_text (_("Disk"));
2153 if (monitor_section_button) {
2154 monitor_section_button->set_text (_("Mon"));
2157 if (_route && _route->solo_safe_control()->solo_safe()) {
2158 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2160 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2162 if (!Config->get_solo_control_is_listen_control()) {
2163 solo_button->set_text (_("Solo"));
2165 switch (Config->get_listen_position()) {
2166 case AfterFaderListen:
2167 solo_button->set_text (_("AFL"));
2169 case PreFaderListen:
2170 solo_button->set_text (_("PFL"));
2174 solo_isolated_led->set_text (_("Iso"));
2175 solo_safe_led->set_text (S_("SoloLock|Lock"));
2179 mute_button->set_text (S_("Mute|M"));
2180 monitor_input_button->set_text (S_("MonitorInput|I"));
2181 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2182 if (monitor_section_button) {
2183 monitor_section_button->set_text (S_("Mon|O"));
2186 if (_route && _route->solo_safe_control()->solo_safe()) {
2187 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2189 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2191 if (!Config->get_solo_control_is_listen_control()) {
2192 solo_button->set_text (S_("Solo|S"));
2194 switch (Config->get_listen_position()) {
2195 case AfterFaderListen:
2196 solo_button->set_text (S_("AfterFader|A"));
2198 case PreFaderListen:
2199 solo_button->set_text (S_("Prefader|P"));
2204 solo_isolated_led->set_text (S_("SoloIso|I"));
2205 solo_safe_led->set_text (S_("SoloLock|L"));
2210 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2212 meter_point_button.set_text ("");
2217 MixerStrip::plugin_selector()
2219 return _mixer.plugin_selector();
2223 MixerStrip::hide_things ()
2225 processor_box.hide_things ();
2229 MixerStrip::input_active_button_press (GdkEventButton*)
2231 /* nothing happens on press */
2236 MixerStrip::input_active_button_release (GdkEventButton* ev)
2238 boost::shared_ptr<MidiTrack> mt = midi_track ();
2244 boost::shared_ptr<RouteList> rl (new RouteList);
2246 rl->push_back (route());
2248 _session->set_exclusive_input_active (rl, !mt->input_active(),
2249 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2255 MixerStrip::midi_input_status_changed ()
2257 if (midi_input_enable_button) {
2258 boost::shared_ptr<MidiTrack> mt = midi_track ();
2260 midi_input_enable_button->set_active (mt->input_active ());
2265 MixerStrip::state_id () const
2267 return string_compose ("strip %1", _route->id().to_s());
2271 MixerStrip::parameter_changed (string p)
2273 if (p == _visibility.get_state_name()) {
2274 /* The user has made changes to the mixer strip visibility, so get
2275 our VisibilityGroup to reflect these changes in our widgets.
2277 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2278 } else if (p == "track-name-number") {
2280 } else if (p == "use-monitor-bus") {
2281 if (monitor_section_button) {
2282 if (mute_button->get_parent()) {
2283 mute_button->get_parent()->remove(*mute_button);
2285 if (monitor_section_button->get_parent()) {
2286 monitor_section_button->get_parent()->remove(*monitor_section_button);
2288 if (Config->get_use_monitor_bus ()) {
2289 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2290 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2291 mute_button->show();
2292 monitor_section_button->show();
2294 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2295 mute_button->show();
2298 } else if (p == "track-name-number") {
2299 update_track_number_visibility();
2303 /** Called to decide whether the solo isolate / solo lock button visibility should
2304 * be overridden from that configured by the user. We do this for the master bus.
2306 * @return optional value that is present if visibility state should be overridden.
2308 boost::optional<bool>
2309 MixerStrip::override_solo_visibility () const
2311 if (_route && _route->is_master ()) {
2312 return boost::optional<bool> (false);
2315 return boost::optional<bool> ();
2319 MixerStrip::add_input_port (DataType t)
2321 _route->input()->add_port ("", this, t);
2325 MixerStrip::add_output_port (DataType t)
2327 _route->output()->add_port ("", this, t);
2331 MixerStrip::route_active_changed ()
2333 reset_strip_style ();
2337 MixerStrip::copy_processors ()
2339 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2343 MixerStrip::cut_processors ()
2345 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2349 MixerStrip::paste_processors ()
2351 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2355 MixerStrip::select_all_processors ()
2357 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2361 MixerStrip::deselect_all_processors ()
2363 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2367 MixerStrip::delete_processors ()
2369 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2373 MixerStrip::toggle_processors ()
2375 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2379 MixerStrip::ab_plugins ()
2381 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2385 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2387 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2390 if (ev->button == 3) {
2391 popup_level_meter_menu (ev);
2399 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2401 using namespace Gtk::Menu_Helpers;
2403 Gtk::Menu* m = manage (new Menu);
2404 MenuList& items = m->items ();
2406 RadioMenuItem::Group group;
2408 _suspend_menu_callbacks = true;
2409 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2410 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2411 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2412 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2413 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2415 if (gpm.meter_channels().n_audio() == 0) {
2416 m->popup (ev->button, ev->time);
2417 _suspend_menu_callbacks = false;
2421 RadioMenuItem::Group tgroup;
2422 items.push_back (SeparatorElem());
2424 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2425 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2426 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2427 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2428 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2429 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2430 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2431 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2432 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2433 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2434 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2437 if (_route->is_master()) {
2440 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2441 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2442 /* non-master bus */
2445 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2452 MeterType cmt = _route->meter_type();
2453 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2455 items.push_back (SeparatorElem());
2456 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2457 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2458 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2459 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2460 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2461 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2463 m->popup (ev->button, ev->time);
2464 _suspend_menu_callbacks = false;
2468 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2469 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2471 using namespace Menu_Helpers;
2473 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2474 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2475 i->set_active (_route->meter_point() == point);
2479 MixerStrip::set_meter_point (MeterPoint p)
2481 if (_suspend_menu_callbacks) return;
2482 _route->set_meter_point (p);
2486 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2487 RadioMenuItem::Group& group, string const & name, MeterType type)
2489 using namespace Menu_Helpers;
2491 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2492 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2493 i->set_active (_route->meter_type() == type);
2497 MixerStrip::set_meter_type (MeterType t)
2499 if (_suspend_menu_callbacks) return;
2504 MixerStrip::update_track_number_visibility ()
2506 DisplaySuspender ds;
2507 bool show_label = _session->config.get_track_name_number();
2509 if (_route && _route->is_master()) {
2514 number_label.show ();
2515 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2516 // except the width of the number label is subtracted from the name-hbox, so we
2517 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2518 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2520 number_label.set_size_request(tnw, -1);
2521 number_label.show ();
2523 number_label.hide ();
2528 MixerStrip::color () const
2530 return route_color ();
2534 MixerStrip::marked_for_display () const
2536 return !_route->presentation_info().hidden();
2540 MixerStrip::set_marked_for_display (bool yn)
2542 return RouteUI::mark_hidden (!yn);