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)
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"))
110 /* the editor mixer strip: don't destroy it every time
111 the underlying route goes away.
114 self_destruct = false;
118 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
122 , _mixer_owned (in_mixer)
123 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
126 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
127 , rec_mon_table (2, 2)
128 , solo_iso_table (1, 2)
129 , mute_solo_table (1, 2)
130 , bottom_button_table (1, 3)
131 , meter_point_button (_("pre"))
132 , monitor_section_button (0)
133 , midi_input_enable_button (0)
134 , _comment_button (_("Comments"))
135 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
136 , _visibility (X_("mixer-element-visibility"))
145 _entered_mixer_strip= 0;
148 ignore_comment_edit = false;
149 ignore_toggle = false;
154 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
155 longest_label = "longest label";
157 string t = _("Click to toggle the width of this mixer strip.");
159 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
162 width_button.set_icon (ArdourIcon::StripWidth);
163 set_tooltip (width_button, t);
165 hide_button.set_icon (ArdourIcon::CloseCross);
166 set_tooltip (&hide_button, _("Hide this mixer strip"));
168 input_button_box.set_spacing(2);
170 input_button.set_text (_("Input"));
171 input_button.set_name ("mixer strip button");
172 input_button_box.pack_start (input_button, true, true);
174 output_button.set_text (_("Output"));
175 output_button.set_name ("mixer strip button");
177 set_tooltip (&meter_point_button, _("Click to select metering point"));
178 meter_point_button.set_name ("mixer strip button");
180 bottom_button_table.attach (meter_point_button, 2, 3, 0, 1);
182 meter_point_button.signal_button_press_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_press), false);
183 meter_point_button.signal_button_release_event().connect (sigc::mem_fun (gpm, &GainMeter::meter_release), false);
185 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
187 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
188 solo_isolated_led->show ();
189 solo_isolated_led->set_no_show_all (true);
190 solo_isolated_led->set_name (X_("solo isolate"));
191 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
192 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
193 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
195 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
196 solo_safe_led->show ();
197 solo_safe_led->set_no_show_all (true);
198 solo_safe_led->set_name (X_("solo safe"));
199 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
200 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
201 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
203 solo_safe_led->set_text (S_("SoloLock|Lock"));
204 solo_isolated_led->set_text (_("Iso"));
206 solo_iso_table.set_homogeneous (true);
207 solo_iso_table.set_spacings (2);
208 if (!ARDOUR::Profile->get_trx()) {
209 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
210 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
212 solo_iso_table.show ();
214 vca_button = manage (new ArdourButton (ArdourButton::default_elements));
215 vca_button->set_no_show_all (true);
216 vca_button->set_name (X_("vca assign"));
217 vca_button->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
218 vca_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::vca_button_release), false);
219 UI::instance()->set_tip (*vca_button, _("VCA assignments"));
220 vca_button->set_text (_("-vca-"));
223 rec_mon_table.set_homogeneous (true);
224 rec_mon_table.set_row_spacings (2);
225 rec_mon_table.set_col_spacings (2);
226 if (ARDOUR::Profile->get_mixbus()) {
227 rec_mon_table.resize (1, 3);
228 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
229 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
230 } else if (!ARDOUR::Profile->get_trx()) {
231 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
232 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
234 rec_mon_table.show ();
236 if (solo_isolated_led) {
237 button_size_group->add_widget (*solo_isolated_led);
240 button_size_group->add_widget (*solo_safe_led);
243 if (!ARDOUR::Profile->get_mixbus()) {
244 if (rec_enable_button) {
245 button_size_group->add_widget (*rec_enable_button);
247 if (monitor_disk_button) {
248 button_size_group->add_widget (*monitor_disk_button);
250 if (monitor_input_button) {
251 button_size_group->add_widget (*monitor_input_button);
255 mute_solo_table.set_homogeneous (true);
256 mute_solo_table.set_spacings (2);
258 bottom_button_table.set_spacings (2);
259 bottom_button_table.set_homogeneous (true);
260 bottom_button_table.attach (group_button, 1, 2, 0, 1);
261 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
263 name_button.set_name ("mixer strip button");
264 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
265 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
267 set_tooltip (&group_button, _("Mix group"));
268 group_button.set_name ("mixer strip button");
270 _comment_button.set_name (X_("mixer strip button"));
271 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
273 // TODO implement ArdourKnob::on_size_request properly
274 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
275 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
277 trim_control.set_tooltip_prefix (_("Trim: "));
278 trim_control.set_name ("trim knob");
279 trim_control.set_no_show_all (true);
280 input_button_box.pack_start (trim_control, false, false);
282 global_vpacker.set_border_width (1);
283 global_vpacker.set_spacing (0);
285 width_button.set_name ("mixer strip button");
286 hide_button.set_name ("mixer strip button");
288 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
289 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
291 // width_hide_box.set_border_width (1);
292 width_hide_box.set_spacing (2);
293 width_hide_box.pack_start (width_button, false, true);
294 width_hide_box.pack_start (number_label, true, true);
295 width_hide_box.pack_end (hide_button, false, true);
297 number_label.set_text ("-");
298 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
299 number_label.set_no_show_all ();
300 number_label.set_name ("tracknumber label");
301 number_label.set_fixed_colors (0x80808080, 0x80808080);
302 number_label.set_alignment (.5, .5);
303 number_label.set_fallthrough_to_parent (true);
305 global_vpacker.set_spacing (2);
306 if (!ARDOUR::Profile->get_trx()) {
307 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (processor_box, true, true);
313 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
318 global_vpacker.pack_start (*vca_button, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
320 if (!ARDOUR::Profile->get_trx()) {
321 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
322 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
324 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
327 global_frame.add (global_vpacker);
328 global_frame.set_shadow_type (Gtk::SHADOW_IN);
329 global_frame.set_name ("BaseFrame");
333 /* force setting of visible selected status */
336 set_selected (false);
341 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
342 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
344 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
345 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
346 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
348 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
349 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
351 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
352 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
353 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
355 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
357 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
358 name_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_release), false);
360 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
364 /* start off as a passthru strip. we'll correct this, if necessary,
365 in update_diskstream_display().
368 /* start off as a passthru strip. we'll correct this, if necessary,
369 in update_diskstream_display().
372 if (is_midi_track()) {
373 set_name ("MidiTrackStripBase");
375 set_name ("AudioTrackStripBase");
378 add_events (Gdk::BUTTON_RELEASE_MASK|
379 Gdk::ENTER_NOTIFY_MASK|
380 Gdk::LEAVE_NOTIFY_MASK|
382 Gdk::KEY_RELEASE_MASK);
384 set_flags (get_flags() | Gtk::CAN_FOCUS);
386 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
387 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
390 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
391 must be the same as those used in RCOptionEditor so that the configuration changes
392 are recognised when they occur.
394 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
395 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
396 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
397 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
398 _visibility.add (&output_button, X_("Output"), _("Output"), false);
399 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
400 _visibility.add (vca_button, X_("VCA"), _("VCA Assigns"), false);
402 parameter_changed (X_("mixer-element-visibility"));
403 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
404 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
405 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
407 //watch for mouse enter/exit so we can do some stuff
408 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
409 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
411 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
414 MixerStrip::~MixerStrip ()
416 CatchDeletion (this);
418 if (this ==_entered_mixer_strip)
419 _entered_mixer_strip = NULL;
423 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
425 _entered_mixer_strip = this;
427 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
428 //because the mixerstrip control is a parent that encompasses the strip
429 deselect_all_processors();
435 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
437 //if we have moved outside our strip, but not into a child view, then deselect ourselves
438 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
439 _entered_mixer_strip= 0;
441 //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
442 gpm.gain_display.set_sensitive(false);
444 gpm.gain_display.set_sensitive(true);
446 //if we leave this mixer strip we need to clear out any selections
447 //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
454 MixerStrip::set_route (boost::shared_ptr<Route> rt)
456 //the rec/monitor stuff only shows up for tracks.
457 //the show_sends only shows up for buses.
458 //remove them all here, and we may add them back later
459 if (show_sends_button->get_parent()) {
460 rec_mon_table.remove (*show_sends_button);
462 if (rec_enable_button->get_parent()) {
463 rec_mon_table.remove (*rec_enable_button);
465 if (monitor_input_button->get_parent()) {
466 rec_mon_table.remove (*monitor_input_button);
468 if (monitor_disk_button->get_parent()) {
469 rec_mon_table.remove (*monitor_disk_button);
471 if (group_button.get_parent()) {
472 bottom_button_table.remove (group_button);
475 RouteUI::set_route (rt);
477 /* ProcessorBox needs access to _route so that it can read
480 processor_box.set_route (rt);
482 revert_to_default_display ();
484 /* unpack these from the parent and stuff them into our own
488 if (gpm.peak_display.get_parent()) {
489 gpm.peak_display.get_parent()->remove (gpm.peak_display);
491 if (gpm.gain_display.get_parent()) {
492 gpm.gain_display.get_parent()->remove (gpm.gain_display);
495 gpm.set_type (rt->meter_type());
497 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
498 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
500 if (solo_button->get_parent()) {
501 mute_solo_table.remove (*solo_button);
504 if (mute_button->get_parent()) {
505 mute_solo_table.remove (*mute_button);
508 if (route()->is_master()) {
509 solo_button->hide ();
510 mute_button->show ();
511 rec_mon_table.hide ();
512 if (solo_iso_table.get_parent()) {
513 solo_iso_table.get_parent()->remove(solo_iso_table);
515 if (monitor_section_button == 0) {
516 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
517 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
519 monitor_section_button = manage (new ArdourButton);
521 monitor_section_button->set_related_action (act);
522 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
523 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
524 monitor_section_button->show();
525 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
527 parameter_changed ("use-monitor-bus");
529 bottom_button_table.attach (group_button, 1, 2, 0, 1);
530 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
531 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
532 mute_button->show ();
533 solo_button->show ();
534 rec_mon_table.show ();
537 if (_mixer_owned && route()->is_master() ) {
539 HScrollbar scrollbar;
540 Gtk::Requisition requisition(scrollbar.size_request ());
541 int scrollbar_height = requisition.height;
543 spacer = manage (new EventBox);
544 spacer->set_size_request (-1, scrollbar_height+2);
545 global_vpacker.pack_start (*spacer, false, false);
550 monitor_input_button->show ();
551 monitor_disk_button->show ();
553 monitor_input_button->hide();
554 monitor_disk_button->hide ();
557 if (route()->trim() && route()->trim()->active()) {
558 trim_control.show ();
559 trim_control.set_controllable (route()->trim()->gain_control());
561 trim_control.hide ();
562 boost::shared_ptr<Controllable> none;
563 trim_control.set_controllable (none);
566 if (is_midi_track()) {
567 if (midi_input_enable_button == 0) {
568 midi_input_enable_button = manage (new ArdourButton);
569 midi_input_enable_button->set_name ("midi input button");
570 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
571 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
572 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
573 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
574 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
576 input_button_box.remove (*midi_input_enable_button);
578 /* get current state */
579 midi_input_status_changed ();
580 input_button_box.pack_start (*midi_input_enable_button, false, false);
582 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
584 if (midi_input_enable_button) {
585 /* removal from the container will delete it */
586 input_button_box.remove (*midi_input_enable_button);
587 midi_input_enable_button = 0;
591 if (is_audio_track()) {
592 boost::shared_ptr<AudioTrack> at = audio_track();
593 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
598 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
599 rec_enable_button->show();
601 if (ARDOUR::Profile->get_mixbus()) {
602 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
603 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
604 } else if (ARDOUR::Profile->get_trx()) {
605 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
607 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
608 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
615 if (!_route->is_master()) {
616 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
617 show_sends_button->show();
621 meter_point_button.set_text (meter_point_string (_route->meter_point()));
623 delete route_ops_menu;
626 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
627 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
628 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
629 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
631 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
633 if (_route->panner_shell()) {
634 update_panner_choices();
635 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
638 if (is_audio_track()) {
639 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
642 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
643 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::property_changed, this, _1), gui_context());
645 _route->gain_control()->MasterStatusChange.connect (route_connections,
647 boost::bind (&MixerStrip::update_vca_display, this),
650 set_stuff_from_route ();
652 /* now force an update of all the various elements */
654 update_mute_display ();
655 update_solo_display ();
656 update_vca_display ();
659 route_group_changed ();
660 update_track_number_visibility ();
663 panners.setup_pan ();
665 if (has_audio_outputs ()) {
671 update_diskstream_display ();
672 update_input_display ();
673 update_output_display ();
675 add_events (Gdk::BUTTON_RELEASE_MASK);
677 processor_box.show ();
679 if (!route()->is_master() && !route()->is_monitor()) {
680 /* we don't allow master or control routes to be hidden */
685 gpm.reset_peak_display ();
686 gpm.gain_display.show ();
687 gpm.peak_display.show ();
690 width_hide_box.show();
692 global_vpacker.show();
693 mute_solo_table.show();
694 bottom_button_table.show();
696 meter_point_button.show();
697 input_button_box.show_all();
698 output_button.show();
700 _comment_button.show();
702 gpm.gain_automation_state_button.show();
704 parameter_changed ("mixer-element-visibility");
711 MixerStrip::set_stuff_from_route ()
713 /* if width is not set, it will be set by the MixerUI or editor */
715 string str = gui_property ("strip-width");
717 set_width_enum (Width (string_2_enum (str, _width)), this);
722 MixerStrip::set_width_enum (Width w, void* owner)
724 /* always set the gpm width again, things may be hidden */
727 panners.set_width (w);
729 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
731 _width_owner = owner;
735 if (_width_owner == this) {
736 set_gui_property ("strip-width", enum_2_string (_width));
741 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
746 if (show_sends_button) {
747 show_sends_button->set_text (_("Aux"));
750 gpm.gain_automation_style_button.set_text (
751 gpm.astyle_string(gain_automation->automation_style()));
752 gpm.gain_automation_state_button.set_text (
753 gpm.astate_string(gain_automation->automation_state()));
755 if (_route->panner()) {
756 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
757 panners.astyle_string(_route->panner()->automation_style()));
758 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
759 panners.astate_string(_route->panner()->automation_state()));
763 // panners expect an even number of horiz. pixels
764 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
766 set_size_request (width, -1);
772 if (show_sends_button) {
773 show_sends_button->set_text (_("Snd"));
776 gpm.gain_automation_style_button.set_text (
777 gpm.short_astyle_string(gain_automation->automation_style()));
778 gpm.gain_automation_state_button.set_text (
779 gpm.short_astate_string(gain_automation->automation_state()));
780 gain_meter().setup_meters (); // recalc meter width
782 if (_route->panner()) {
783 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
784 panners.short_astyle_string(_route->panner()->automation_style()));
785 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
786 panners.short_astate_string(_route->panner()->automation_state()));
790 // panners expect an even number of horiz. pixels
791 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
793 set_size_request (width, -1);
798 processor_box.set_width (w);
800 update_input_display ();
801 update_output_display ();
802 setup_comment_button ();
803 route_group_changed ();
809 MixerStrip::set_packed (bool yn)
814 set_gui_property ("visible", true);
816 set_gui_property ("visible", false);
821 struct RouteCompareByName {
822 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
823 return a->name().compare (b->name()) < 0;
828 MixerStrip::output_release (GdkEventButton *ev)
830 switch (ev->button) {
832 edit_output_configuration ();
840 MixerStrip::output_press (GdkEventButton *ev)
842 using namespace Menu_Helpers;
843 if (!_session->engine().connected()) {
844 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
849 MenuList& citems = output_menu.items();
850 switch (ev->button) {
853 return false; //wait for the mouse-up to pop the dialog
857 output_menu.set_name ("ArdourContextMenu");
859 output_menu_bundles.clear ();
861 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
863 citems.push_back (SeparatorElem());
864 uint32_t const n_with_separator = citems.size ();
866 ARDOUR::BundleList current = _route->output()->bundles_connected ();
868 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
870 /* give user bundles first chance at being in the menu */
872 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
873 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
874 maybe_add_bundle_to_output_menu (*i, current);
878 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
879 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
880 maybe_add_bundle_to_output_menu (*i, current);
884 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
885 RouteList copy = *routes;
886 copy.sort (RouteCompareByName ());
887 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
888 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
891 if (citems.size() == n_with_separator) {
892 /* no routes added; remove the separator */
896 if (!ARDOUR::Profile->get_mixbus()) {
897 citems.push_back (SeparatorElem());
899 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
902 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
903 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
909 citems.push_back (SeparatorElem());
910 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
912 output_menu.popup (1, ev->time);
923 MixerStrip::input_release (GdkEventButton *ev)
925 switch (ev->button) {
928 edit_input_configuration ();
940 MixerStrip::input_press (GdkEventButton *ev)
942 using namespace Menu_Helpers;
944 MenuList& citems = input_menu.items();
945 input_menu.set_name ("ArdourContextMenu");
948 if (!_session->engine().connected()) {
949 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
954 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
957 switch (ev->button) {
960 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
964 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
966 citems.push_back (SeparatorElem());
967 uint32_t const n_with_separator = citems.size ();
969 input_menu_bundles.clear ();
971 ARDOUR::BundleList current = _route->input()->bundles_connected ();
973 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
975 /* give user bundles first chance at being in the menu */
977 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
978 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
979 maybe_add_bundle_to_input_menu (*i, current);
983 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
984 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
985 maybe_add_bundle_to_input_menu (*i, current);
989 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
990 RouteList copy = *routes;
991 copy.sort (RouteCompareByName ());
992 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
993 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
996 if (citems.size() == n_with_separator) {
997 /* no routes added; remove the separator */
1001 citems.push_back (SeparatorElem());
1002 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1005 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1006 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1011 citems.push_back (SeparatorElem());
1012 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1014 input_menu.popup (1, ev->time);
1025 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1027 if (ignore_toggle) {
1031 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1033 if (std::find (current.begin(), current.end(), c) == current.end()) {
1034 _route->input()->connect_ports_to_bundle (c, true, this);
1036 _route->input()->disconnect_ports_from_bundle (c, this);
1041 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1043 if (ignore_toggle) {
1047 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1049 if (std::find (current.begin(), current.end(), c) == current.end()) {
1050 _route->output()->connect_ports_to_bundle (c, true, this);
1052 _route->output()->disconnect_ports_from_bundle (c, this);
1057 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1059 using namespace Menu_Helpers;
1061 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1065 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1066 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1070 if (i != input_menu_bundles.end()) {
1074 input_menu_bundles.push_back (b);
1076 MenuList& citems = input_menu.items();
1078 std::string n = b->name ();
1079 replace_all (n, "_", " ");
1081 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1085 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1087 using namespace Menu_Helpers;
1089 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1093 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1094 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1098 if (i != output_menu_bundles.end()) {
1102 output_menu_bundles.push_back (b);
1104 MenuList& citems = output_menu.items();
1106 std::string n = b->name ();
1107 replace_all (n, "_", " ");
1109 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1113 MixerStrip::update_diskstream_display ()
1115 if (is_track() && input_selector) {
1116 input_selector->hide_all ();
1119 route_color_changed ();
1123 MixerStrip::connect_to_pan ()
1125 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1127 panstate_connection.disconnect ();
1128 panstyle_connection.disconnect ();
1130 if (!_route->panner()) {
1134 boost::shared_ptr<Pannable> p = _route->pannable ();
1136 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1137 p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1139 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1140 * However, that only works a panner was previously set.
1142 * PannerUI must remain subscribed to _panshell->Changed() in case
1143 * we switch the panner eg. AUX-Send and back
1144 * _route->panner_shell()->Changed() vs _panshell->Changed
1146 if (panners._panner == 0) {
1147 panners.panshell_changed ();
1149 update_panner_choices();
1153 MixerStrip::update_panner_choices ()
1155 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1156 if (!_route->panner_shell()) { return; }
1158 uint32_t in = _route->output()->n_ports().n_audio();
1160 if (_route->panner()) {
1161 in = _route->panner()->in().n_audio();
1164 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1168 * Output port labelling
1169 * =====================
1171 * Case 1: Each output has one connection, all connections are to system:playback_%i
1172 * out 1 -> system:playback_1
1173 * out 2 -> system:playback_2
1174 * out 3 -> system:playback_3
1177 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1178 * out 1 -> ardour:track_x/in 1
1179 * out 2 -> ardour:track_x/in 2
1180 * Display as: track_x
1182 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1183 * out 1 -> program x:foo
1184 * out 2 -> program x:foo
1185 * Display as: program x
1187 * Case 4: No connections (Disconnected)
1190 * Default case (unusual routing):
1191 * Display as: *number of connections*
1195 * .-----------------------------------------------.
1197 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1198 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1199 * '-----------------------------------------------'
1200 * .-----------------------------------------------.
1203 * '-----------------------------------------------'
1207 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1211 boost::shared_ptr<Port> port;
1212 vector<string> port_connections;
1214 uint32_t total_connection_count = 0;
1215 uint32_t io_connection_count = 0;
1216 uint32_t ardour_connection_count = 0;
1217 uint32_t system_connection_count = 0;
1218 uint32_t other_connection_count = 0;
1219 uint32_t typed_connection_count = 0;
1221 ostringstream label;
1223 bool have_label = false;
1224 bool each_io_has_one_connection = true;
1226 string connection_name;
1227 string ardour_track_name;
1228 string other_connection_type;
1229 string system_ports;
1232 ostringstream tooltip;
1233 char * tooltip_cstr;
1235 //to avoid confusion, the button caption should only show connections that match the datatype of the track
1236 DataType dt = DataType::AUDIO;
1237 if ( boost::dynamic_pointer_cast<MidiTrack>(route) != 0 ) {
1238 dt = DataType::MIDI;
1239 // avoid further confusion with Midi-tracks that have a synth.
1240 // Audio-ports may be connected, but button says "Disconnected"
1241 tooltip << _("MIDI ");
1245 io_count = route->n_inputs().n_total();
1246 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1248 io_count = route->n_outputs().n_total();
1249 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1253 for (io_index = 0; io_index < io_count; ++io_index) {
1255 port = route->input()->nth (io_index);
1257 port = route->output()->nth (io_index);
1260 port_connections.clear ();
1261 port->get_connections(port_connections);
1263 //ignore any port connections that don't match our DataType
1264 if (port->type() != dt) {
1265 if (!port_connections.empty()) {
1266 ++typed_connection_count;
1271 io_connection_count = 0;
1273 if (!port_connections.empty()) {
1274 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1276 string& connection_name (*i);
1278 if (connection_name.find("system:") == 0) {
1279 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1282 if (io_connection_count == 0) {
1283 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1285 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1288 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1291 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1292 if (ardour_track_name.empty()) {
1293 // "ardour:Master/in 1" -> "ardour:Master/"
1294 string::size_type slash = connection_name.find("/");
1295 if (slash != string::npos) {
1296 ardour_track_name = connection_name.substr(0, slash + 1);
1300 if (connection_name.find(ardour_track_name) == 0) {
1301 ++ardour_connection_count;
1303 } else if (!pn.empty()) {
1304 if (system_ports.empty()) {
1307 system_ports += "/" + pn;
1309 if (connection_name.find("system:") == 0) {
1310 ++system_connection_count;
1312 } else if (connection_name.find("system:midi_") == 0) {
1314 // "system:midi_capture_123" -> "123"
1315 system_port = "M " + connection_name.substr(20);
1317 // "system:midi_playback_123" -> "123"
1318 system_port = "M " + connection_name.substr(21);
1321 if (system_ports.empty()) {
1322 system_ports += system_port;
1324 system_ports += "/" + system_port;
1327 ++system_connection_count;
1329 } else if (connection_name.find("system:") == 0) {
1331 // "system:capture_123" -> "123"
1332 system_port = connection_name.substr(15);
1334 // "system:playback_123" -> "123"
1335 system_port = connection_name.substr(16);
1338 if (system_ports.empty()) {
1339 system_ports += system_port;
1341 system_ports += "/" + system_port;
1344 ++system_connection_count;
1346 if (other_connection_type.empty()) {
1347 // "jamin:in 1" -> "jamin:"
1348 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1351 if (connection_name.find(other_connection_type) == 0) {
1352 ++other_connection_count;
1356 ++total_connection_count;
1357 ++io_connection_count;
1361 if (io_connection_count != 1) {
1362 each_io_has_one_connection = false;
1366 if (total_connection_count == 0) {
1367 tooltip << endl << _("Disconnected");
1370 tooltip_cstr = new char[tooltip.str().size() + 1];
1371 strcpy(tooltip_cstr, tooltip.str().c_str());
1374 set_tooltip (&input_button, tooltip_cstr);
1376 set_tooltip (&output_button, tooltip_cstr);
1379 delete [] tooltip_cstr;
1381 if (each_io_has_one_connection) {
1382 if (total_connection_count == ardour_connection_count) {
1383 // all connections are to the same track in ardour
1384 // "ardour:Master/" -> "Master"
1385 string::size_type slash = ardour_track_name.find("/");
1386 if (slash != string::npos) {
1387 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1388 label << ardour_track_name.substr (ppps, slash - ppps);
1392 else if (total_connection_count == system_connection_count) {
1393 // all connections are to system ports
1394 label << system_ports;
1397 else if (total_connection_count == other_connection_count) {
1398 // all connections are to the same external program eg jamin
1399 // "jamin:" -> "jamin"
1400 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1406 if (total_connection_count == 0) {
1410 // Odd configuration
1411 label << "*" << total_connection_count << "*";
1413 if (typed_connection_count > 0) {
1414 label << "\u2295"; // circled plus
1419 input_button.set_text (label.str());
1421 output_button.set_text (label.str());
1426 MixerStrip::update_input_display ()
1428 update_io_button (_route, _width, true);
1429 panners.setup_pan ();
1431 if (has_audio_outputs ()) {
1432 panners.show_all ();
1434 panners.hide_all ();
1440 MixerStrip::update_output_display ()
1442 update_io_button (_route, _width, false);
1443 gpm.setup_meters ();
1444 panners.setup_pan ();
1446 if (has_audio_outputs ()) {
1447 panners.show_all ();
1449 panners.hide_all ();
1454 MixerStrip::fast_update ()
1456 gpm.update_meters ();
1460 MixerStrip::diskstream_changed ()
1462 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1466 MixerStrip::io_changed_proxy ()
1468 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1472 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1474 boost::shared_ptr<Port> a = wa.lock ();
1475 boost::shared_ptr<Port> b = wb.lock ();
1477 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1478 update_input_display ();
1479 set_width_enum (_width, this);
1482 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1483 update_output_display ();
1484 set_width_enum (_width, this);
1489 MixerStrip::setup_comment_button ()
1494 if (_route->comment().empty ()) {
1495 _comment_button.unset_bg (STATE_NORMAL);
1496 _comment_button.set_text (_("Comments"));
1498 _comment_button.modify_bg (STATE_NORMAL, color ());
1499 _comment_button.set_text (_("*Comments*"));
1504 if (_route->comment().empty ()) {
1505 _comment_button.unset_bg (STATE_NORMAL);
1506 _comment_button.set_text (_("Cmt"));
1508 _comment_button.modify_bg (STATE_NORMAL, color ());
1509 _comment_button.set_text (_("*Cmt*"));
1515 _comment_button, _route->comment().empty() ? _("Click to add/edit comments") : _route->comment()
1521 MixerStrip::select_route_group (GdkEventButton *ev)
1523 using namespace Menu_Helpers;
1525 if (ev->button == 1) {
1527 if (group_menu == 0) {
1529 PropertyList* plist = new PropertyList();
1531 plist->add (Properties::gain, true);
1532 plist->add (Properties::mute, true);
1533 plist->add (Properties::solo, true);
1535 group_menu = new RouteGroupMenu (_session, plist);
1539 r.push_back (route ());
1540 group_menu->build (r);
1541 group_menu->menu()->popup (1, ev->time);
1548 MixerStrip::route_group_changed ()
1550 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1552 RouteGroup *rg = _route->route_group();
1555 group_button.set_text (PBD::short_version (rg->name(), 5));
1559 group_button.set_text (_("Grp"));
1562 group_button.set_text (_("~G"));
1569 MixerStrip::route_color_changed ()
1571 name_button.modify_bg (STATE_NORMAL, color());
1572 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1573 reset_strip_style ();
1577 MixerStrip::show_passthru_color ()
1579 reset_strip_style ();
1584 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1586 boost::shared_ptr<Processor> processor (p.lock ());
1587 if (!processor || !processor->display_to_user()) {
1590 if (boost::dynamic_pointer_cast<PluginInsert> (processor)) {
1591 ++_plugin_insert_cnt;
1595 MixerStrip::build_route_ops_menu ()
1597 using namespace Menu_Helpers;
1598 route_ops_menu = new Menu;
1599 route_ops_menu->set_name ("ArdourContextMenu");
1601 MenuList& items = route_ops_menu->items();
1603 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1605 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1607 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1609 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1611 items.push_back (SeparatorElem());
1613 if (!_route->is_master()) {
1614 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1616 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1617 rename_menu_item = &items.back();
1619 items.push_back (SeparatorElem());
1620 items.push_back (CheckMenuElem (_("Active")));
1621 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1622 i->set_active (_route->active());
1623 i->set_sensitive(! _session->transport_rolling());
1624 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1626 if (!Profile->get_mixbus ()) {
1627 items.push_back (SeparatorElem());
1628 items.push_back (CheckMenuElem (_("Strict I/O")));
1629 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1630 i->set_active (_route->strict_io());
1631 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1634 _plugin_insert_cnt = 0;
1635 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1636 if (_plugin_insert_cnt > 0) {
1637 items.push_back (SeparatorElem());
1638 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1641 items.push_back (SeparatorElem());
1642 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1644 items.push_back (SeparatorElem());
1645 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1646 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1647 denormal_menu_item->set_active (_route->denormal_protection());
1650 /* note that this relies on selection being shared across editor and
1651 mixer (or global to the backend, in the future), which is the only
1652 sane thing for users anyway.
1655 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1657 Selection& selection (PublicEditor::instance().get_selection());
1658 if (!selection.selected (rtav)) {
1659 selection.set (rtav);
1662 if (!_route->is_master()) {
1663 items.push_back (SeparatorElem());
1664 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1667 items.push_back (SeparatorElem());
1668 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1674 MixerStrip::name_button_button_press (GdkEventButton* ev)
1676 if (ev->button == 3) {
1677 list_route_operations ();
1679 /* do not allow rename if the track is record-enabled */
1680 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1681 route_ops_menu->popup (1, ev->time);
1690 MixerStrip::name_button_button_release (GdkEventButton* ev)
1692 if (ev->button == 1) {
1693 list_route_operations ();
1695 /* do not allow rename if the track is record-enabled */
1696 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1697 route_ops_menu->popup (1, ev->time);
1704 MixerStrip::number_button_button_press (GdkEventButton* ev)
1706 if ( ev->button == 3 ) {
1707 list_route_operations ();
1709 /* do not allow rename if the track is record-enabled */
1710 rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1711 route_ops_menu->popup (1, ev->time);
1720 MixerStrip::list_route_operations ()
1722 delete route_ops_menu;
1723 build_route_ops_menu ();
1727 MixerStrip::set_selected (bool yn)
1729 AxisView::set_selected (yn);
1731 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1732 global_frame.set_name ("MixerStripSelectedFrame");
1734 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1735 global_frame.set_name ("MixerStripFrame");
1737 global_frame.queue_draw ();
1740 // processor_box.deselect_all_processors();
1744 MixerStrip::property_changed (const PropertyChange& what_changed)
1746 RouteUI::property_changed (what_changed);
1748 if (what_changed.contains (ARDOUR::Properties::name)) {
1754 MixerStrip::name_changed ()
1758 name_button.set_text (_route->name());
1761 name_button.set_text (PBD::short_version (_route->name(), 5));
1765 set_tooltip (name_button, _route->name());
1767 if (_session->config.get_track_name_number()) {
1768 const int64_t track_number = _route->track_number ();
1769 if (track_number == 0) {
1770 number_label.set_text ("-");
1772 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1775 number_label.set_text ("");
1780 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1782 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1786 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1788 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1792 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1794 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1798 MixerStrip::width_button_pressed (GdkEventButton* ev)
1800 if (ev->button != 1) {
1804 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1807 _mixer.set_strip_width (Narrow, true);
1811 _mixer.set_strip_width (Wide, true);
1817 set_width_enum (Narrow, this);
1820 set_width_enum (Wide, this);
1829 MixerStrip::hide_clicked ()
1831 // LAME fix to reset the button status for when it is redisplayed (part 1)
1832 hide_button.set_sensitive(false);
1835 Hiding(); /* EMIT_SIGNAL */
1837 _mixer.hide_strip (this);
1841 hide_button.set_sensitive(true);
1845 MixerStrip::set_embedded (bool yn)
1851 MixerStrip::map_frozen ()
1853 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1855 boost::shared_ptr<AudioTrack> at = audio_track();
1858 switch (at->freeze_state()) {
1859 case AudioTrack::Frozen:
1860 processor_box.set_sensitive (false);
1861 hide_redirect_editors ();
1864 processor_box.set_sensitive (true);
1865 // XXX need some way, maybe, to retoggle redirect editors
1869 processor_box.set_sensitive (true);
1871 RouteUI::map_frozen ();
1875 MixerStrip::hide_redirect_editors ()
1877 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1881 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1883 boost::shared_ptr<Processor> processor (p.lock ());
1888 Gtk::Window* w = processor_box.get_processor_ui (processor);
1896 MixerStrip::reset_strip_style ()
1898 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1900 gpm.set_fader_name ("SendStripBase");
1904 if (is_midi_track()) {
1905 if (_route->active()) {
1906 set_name ("MidiTrackStripBase");
1908 set_name ("MidiTrackStripBaseInactive");
1910 gpm.set_fader_name ("MidiTrackFader");
1911 } else if (is_audio_track()) {
1912 if (_route->active()) {
1913 set_name ("AudioTrackStripBase");
1915 set_name ("AudioTrackStripBaseInactive");
1917 gpm.set_fader_name ("AudioTrackFader");
1919 if (_route->active()) {
1920 set_name ("AudioBusStripBase");
1922 set_name ("AudioBusStripBaseInactive");
1924 gpm.set_fader_name ("AudioBusFader");
1926 /* (no MIDI busses yet) */
1933 MixerStrip::engine_stopped ()
1938 MixerStrip::engine_running ()
1943 MixerStrip::meter_point_string (MeterPoint mp)
1956 case MeterPostFader:
1973 return S_("Meter|In");
1977 return S_("Meter|Pr");
1980 case MeterPostFader:
1981 return S_("Meter|Po");
1985 return S_("Meter|O");
1990 return S_("Meter|C");
1999 /** Called when the monitor-section state */
2001 MixerStrip::monitor_changed ()
2003 assert (monitor_section_button);
2004 if (_session->monitor_active()) {
2005 monitor_section_button->set_name ("master monitor section button active");
2007 monitor_section_button->set_name ("master monitor section button normal");
2011 /** Called when the metering point has changed */
2013 MixerStrip::meter_changed ()
2015 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2016 gpm.setup_meters ();
2017 // reset peak when meter point changes
2018 gpm.reset_peak_display();
2021 /** The bus that we are displaying sends to has changed, or been turned off.
2022 * @param send_to New bus that we are displaying sends to, or 0.
2025 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2027 RouteUI::bus_send_display_changed (send_to);
2030 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2035 revert_to_default_display ();
2038 revert_to_default_display ();
2043 MixerStrip::drop_send ()
2045 boost::shared_ptr<Send> current_send;
2047 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2048 current_send->set_metering (false);
2051 send_gone_connection.disconnect ();
2052 input_button.set_sensitive (true);
2053 output_button.set_sensitive (true);
2054 group_button.set_sensitive (true);
2055 set_invert_sensitive (true);
2056 meter_point_button.set_sensitive (true);
2057 mute_button->set_sensitive (true);
2058 solo_button->set_sensitive (true);
2059 solo_isolated_led->set_sensitive (true);
2060 solo_safe_led->set_sensitive (true);
2061 monitor_input_button->set_sensitive (true);
2062 monitor_disk_button->set_sensitive (true);
2063 _comment_button.set_sensitive (true);
2064 RouteUI::check_rec_enable_sensitivity ();
2065 set_button_names (); // update solo button visual state
2069 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2071 _current_delivery = d;
2072 DeliveryChanged (_current_delivery);
2076 MixerStrip::show_send (boost::shared_ptr<Send> send)
2082 set_current_delivery (send);
2084 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2085 send->set_metering (true);
2086 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2088 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2089 gain_meter().setup_meters ();
2091 uint32_t const in = _current_delivery->pans_required();
2092 uint32_t const out = _current_delivery->pan_outs();
2094 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2095 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2096 panner_ui().setup_pan ();
2097 panner_ui().set_send_drawing_mode (true);
2098 panner_ui().show_all ();
2100 input_button.set_sensitive (false);
2101 group_button.set_sensitive (false);
2102 set_invert_sensitive (false);
2103 meter_point_button.set_sensitive (false);
2104 mute_button->set_sensitive (false);
2105 solo_button->set_sensitive (false);
2106 rec_enable_button->set_sensitive (false);
2107 solo_isolated_led->set_sensitive (false);
2108 solo_safe_led->set_sensitive (false);
2109 monitor_input_button->set_sensitive (false);
2110 monitor_disk_button->set_sensitive (false);
2111 _comment_button.set_sensitive (false);
2113 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2114 output_button.set_sensitive (false);
2117 reset_strip_style ();
2121 MixerStrip::revert_to_default_display ()
2125 set_current_delivery (_route->main_outs ());
2127 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2128 gain_meter().setup_meters ();
2130 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2131 update_panner_choices();
2132 panner_ui().setup_pan ();
2133 panner_ui().set_send_drawing_mode (false);
2135 if (has_audio_outputs ()) {
2136 panners.show_all ();
2138 panners.hide_all ();
2141 reset_strip_style ();
2145 MixerStrip::set_button_names ()
2149 mute_button->set_text (_("Mute"));
2150 monitor_input_button->set_text (_("In"));
2151 monitor_disk_button->set_text (_("Disk"));
2152 if (monitor_section_button) {
2153 monitor_section_button->set_text (_("Mon"));
2156 if (_route && _route->solo_safe_control()->solo_safe()) {
2157 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2159 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2161 if (!Config->get_solo_control_is_listen_control()) {
2162 solo_button->set_text (_("Solo"));
2164 switch (Config->get_listen_position()) {
2165 case AfterFaderListen:
2166 solo_button->set_text (_("AFL"));
2168 case PreFaderListen:
2169 solo_button->set_text (_("PFL"));
2173 solo_isolated_led->set_text (_("Iso"));
2174 solo_safe_led->set_text (S_("SoloLock|Lock"));
2178 mute_button->set_text (S_("Mute|M"));
2179 monitor_input_button->set_text (S_("MonitorInput|I"));
2180 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2181 if (monitor_section_button) {
2182 monitor_section_button->set_text (S_("Mon|O"));
2185 if (_route && _route->solo_safe_control()->solo_safe()) {
2186 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2188 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2190 if (!Config->get_solo_control_is_listen_control()) {
2191 solo_button->set_text (S_("Solo|S"));
2193 switch (Config->get_listen_position()) {
2194 case AfterFaderListen:
2195 solo_button->set_text (S_("AfterFader|A"));
2197 case PreFaderListen:
2198 solo_button->set_text (S_("Prefader|P"));
2203 solo_isolated_led->set_text (S_("SoloIso|I"));
2204 solo_safe_led->set_text (S_("SoloLock|L"));
2209 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2211 meter_point_button.set_text ("");
2216 MixerStrip::plugin_selector()
2218 return _mixer.plugin_selector();
2222 MixerStrip::hide_things ()
2224 processor_box.hide_things ();
2228 MixerStrip::input_active_button_press (GdkEventButton*)
2230 /* nothing happens on press */
2235 MixerStrip::input_active_button_release (GdkEventButton* ev)
2237 boost::shared_ptr<MidiTrack> mt = midi_track ();
2243 boost::shared_ptr<RouteList> rl (new RouteList);
2245 rl->push_back (route());
2247 _session->set_exclusive_input_active (rl, !mt->input_active(),
2248 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2254 MixerStrip::midi_input_status_changed ()
2256 if (midi_input_enable_button) {
2257 boost::shared_ptr<MidiTrack> mt = midi_track ();
2259 midi_input_enable_button->set_active (mt->input_active ());
2264 MixerStrip::state_id () const
2266 return string_compose ("strip %1", _route->id().to_s());
2270 MixerStrip::parameter_changed (string p)
2272 if (p == _visibility.get_state_name()) {
2273 /* The user has made changes to the mixer strip visibility, so get
2274 our VisibilityGroup to reflect these changes in our widgets.
2276 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2277 } else if (p == "track-name-number") {
2279 } else if (p == "use-monitor-bus") {
2280 if (monitor_section_button) {
2281 if (mute_button->get_parent()) {
2282 mute_button->get_parent()->remove(*mute_button);
2284 if (monitor_section_button->get_parent()) {
2285 monitor_section_button->get_parent()->remove(*monitor_section_button);
2287 if (Config->get_use_monitor_bus ()) {
2288 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2289 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2290 mute_button->show();
2291 monitor_section_button->show();
2293 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2294 mute_button->show();
2297 } else if (p == "track-name-number") {
2298 update_track_number_visibility();
2302 /** Called to decide whether the solo isolate / solo lock button visibility should
2303 * be overridden from that configured by the user. We do this for the master bus.
2305 * @return optional value that is present if visibility state should be overridden.
2307 boost::optional<bool>
2308 MixerStrip::override_solo_visibility () const
2310 if (_route && _route->is_master ()) {
2311 return boost::optional<bool> (false);
2314 return boost::optional<bool> ();
2318 MixerStrip::add_input_port (DataType t)
2320 _route->input()->add_port ("", this, t);
2324 MixerStrip::add_output_port (DataType t)
2326 _route->output()->add_port ("", this, t);
2330 MixerStrip::route_active_changed ()
2332 reset_strip_style ();
2336 MixerStrip::copy_processors ()
2338 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2342 MixerStrip::cut_processors ()
2344 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2348 MixerStrip::paste_processors ()
2350 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2354 MixerStrip::select_all_processors ()
2356 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2360 MixerStrip::deselect_all_processors ()
2362 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2366 MixerStrip::delete_processors ()
2368 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2372 MixerStrip::toggle_processors ()
2374 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2378 MixerStrip::ab_plugins ()
2380 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2384 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2386 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2389 if (ev->button == 3) {
2390 popup_level_meter_menu (ev);
2398 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2400 using namespace Gtk::Menu_Helpers;
2402 Gtk::Menu* m = manage (new Menu);
2403 MenuList& items = m->items ();
2405 RadioMenuItem::Group group;
2407 _suspend_menu_callbacks = true;
2408 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2409 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2410 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2411 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2412 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2414 if (gpm.meter_channels().n_audio() == 0) {
2415 m->popup (ev->button, ev->time);
2416 _suspend_menu_callbacks = false;
2420 RadioMenuItem::Group tgroup;
2421 items.push_back (SeparatorElem());
2423 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2424 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2425 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2426 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2427 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2428 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2429 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2430 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2431 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2432 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2433 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2436 if (_route->is_master()) {
2439 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2440 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2441 /* non-master bus */
2444 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2451 MeterType cmt = _route->meter_type();
2452 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2454 items.push_back (SeparatorElem());
2455 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2456 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2457 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2458 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2459 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2460 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2462 m->popup (ev->button, ev->time);
2463 _suspend_menu_callbacks = false;
2467 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2468 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2470 using namespace Menu_Helpers;
2472 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2473 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2474 i->set_active (_route->meter_point() == point);
2478 MixerStrip::set_meter_point (MeterPoint p)
2480 if (_suspend_menu_callbacks) return;
2481 _route->set_meter_point (p);
2485 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2486 RadioMenuItem::Group& group, string const & name, MeterType type)
2488 using namespace Menu_Helpers;
2490 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2491 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2492 i->set_active (_route->meter_type() == type);
2496 MixerStrip::set_meter_type (MeterType t)
2498 if (_suspend_menu_callbacks) return;
2503 MixerStrip::vca_menu_toggle (Gtk::CheckMenuItem* menuitem, uint32_t n)
2509 boost::shared_ptr<VCA> vca = _session->vca_manager().vca_by_number (n);
2516 /* if this strip is not selected, add it before carrying out
2517 changes to assignment. the user probably didn't notice
2518 that they were clicking on an unselected track.
2520 _mixer.select_strip (*this);
2523 if (!menuitem->get_active()) {
2524 _mixer.do_vca_unassign (vca);
2526 _mixer.do_vca_assign (vca);
2531 MixerStrip::vca_assign (boost::shared_ptr<VCA> vca)
2533 if (!vca || !_route) {
2537 _route->assign (vca);
2541 MixerStrip::vca_unassign (boost::shared_ptr<VCA> vca)
2547 _route->unassign (vca);
2551 MixerStrip::vca_button_release (GdkEventButton* ev)
2553 using namespace Gtk::Menu_Helpers;
2559 /* primary click only */
2561 if (ev->button != 1) {
2566 /* no route - nothing to do */
2570 VCAList vcas (_session->vca_manager().vcas());
2573 /* the button should not have been visible under these conditions */
2577 Menu* menu = new Menu;
2578 MenuList& items = menu->items();
2580 items.push_back (MenuElem (_("Unassign"), sigc::bind (sigc::mem_fun (_mixer, &Mixer_UI::do_vca_unassign), boost::shared_ptr<VCA>())));
2582 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
2583 items.push_back (CheckMenuElem ((*v)->name()));
2584 Gtk::CheckMenuItem* item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2585 if (_route->slaved_to (*v)) {
2586 item->set_active (true);
2588 item->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &MixerStrip::vca_menu_toggle), item, (*v)->number()));
2591 menu->popup (1, ev->time);
2597 MixerStrip::update_track_number_visibility ()
2599 DisplaySuspender ds;
2600 bool show_label = _session->config.get_track_name_number();
2602 if (_route && _route->is_master()) {
2607 number_label.show ();
2608 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2609 // except the width of the number label is subtracted from the name-hbox, so we
2610 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2611 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2613 number_label.set_size_request(tnw, -1);
2614 number_label.show ();
2616 number_label.hide ();