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::show_selected ()
1725 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1726 global_frame.set_name ("MixerStripSelectedFrame");
1728 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1729 global_frame.set_name ("MixerStripFrame");
1732 global_frame.queue_draw ();
1735 // processor_box.deselect_all_processors();
1739 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1741 if (what_changed.contains (ARDOUR::Properties::name)) {
1747 MixerStrip::name_changed ()
1751 name_button.set_text (_route->name());
1754 name_button.set_text (PBD::short_version (_route->name(), 5));
1758 set_tooltip (name_button, _route->name());
1760 if (_session->config.get_track_name_number()) {
1761 const int64_t track_number = _route->track_number ();
1762 if (track_number == 0) {
1763 number_label.set_text ("-");
1765 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1768 number_label.set_text ("");
1773 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1775 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1779 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1781 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1785 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1787 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1791 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1793 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1797 MixerStrip::width_button_pressed (GdkEventButton* ev)
1799 if (ev->button != 1) {
1803 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1806 _mixer.set_strip_width (Narrow, true);
1810 _mixer.set_strip_width (Wide, true);
1816 set_width_enum (Narrow, this);
1819 set_width_enum (Wide, this);
1828 MixerStrip::hide_clicked ()
1830 // LAME fix to reset the button status for when it is redisplayed (part 1)
1831 hide_button.set_sensitive(false);
1834 Hiding(); /* EMIT_SIGNAL */
1836 _mixer.hide_strip (this);
1840 hide_button.set_sensitive(true);
1844 MixerStrip::set_embedded (bool yn)
1850 MixerStrip::map_frozen ()
1852 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1854 boost::shared_ptr<AudioTrack> at = audio_track();
1857 switch (at->freeze_state()) {
1858 case AudioTrack::Frozen:
1859 processor_box.set_sensitive (false);
1860 hide_redirect_editors ();
1863 processor_box.set_sensitive (true);
1864 // XXX need some way, maybe, to retoggle redirect editors
1868 processor_box.set_sensitive (true);
1870 RouteUI::map_frozen ();
1874 MixerStrip::hide_redirect_editors ()
1876 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1880 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1882 boost::shared_ptr<Processor> processor (p.lock ());
1887 Gtk::Window* w = processor_box.get_processor_ui (processor);
1895 MixerStrip::reset_strip_style ()
1897 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1899 gpm.set_fader_name ("SendStripBase");
1903 if (is_midi_track()) {
1904 if (_route->active()) {
1905 set_name ("MidiTrackStripBase");
1907 set_name ("MidiTrackStripBaseInactive");
1909 gpm.set_fader_name ("MidiTrackFader");
1910 } else if (is_audio_track()) {
1911 if (_route->active()) {
1912 set_name ("AudioTrackStripBase");
1914 set_name ("AudioTrackStripBaseInactive");
1916 gpm.set_fader_name ("AudioTrackFader");
1918 if (_route->active()) {
1919 set_name ("AudioBusStripBase");
1921 set_name ("AudioBusStripBaseInactive");
1923 gpm.set_fader_name ("AudioBusFader");
1925 /* (no MIDI busses yet) */
1932 MixerStrip::engine_stopped ()
1937 MixerStrip::engine_running ()
1942 MixerStrip::meter_point_string (MeterPoint mp)
1955 case MeterPostFader:
1972 return S_("Meter|In");
1976 return S_("Meter|Pr");
1979 case MeterPostFader:
1980 return S_("Meter|Po");
1984 return S_("Meter|O");
1989 return S_("Meter|C");
1998 /** Called when the monitor-section state */
2000 MixerStrip::monitor_changed ()
2002 assert (monitor_section_button);
2003 if (_session->monitor_active()) {
2004 monitor_section_button->set_name ("master monitor section button active");
2006 monitor_section_button->set_name ("master monitor section button normal");
2010 /** Called when the metering point has changed */
2012 MixerStrip::meter_changed ()
2014 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2015 gpm.setup_meters ();
2016 // reset peak when meter point changes
2017 gpm.reset_peak_display();
2020 /** The bus that we are displaying sends to has changed, or been turned off.
2021 * @param send_to New bus that we are displaying sends to, or 0.
2024 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2026 RouteUI::bus_send_display_changed (send_to);
2029 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2034 revert_to_default_display ();
2037 revert_to_default_display ();
2042 MixerStrip::drop_send ()
2044 boost::shared_ptr<Send> current_send;
2046 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2047 current_send->set_metering (false);
2050 send_gone_connection.disconnect ();
2051 input_button.set_sensitive (true);
2052 output_button.set_sensitive (true);
2053 group_button.set_sensitive (true);
2054 set_invert_sensitive (true);
2055 meter_point_button.set_sensitive (true);
2056 mute_button->set_sensitive (true);
2057 solo_button->set_sensitive (true);
2058 solo_isolated_led->set_sensitive (true);
2059 solo_safe_led->set_sensitive (true);
2060 monitor_input_button->set_sensitive (true);
2061 monitor_disk_button->set_sensitive (true);
2062 _comment_button.set_sensitive (true);
2063 RouteUI::check_rec_enable_sensitivity ();
2064 set_button_names (); // update solo button visual state
2068 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2070 _current_delivery = d;
2071 DeliveryChanged (_current_delivery);
2075 MixerStrip::show_send (boost::shared_ptr<Send> send)
2081 set_current_delivery (send);
2083 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2084 send->set_metering (true);
2085 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2087 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2088 gain_meter().setup_meters ();
2090 uint32_t const in = _current_delivery->pans_required();
2091 uint32_t const out = _current_delivery->pan_outs();
2093 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2094 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2095 panner_ui().setup_pan ();
2096 panner_ui().set_send_drawing_mode (true);
2097 panner_ui().show_all ();
2099 input_button.set_sensitive (false);
2100 group_button.set_sensitive (false);
2101 set_invert_sensitive (false);
2102 meter_point_button.set_sensitive (false);
2103 mute_button->set_sensitive (false);
2104 solo_button->set_sensitive (false);
2105 rec_enable_button->set_sensitive (false);
2106 solo_isolated_led->set_sensitive (false);
2107 solo_safe_led->set_sensitive (false);
2108 monitor_input_button->set_sensitive (false);
2109 monitor_disk_button->set_sensitive (false);
2110 _comment_button.set_sensitive (false);
2112 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2113 output_button.set_sensitive (false);
2116 reset_strip_style ();
2120 MixerStrip::revert_to_default_display ()
2124 set_current_delivery (_route->main_outs ());
2126 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2127 gain_meter().setup_meters ();
2129 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2130 update_panner_choices();
2131 panner_ui().setup_pan ();
2132 panner_ui().set_send_drawing_mode (false);
2134 if (has_audio_outputs ()) {
2135 panners.show_all ();
2137 panners.hide_all ();
2140 reset_strip_style ();
2144 MixerStrip::set_button_names ()
2148 mute_button->set_text (_("Mute"));
2149 monitor_input_button->set_text (_("In"));
2150 monitor_disk_button->set_text (_("Disk"));
2151 if (monitor_section_button) {
2152 monitor_section_button->set_text (_("Mon"));
2155 if (_route && _route->solo_safe_control()->solo_safe()) {
2156 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2158 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2160 if (!Config->get_solo_control_is_listen_control()) {
2161 solo_button->set_text (_("Solo"));
2163 switch (Config->get_listen_position()) {
2164 case AfterFaderListen:
2165 solo_button->set_text (_("AFL"));
2167 case PreFaderListen:
2168 solo_button->set_text (_("PFL"));
2172 solo_isolated_led->set_text (_("Iso"));
2173 solo_safe_led->set_text (S_("SoloLock|Lock"));
2177 mute_button->set_text (S_("Mute|M"));
2178 monitor_input_button->set_text (S_("MonitorInput|I"));
2179 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2180 if (monitor_section_button) {
2181 monitor_section_button->set_text (S_("Mon|O"));
2184 if (_route && _route->solo_safe_control()->solo_safe()) {
2185 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2187 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2189 if (!Config->get_solo_control_is_listen_control()) {
2190 solo_button->set_text (S_("Solo|S"));
2192 switch (Config->get_listen_position()) {
2193 case AfterFaderListen:
2194 solo_button->set_text (S_("AfterFader|A"));
2196 case PreFaderListen:
2197 solo_button->set_text (S_("Prefader|P"));
2202 solo_isolated_led->set_text (S_("SoloIso|I"));
2203 solo_safe_led->set_text (S_("SoloLock|L"));
2208 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2210 meter_point_button.set_text ("");
2215 MixerStrip::plugin_selector()
2217 return _mixer.plugin_selector();
2221 MixerStrip::hide_things ()
2223 processor_box.hide_things ();
2227 MixerStrip::input_active_button_press (GdkEventButton*)
2229 /* nothing happens on press */
2234 MixerStrip::input_active_button_release (GdkEventButton* ev)
2236 boost::shared_ptr<MidiTrack> mt = midi_track ();
2242 boost::shared_ptr<RouteList> rl (new RouteList);
2244 rl->push_back (route());
2246 _session->set_exclusive_input_active (rl, !mt->input_active(),
2247 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2253 MixerStrip::midi_input_status_changed ()
2255 if (midi_input_enable_button) {
2256 boost::shared_ptr<MidiTrack> mt = midi_track ();
2258 midi_input_enable_button->set_active (mt->input_active ());
2263 MixerStrip::state_id () const
2265 return string_compose ("strip %1", _route->id().to_s());
2269 MixerStrip::parameter_changed (string p)
2271 if (p == _visibility.get_state_name()) {
2272 /* The user has made changes to the mixer strip visibility, so get
2273 our VisibilityGroup to reflect these changes in our widgets.
2275 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2276 } else if (p == "track-name-number") {
2278 } else if (p == "use-monitor-bus") {
2279 if (monitor_section_button) {
2280 if (mute_button->get_parent()) {
2281 mute_button->get_parent()->remove(*mute_button);
2283 if (monitor_section_button->get_parent()) {
2284 monitor_section_button->get_parent()->remove(*monitor_section_button);
2286 if (Config->get_use_monitor_bus ()) {
2287 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2288 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2289 mute_button->show();
2290 monitor_section_button->show();
2292 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2293 mute_button->show();
2296 } else if (p == "track-name-number") {
2297 update_track_number_visibility();
2301 /** Called to decide whether the solo isolate / solo lock button visibility should
2302 * be overridden from that configured by the user. We do this for the master bus.
2304 * @return optional value that is present if visibility state should be overridden.
2306 boost::optional<bool>
2307 MixerStrip::override_solo_visibility () const
2309 if (_route && _route->is_master ()) {
2310 return boost::optional<bool> (false);
2313 return boost::optional<bool> ();
2317 MixerStrip::add_input_port (DataType t)
2319 _route->input()->add_port ("", this, t);
2323 MixerStrip::add_output_port (DataType t)
2325 _route->output()->add_port ("", this, t);
2329 MixerStrip::route_active_changed ()
2331 reset_strip_style ();
2335 MixerStrip::copy_processors ()
2337 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2341 MixerStrip::cut_processors ()
2343 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2347 MixerStrip::paste_processors ()
2349 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2353 MixerStrip::select_all_processors ()
2355 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2359 MixerStrip::deselect_all_processors ()
2361 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2365 MixerStrip::delete_processors ()
2367 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2371 MixerStrip::toggle_processors ()
2373 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2377 MixerStrip::ab_plugins ()
2379 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2383 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2385 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2388 if (ev->button == 3) {
2389 popup_level_meter_menu (ev);
2397 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2399 using namespace Gtk::Menu_Helpers;
2401 Gtk::Menu* m = manage (new Menu);
2402 MenuList& items = m->items ();
2404 RadioMenuItem::Group group;
2406 _suspend_menu_callbacks = true;
2407 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2408 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2409 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2410 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2411 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2413 if (gpm.meter_channels().n_audio() == 0) {
2414 m->popup (ev->button, ev->time);
2415 _suspend_menu_callbacks = false;
2419 RadioMenuItem::Group tgroup;
2420 items.push_back (SeparatorElem());
2422 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2423 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2424 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2425 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2426 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2427 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2428 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2429 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2430 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2431 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2432 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2435 if (_route->is_master()) {
2438 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2439 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2440 /* non-master bus */
2443 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2450 MeterType cmt = _route->meter_type();
2451 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2453 items.push_back (SeparatorElem());
2454 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2455 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2456 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2457 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2458 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2459 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2461 m->popup (ev->button, ev->time);
2462 _suspend_menu_callbacks = false;
2466 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2467 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2469 using namespace Menu_Helpers;
2471 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2472 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2473 i->set_active (_route->meter_point() == point);
2477 MixerStrip::set_meter_point (MeterPoint p)
2479 if (_suspend_menu_callbacks) return;
2480 _route->set_meter_point (p);
2484 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2485 RadioMenuItem::Group& group, string const & name, MeterType type)
2487 using namespace Menu_Helpers;
2489 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2490 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2491 i->set_active (_route->meter_type() == type);
2495 MixerStrip::set_meter_type (MeterType t)
2497 if (_suspend_menu_callbacks) return;
2502 MixerStrip::update_track_number_visibility ()
2504 DisplaySuspender ds;
2505 bool show_label = _session->config.get_track_name_number();
2507 if (_route && _route->is_master()) {
2512 number_label.show ();
2513 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2514 // except the width of the number label is subtracted from the name-hbox, so we
2515 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2516 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2518 number_label.set_size_request(tnw, -1);
2519 number_label.show ();
2521 number_label.hide ();
2526 MixerStrip::color () const
2528 return route_color ();
2532 MixerStrip::marked_for_display () const
2534 return !_route->presentation_info().hidden();
2538 MixerStrip::set_marked_for_display (bool yn)
2540 return RouteUI::mark_hidden (!yn);