goodbye Profile->...trx
[ardour.git] / gtk2_ardour / mixer_strip.cc
1 /*
2  * Copyright (C) 2005-2006 Nick Mainsbridge <mainsbridge@gmail.com>
3  * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
4  * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
5  * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
6  * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
7  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8  * Copyright (C) 2008 Hans Baier <hansfbaier@googlemail.com>
9  * Copyright (C) 2009-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10  * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11  * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
12  * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
13  * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
14  * Copyright (C) 2016-2017 Julien "_FrnchFrgg_" RIVAUD <frnchfrgg@free.fr>
15  * Copyright (C) 2018 Len Ovens <len@ovenwerks.net>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, write to the Free Software Foundation, Inc.,
29  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30  */
31
32 #include <cmath>
33 #include <list>
34 #include <algorithm>
35
36 #include <sigc++/bind.h>
37
38 #include <gtkmm/messagedialog.h>
39
40 #include "pbd/convert.h"
41 #include "pbd/enumwriter.h"
42 #include "pbd/replace_all.h"
43 #include "pbd/stacktrace.h"
44 #include "pbd/unwind.h"
45
46 #include "ardour/amp.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/internal_send.h"
50 #include "ardour/io.h"
51 #include "ardour/meter.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/pannable.h"
54 #include "ardour/panner.h"
55 #include "ardour/panner_shell.h"
56 #include "ardour/panner_manager.h"
57 #include "ardour/port.h"
58 #include "ardour/profile.h"
59 #include "ardour/route.h"
60 #include "ardour/route_group.h"
61 #include "ardour/send.h"
62 #include "ardour/session.h"
63 #include "ardour/types.h"
64 #include "ardour/user_bundle.h"
65 #include "ardour/vca.h"
66 #include "ardour/vca_manager.h"
67
68 #include "gtkmm2ext/gtk_ui.h"
69 #include "gtkmm2ext/menu_elems.h"
70 #include "gtkmm2ext/utils.h"
71 #include "gtkmm2ext/doi.h"
72
73 #include "widgets/tooltips.h"
74
75 #include "ardour_window.h"
76 #include "context_menu_helper.h"
77 #include "enums_convert.h"
78 #include "mixer_strip.h"
79 #include "mixer_ui.h"
80 #include "keyboard.h"
81 #include "public_editor.h"
82 #include "send_ui.h"
83 #include "io_selector.h"
84 #include "utils.h"
85 #include "gui_thread.h"
86 #include "route_group_menu.h"
87 #include "meter_patterns.h"
88 #include "ui_config.h"
89
90 #include "pbd/i18n.h"
91
92 using namespace ARDOUR;
93 using namespace ArdourWidgets;
94 using namespace PBD;
95 using namespace Gtk;
96 using namespace Gtkmm2ext;
97 using namespace std;
98 using namespace ArdourMeter;
99
100 MixerStrip* MixerStrip::_entered_mixer_strip;
101 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
102
103 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
104         : SessionHandlePtr (sess)
105         , RouteUI (sess)
106         , _mixer(mx)
107         , _mixer_owned (in_mixer)
108         , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
109         , gpm (sess, 250)
110         , panners (sess)
111         , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
112         , rec_mon_table (2, 2)
113         , solo_iso_table (1, 2)
114         , mute_solo_table (1, 2)
115         , bottom_button_table (1, 3)
116         , monitor_section_button (0)
117         , midi_input_enable_button (0)
118         , _plugin_insert_cnt (0)
119         , _comment_button (_("Comments"))
120         , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
121         , _visibility (X_("mixer-element-visibility"))
122         , _suspend_menu_callbacks (false)
123         , control_slave_ui (sess)
124 {
125         init ();
126
127         if (!_mixer_owned) {
128                 /* the editor mixer strip: don't destroy it every time
129                    the underlying route goes away.
130                 */
131
132                 self_destruct = false;
133         }
134 }
135
136 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
137         : SessionHandlePtr (sess)
138         , RouteUI (sess)
139         , _mixer(mx)
140         , _mixer_owned (in_mixer)
141         , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
142         , gpm (sess, 250)
143         , panners (sess)
144         , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
145         , rec_mon_table (2, 2)
146         , solo_iso_table (1, 2)
147         , mute_solo_table (1, 2)
148         , bottom_button_table (1, 3)
149         , monitor_section_button (0)
150         , midi_input_enable_button (0)
151         , _plugin_insert_cnt (0)
152         , _comment_button (_("Comments"))
153         , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
154         , _visibility (X_("mixer-element-visibility"))
155         , _suspend_menu_callbacks (false)
156         , control_slave_ui (sess)
157 {
158         init ();
159         set_route (rt);
160 }
161
162 void
163 MixerStrip::init ()
164 {
165         _entered_mixer_strip= 0;
166         group_menu = 0;
167         route_ops_menu = 0;
168         ignore_comment_edit = false;
169         ignore_toggle = false;
170         comment_area = 0;
171         _width_owner = 0;
172
173         /* the length of this string determines the width of the mixer strip when it is set to `wide' */
174         longest_label = "longest label";
175
176         string t = _("Click to toggle the width of this mixer strip.");
177         if (_mixer_owned) {
178                 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
179         }
180
181         width_button.set_icon (ArdourIcon::StripWidth);
182         hide_button.set_tweaks (ArdourButton::Square);
183         set_tooltip (width_button, t);
184
185         hide_button.set_icon (ArdourIcon::HideEye);
186         hide_button.set_tweaks (ArdourButton::Square);
187         set_tooltip (&hide_button, _("Hide this mixer strip"));
188
189         input_button_box.set_spacing(2);
190
191         input_button.set_text (_("Input"));
192         input_button.set_name ("mixer strip button");
193         input_button_box.pack_start (input_button, true, true);
194
195         output_button.set_text (_("Output"));
196         output_button.set_name ("mixer strip button");
197
198         bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
199
200         hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
201
202         solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
203         solo_isolated_led->show ();
204         solo_isolated_led->set_no_show_all (true);
205         solo_isolated_led->set_name (X_("solo isolate"));
206         solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
207         solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
208         UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
209
210         solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
211         solo_safe_led->show ();
212         solo_safe_led->set_no_show_all (true);
213         solo_safe_led->set_name (X_("solo safe"));
214         solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
215         solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
216         UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
217
218         solo_safe_led->set_text (S_("SoloLock|Lock"));
219         solo_isolated_led->set_text (_("Iso"));
220
221         solo_iso_table.set_homogeneous (true);
222         solo_iso_table.set_spacings (2);
223         solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
224         solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
225         solo_iso_table.show ();
226
227         rec_mon_table.set_homogeneous (true);
228         rec_mon_table.set_row_spacings (2);
229         rec_mon_table.set_col_spacings (2);
230         if (ARDOUR::Profile->get_mixbus()) {
231                 rec_mon_table.resize (1, 3);
232                 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
233                 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
234         }
235         rec_mon_table.show ();
236
237         if (solo_isolated_led) {
238                 button_size_group->add_widget (*solo_isolated_led);
239         }
240         if (solo_safe_led) {
241                 button_size_group->add_widget (*solo_safe_led);
242         }
243
244         if (!ARDOUR::Profile->get_mixbus()) {
245                 if (rec_enable_button) {
246                         button_size_group->add_widget (*rec_enable_button);
247                 }
248                 if (monitor_disk_button) {
249                         button_size_group->add_widget (*monitor_disk_button);
250                 }
251                 if (monitor_input_button) {
252                         button_size_group->add_widget (*monitor_input_button);
253                 }
254         }
255
256         mute_solo_table.set_homogeneous (true);
257         mute_solo_table.set_spacings (2);
258
259         bottom_button_table.set_spacings (2);
260         bottom_button_table.set_homogeneous (true);
261         bottom_button_table.attach (group_button, 1, 2, 0, 1);
262         bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
263
264         name_button.set_name ("mixer strip button");
265         name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
266         name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
267
268         set_tooltip (&group_button, _("Mix group"));
269         group_button.set_name ("mixer strip button");
270
271         _comment_button.set_name (X_("mixer strip button"));
272         _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
273         _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
274         _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
275
276         // TODO implement ArdourKnob::on_size_request properly
277 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
278         trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
279 #undef PX_SCALE
280         trim_control.set_tooltip_prefix (_("Trim: "));
281         trim_control.set_name ("trim knob");
282         trim_control.set_no_show_all (true);
283         trim_control.StartGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_start_touch));
284         trim_control.StopGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_end_touch));
285         input_button_box.pack_start (trim_control, false, false);
286
287         global_vpacker.set_border_width (1);
288         global_vpacker.set_spacing (0);
289
290         width_button.set_name ("mixer strip button");
291         hide_button.set_name ("mixer strip button");
292
293         width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
294         hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
295
296         width_hide_box.set_spacing (2);
297         width_hide_box.pack_start (width_button, false, true);
298         width_hide_box.pack_start (number_label, true, true);
299         width_hide_box.pack_end (hide_button, false, true);
300
301         number_label.set_text ("-");
302         number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
303         number_label.set_no_show_all ();
304         number_label.set_name ("tracknumber label");
305         number_label.set_fixed_colors (0x80808080, 0x80808080);
306         number_label.set_alignment (.5, .5);
307         number_label.set_fallthrough_to_parent (true);
308         number_label.set_tweaks (ArdourButton::OccasionalText);
309
310         global_vpacker.set_spacing (2);
311         global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
312         global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
313         global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
314         global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
315         global_vpacker.pack_start (processor_box, true, true);
316         global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
317         global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
318         global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
319         global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
320         global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
321         global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
322         global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
323         global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
324         global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
325
326 #ifndef MIXBUS
327         //add a spacer underneath the master bus;
328         //this fills the area that is taken up by the scrollbar on the tracks;
329         //and therefore keeps the faders "even" across the bottom
330         int scrollbar_height = 0;
331         {
332                 Gtk::Window window (WINDOW_TOPLEVEL);
333                 HScrollbar scrollbar;
334                 window.add (scrollbar);
335                 scrollbar.set_name ("MixerWindow");
336                 scrollbar.ensure_style();
337                 Gtk::Requisition requisition(scrollbar.size_request ());
338                 scrollbar_height = requisition.height;
339         }
340         spacer.set_size_request (-1, scrollbar_height);
341         global_vpacker.pack_end (spacer, false, false);
342 #endif
343
344         global_frame.add (global_vpacker);
345         global_frame.set_shadow_type (Gtk::SHADOW_IN);
346         global_frame.set_name ("BaseFrame");
347
348         add (global_frame);
349
350         /* force setting of visible selected status */
351
352         _selected = true;
353         set_selected (false);
354
355         _packed = false;
356         _embedded = false;
357
358         input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
359         input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
360         input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
361
362         input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
363         output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
364
365         output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
366         output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
367         output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
368
369         number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
370
371         name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
372
373         group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
374
375         _width = (Width) -1;
376
377         /* start off as a passthru strip. we'll correct this, if necessary,
378            in update_diskstream_display().
379         */
380
381         /* start off as a passthru strip. we'll correct this, if necessary,
382            in update_diskstream_display().
383         */
384
385         if (is_midi_track()) {
386                 set_name ("MidiTrackStripBase");
387         } else {
388                 set_name ("AudioTrackStripBase");
389         }
390
391         add_events (Gdk::BUTTON_RELEASE_MASK|
392                     Gdk::ENTER_NOTIFY_MASK|
393                     Gdk::LEAVE_NOTIFY_MASK|
394                     Gdk::KEY_PRESS_MASK|
395                     Gdk::KEY_RELEASE_MASK);
396
397         set_flags (get_flags() | Gtk::CAN_FOCUS);
398
399         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
400                 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
401                 );
402
403         /* Add the widgets under visibility control to the VisibilityGroup; the names used here
404            must be the same as those used in RCOptionEditor so that the configuration changes
405            are recognised when they occur.
406         */
407         _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
408         _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
409         _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
410         _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
411         _visibility.add (&output_button, X_("Output"), _("Output"), false);
412         _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
413         _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
414
415         parameter_changed (X_("mixer-element-visibility"));
416         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
417         Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
418         _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
419
420         //watch for mouse enter/exit so we can do some stuff
421         signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
422         signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
423
424         gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
425 }
426
427 MixerStrip::~MixerStrip ()
428 {
429         CatchDeletion (this);
430
431         if (this ==_entered_mixer_strip)
432                 _entered_mixer_strip = NULL;
433 }
434
435 void
436 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
437 {
438         boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
439         if (sl)
440                 sl->assign(vca);
441 }
442
443 void
444 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
445 {
446         boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
447         if (sl)
448                 sl->unassign(vca);
449 }
450
451 bool
452 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
453 {
454         _entered_mixer_strip = this;
455
456         //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
457         //because the mixerstrip control is a parent that encompasses the strip
458         deselect_all_processors();
459
460         return false;
461 }
462
463 bool
464 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
465 {
466         //if we have moved outside our strip, but not into a child view, then deselect ourselves
467         if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
468                 _entered_mixer_strip= 0;
469
470                 //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
471                 gpm.gain_display.set_sensitive(false);
472                 gpm.show_gain();
473                 gpm.gain_display.set_sensitive(true);
474
475                 //if we leave this mixer strip we need to clear out any selections
476                 //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
477         }
478
479         return false;
480 }
481
482 string
483 MixerStrip::name() const
484 {
485         if (_route) {
486                 return _route->name();
487         }
488         return string();
489 }
490
491 void
492 MixerStrip::update_trim_control ()
493 {
494         if (route()->trim() && route()->trim()->active() &&
495             route()->n_inputs().n_audio() > 0) {
496                 trim_control.show ();
497                 trim_control.set_controllable (route()->trim()->gain_control());
498         } else {
499                 trim_control.hide ();
500                 boost::shared_ptr<Controllable> none;
501                 trim_control.set_controllable (none);
502         }
503 }
504
505 void
506 MixerStrip::trim_start_touch ()
507 {
508         assert (_route && _session);
509         if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
510                 route()->trim()->gain_control ()->start_touch (_session->transport_sample());
511         }
512 }
513
514 void
515 MixerStrip::trim_end_touch ()
516 {
517         assert (_route && _session);
518         if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
519                 route()->trim()->gain_control ()->stop_touch (_session->transport_sample());
520         }
521 }
522
523 void
524 MixerStrip::set_route (boost::shared_ptr<Route> rt)
525 {
526         //the rec/monitor stuff only shows up for tracks.
527         //the show_sends only shows up for buses.
528         //remove them all here, and we may add them back later
529         if (show_sends_button->get_parent()) {
530                 rec_mon_table.remove (*show_sends_button);
531         }
532         if (rec_enable_button->get_parent()) {
533                 rec_mon_table.remove (*rec_enable_button);
534         }
535         if (monitor_input_button->get_parent()) {
536                 rec_mon_table.remove (*monitor_input_button);
537         }
538         if (monitor_disk_button->get_parent()) {
539                 rec_mon_table.remove (*monitor_disk_button);
540         }
541         if (group_button.get_parent()) {
542                 bottom_button_table.remove (group_button);
543         }
544
545         RouteUI::set_route (rt);
546
547         control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
548
549         /* ProcessorBox needs access to _route so that it can read
550            GUI object state.
551         */
552         processor_box.set_route (rt);
553
554         revert_to_default_display ();
555
556         /* unpack these from the parent and stuff them into our own
557            table
558         */
559
560         if (gpm.peak_display.get_parent()) {
561                 gpm.peak_display.get_parent()->remove (gpm.peak_display);
562         }
563         if (gpm.gain_display.get_parent()) {
564                 gpm.gain_display.get_parent()->remove (gpm.gain_display);
565         }
566
567         mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
568         mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
569
570         if (solo_button->get_parent()) {
571                 mute_solo_table.remove (*solo_button);
572         }
573
574         if (mute_button->get_parent()) {
575                 mute_solo_table.remove (*mute_button);
576         }
577
578         if (route()->is_master()) {
579                 solo_button->hide ();
580                 mute_button->show ();
581                 rec_mon_table.hide ();
582                 solo_iso_table.set_sensitive(false);
583                 control_slave_ui.set_sensitive(false);
584                 if (monitor_section_button == 0) {
585                         Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleMonitorSection");
586                         _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
587                         _session->MonitorBusAddedOrRemoved.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_section_added_or_removed, this), gui_context());
588
589                         monitor_section_button = manage (new ArdourButton);
590                         monitor_changed ();
591                         monitor_section_button->set_related_action (act);
592                         set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
593                         mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
594                         monitor_section_button->show();
595                         monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
596                         monitor_section_added_or_removed ();
597                 }
598         } else {
599                 bottom_button_table.attach (group_button, 1, 2, 0, 1);
600                 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
601                 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
602                 mute_button->show ();
603                 solo_button->show ();
604                 rec_mon_table.show ();
605                 solo_iso_table.set_sensitive(true);
606                 control_slave_ui.set_sensitive(true);
607         }
608
609         hide_master_spacer (false);
610
611         if (is_track()) {
612                 monitor_input_button->show ();
613                 monitor_disk_button->show ();
614         } else {
615                 monitor_input_button->hide();
616                 monitor_disk_button->hide ();
617         }
618
619         update_trim_control();
620
621         if (is_midi_track()) {
622                 if (midi_input_enable_button == 0) {
623                         midi_input_enable_button = manage (new ArdourButton);
624                         midi_input_enable_button->set_name ("midi input button");
625                         midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
626                         midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
627                         midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
628                         midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
629                         set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
630                 } else {
631                         input_button_box.remove (*midi_input_enable_button);
632                 }
633                 /* get current state */
634                 midi_input_status_changed ();
635                 input_button_box.pack_start (*midi_input_enable_button, false, false);
636                 /* follow changes */
637                 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
638         } else {
639                 if (midi_input_enable_button) {
640                         /* removal from the container will delete it */
641                         input_button_box.remove (*midi_input_enable_button);
642                         midi_input_enable_button = 0;
643                 }
644         }
645
646         if (is_audio_track()) {
647                 boost::shared_ptr<AudioTrack> at = audio_track();
648                 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
649         }
650
651         if (is_track ()) {
652
653                 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
654                 rec_enable_button->show();
655
656                 if (ARDOUR::Profile->get_mixbus()) {
657                         rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
658                         rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
659                 } else {
660                         rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
661                         rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
662                 }
663
664         } else {
665
666                 /* non-master bus */
667
668                 if (!_route->is_master()) {
669                         rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
670                         show_sends_button->show();
671                 }
672         }
673
674         gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
675
676         delete route_ops_menu;
677         route_ops_menu = 0;
678
679         _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
680         _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
681         _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
682         _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
683
684         _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
685
686         if (_route->panner_shell()) {
687                 update_panner_choices();
688                 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
689         }
690
691         _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
692
693         set_stuff_from_route ();
694
695         /* now force an update of all the various elements */
696
697         update_mute_display ();
698         update_solo_display ();
699         name_changed ();
700         comment_changed ();
701         route_group_changed ();
702         update_track_number_visibility ();
703
704         connect_to_pan ();
705         panners.setup_pan ();
706
707         if (has_audio_outputs ()) {
708                 panners.show_all ();
709         } else {
710                 panners.hide_all ();
711         }
712
713         update_diskstream_display ();
714         update_input_display ();
715         update_output_display ();
716
717         add_events (Gdk::BUTTON_RELEASE_MASK);
718
719         processor_box.show ();
720
721         if (!route()->is_master() && !route()->is_monitor()) {
722                 /* we don't allow master or control routes to be hidden */
723                 hide_button.show();
724                 number_label.show();
725         }
726
727         gpm.reset_peak_display ();
728         gpm.gain_display.show ();
729         gpm.peak_display.show ();
730
731         width_button.show();
732         width_hide_box.show();
733         global_frame.show();
734         global_vpacker.show();
735         mute_solo_table.show();
736         bottom_button_table.show();
737         gpm.show_all ();
738         gpm.meter_point_button.show();
739         input_button_box.show_all();
740         output_button.show();
741         name_button.show();
742         _comment_button.show();
743         group_button.show();
744         gpm.gain_automation_state_button.show();
745
746         parameter_changed ("mixer-element-visibility");
747         map_frozen();
748
749         show ();
750 }
751
752 void
753 MixerStrip::set_stuff_from_route ()
754 {
755         /* if width is not set, it will be set by the MixerUI or editor */
756
757         Width width;
758         if (get_gui_property ("strip-width", width)) {
759                 set_width_enum (width, this);
760         }
761 }
762
763 void
764 MixerStrip::set_width_enum (Width w, void* owner)
765 {
766         /* always set the gpm width again, things may be hidden */
767
768         gpm.set_width (w);
769         panners.set_width (w);
770
771         boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
772
773         _width_owner = owner;
774
775         _width = w;
776
777         if (_width_owner == this) {
778                 set_gui_property ("strip-width", _width);
779         }
780
781         set_button_names ();
782
783         const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
784
785         switch (w) {
786         case Wide:
787
788                 if (show_sends_button)  {
789                         show_sends_button->set_text (_("Aux"));
790                 }
791
792                 gpm.gain_automation_state_button.set_text (
793                                 gpm.astate_string(gain_automation->automation_state()));
794
795                 if (_route->panner()) {
796                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
797                                         panners.astate_string(_route->panner()->automation_state()));
798                 }
799
800                 {
801                         // panners expect an even number of horiz. pixels
802                         int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
803                         width &= ~1;
804                         set_size_request (width, -1);
805                 }
806                 break;
807
808         case Narrow:
809
810                 if (show_sends_button) {
811                         show_sends_button->set_text (_("Snd"));
812                 }
813
814                 gpm.gain_automation_state_button.set_text (
815                                 gpm.short_astate_string(gain_automation->automation_state()));
816                 gain_meter().setup_meters (); // recalc meter width
817
818                 if (_route->panner()) {
819                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
820                         panners.short_astate_string(_route->panner()->automation_state()));
821                 }
822
823                 {
824                         // panners expect an even number of horiz. pixels
825                         int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
826                         width &= ~1;
827                         set_size_request (width, -1);
828                 }
829                 break;
830         }
831
832         processor_box.set_width (w);
833
834         update_input_display ();
835         update_output_display ();
836         setup_comment_button ();
837         route_group_changed ();
838         name_changed ();
839         WidthChanged ();
840 }
841
842 void
843 MixerStrip::set_packed (bool yn)
844 {
845         _packed = yn;
846         set_gui_property ("visible", _packed);
847 }
848
849
850 struct RouteCompareByName {
851         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
852                 return a->name().compare (b->name()) < 0;
853         }
854 };
855
856 gint
857 MixerStrip::output_release (GdkEventButton *ev)
858 {
859         switch (ev->button) {
860         case 3:
861                 edit_output_configuration ();
862                 break;
863         }
864
865         return false;
866 }
867
868 gint
869 MixerStrip::output_press (GdkEventButton *ev)
870 {
871         using namespace Menu_Helpers;
872         if (!ARDOUR_UI_UTILS::engine_is_running ()) {
873                 return true;
874         }
875
876         MenuList& citems = output_menu.items();
877         switch (ev->button) {
878
879         case 3:
880                 return false;  //wait for the mouse-up to pop the dialog
881
882         case 1:
883         {
884                 output_menu.set_name ("ArdourContextMenu");
885                 citems.clear ();
886                 output_menu_bundles.clear ();
887
888                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
889
890                 citems.push_back (SeparatorElem());
891                 uint32_t const n_with_separator = citems.size ();
892
893                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
894
895                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
896
897                 /* guess the user-intended main type of the route output */
898                 DataType intended_type = guess_main_type(false);
899
900                 /* try adding the master bus first */
901                 boost::shared_ptr<Route> master = _session->master_out();
902                 if (master) {
903                         maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
904                 }
905
906                 /* then other routes inputs */
907                 RouteList copy = _session->get_routelist ();
908                 copy.sort (RouteCompareByName ());
909                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
910                         maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
911                 }
912
913                 /* then try adding user bundles, often labeled/grouped physical inputs */
914                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
915                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
916                                 maybe_add_bundle_to_output_menu (*i, current, intended_type);
917                         }
918                 }
919
920                 /* then all other bundles, including physical outs or other sofware */
921                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
922                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
923                                 maybe_add_bundle_to_output_menu (*i, current, intended_type);
924                         }
925                 }
926
927                 if (citems.size() == n_with_separator) {
928                         /* no routes added; remove the separator */
929                         citems.pop_back ();
930                 }
931
932                 citems.push_back (SeparatorElem());
933
934                 if (!ARDOUR::Profile->get_mixbus()) {
935                         bool need_separator = false;
936                         for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
937                                 if (!_route->output()->can_add_port (*i)) {
938                                         continue;
939                                 }
940                                 need_separator = true;
941                                 citems.push_back (
942                                                 MenuElem (
943                                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
944                                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
945                                                         )
946                                                 );
947                         }
948                         if (need_separator) {
949                                 citems.push_back (SeparatorElem());
950                         }
951                 }
952
953                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
954
955                 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
956                                                1, ev->time);
957
958                 break;
959         }
960
961         default:
962                 break;
963         }
964         return TRUE;
965 }
966
967 gint
968 MixerStrip::input_release (GdkEventButton *ev)
969 {
970         switch (ev->button) {
971
972         case 3:
973                 edit_input_configuration ();
974                 break;
975         default:
976                 break;
977
978         }
979
980         return false;
981 }
982
983
984 gint
985 MixerStrip::input_press (GdkEventButton *ev)
986 {
987         using namespace Menu_Helpers;
988
989         MenuList& citems = input_menu.items();
990         input_menu.set_name ("ArdourContextMenu");
991         citems.clear();
992
993         if (!ARDOUR_UI_UTILS::engine_is_running ()) {
994                 return true;
995         }
996
997         if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
998                 return true;
999
1000         switch (ev->button) {
1001
1002         case 3:
1003                 return false;  //don't handle the mouse-down here.  wait for mouse-up to pop the menu
1004
1005         case 1:
1006         {
1007                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1008
1009                 citems.push_back (SeparatorElem());
1010                 uint32_t const n_with_separator = citems.size ();
1011
1012                 input_menu_bundles.clear ();
1013
1014                 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1015
1016                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1017
1018                 /* give user bundles first chance at being in the menu */
1019
1020                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1021                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1022                                 maybe_add_bundle_to_input_menu (*i, current);
1023                         }
1024                 }
1025
1026                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1027                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1028                                 maybe_add_bundle_to_input_menu (*i, current);
1029                         }
1030                 }
1031
1032                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1033                 RouteList copy = *routes;
1034                 copy.sort (RouteCompareByName ());
1035                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1036                         maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1037                 }
1038
1039                 if (citems.size() == n_with_separator) {
1040                         /* no routes added; remove the separator */
1041                         citems.pop_back ();
1042                 }
1043
1044                 citems.push_back (SeparatorElem());
1045
1046                 bool need_separator = false;
1047                 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1048                         if (!_route->input()->can_add_port (*i)) {
1049                                 continue;
1050                         }
1051                         need_separator = true;
1052                         citems.push_back (
1053                                 MenuElem (
1054                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1055                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1056                                         )
1057                                 );
1058                 }
1059                 if (need_separator) {
1060                         citems.push_back (SeparatorElem());
1061                 }
1062
1063                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1064
1065                 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1066                                                1, ev->time);
1067
1068                 break;
1069         }
1070         default:
1071                 break;
1072         }
1073         return TRUE;
1074 }
1075
1076 void
1077 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1078 {
1079         if (ignore_toggle) {
1080                 return;
1081         }
1082
1083         _route->input()->connect_ports_to_bundle (c, true, this);
1084 }
1085
1086 void
1087 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1088 {
1089         if (ignore_toggle) {
1090                 return;
1091         }
1092
1093         _route->output()->connect_ports_to_bundle (c, true, true, this);
1094 }
1095
1096 void
1097 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1098 {
1099         using namespace Menu_Helpers;
1100
1101         if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1102                 return;
1103         }
1104
1105         list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1106         while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1107                 ++i;
1108         }
1109
1110         if (i != input_menu_bundles.end()) {
1111                 return;
1112         }
1113
1114         input_menu_bundles.push_back (b);
1115
1116         MenuList& citems = input_menu.items();
1117         citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1118 }
1119
1120 void
1121 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1122                                              DataType type)
1123 {
1124         using namespace Menu_Helpers;
1125
1126         /* The bundle should be an input one, but not ours */
1127         if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1128                 return;
1129         }
1130
1131         /* Don't add the monitor input unless we are Master */
1132         boost::shared_ptr<Route> monitor = _session->monitor_out();
1133         if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1134                 return;
1135
1136         /* It should either match exactly our outputs (if |type| is DataType::NIL)
1137          * or have the same number of |type| channels than our outputs. */
1138         if (type == DataType::NIL) {
1139                 if(b->nchannels() != _route->n_outputs())
1140                         return;
1141         } else {
1142                 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1143                         return;
1144         }
1145
1146         /* Avoid adding duplicates */
1147         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1148         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1149                 ++i;
1150         }
1151         if (i != output_menu_bundles.end()) {
1152                 return;
1153         }
1154
1155         /* Now add the bundle to the menu */
1156         output_menu_bundles.push_back (b);
1157
1158         MenuList& citems = output_menu.items();
1159         citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1160 }
1161
1162 void
1163 MixerStrip::update_diskstream_display ()
1164 {
1165         if (is_track() && input_selector) {
1166                 input_selector->hide_all ();
1167         }
1168
1169         route_color_changed ();
1170 }
1171
1172 void
1173 MixerStrip::connect_to_pan ()
1174 {
1175         ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1176
1177         panstate_connection.disconnect ();
1178         panstyle_connection.disconnect ();
1179
1180         if (!_route->panner()) {
1181                 return;
1182         }
1183
1184         boost::shared_ptr<Pannable> p = _route->pannable ();
1185
1186         p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1187
1188         /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1189          * However, that only works a panner was previously set.
1190          *
1191          * PannerUI must remain subscribed to _panshell->Changed() in case
1192          * we switch the panner eg. AUX-Send and back
1193          * _route->panner_shell()->Changed() vs _panshell->Changed
1194          */
1195         if (panners._panner == 0) {
1196                 panners.panshell_changed ();
1197         }
1198         update_panner_choices();
1199 }
1200
1201 void
1202 MixerStrip::update_panner_choices ()
1203 {
1204         ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1205         if (!_route->panner_shell()) { return; }
1206
1207         uint32_t in = _route->output()->n_ports().n_audio();
1208         uint32_t out = in;
1209         if (_route->panner()) {
1210                 in = _route->panner()->in().n_audio();
1211         }
1212
1213         panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1214 }
1215
1216 DataType
1217 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1218 {
1219         /* The heuristic follows these principles:
1220          *  A) If all ports that the user connected are of the same type, then he
1221          *     very probably intends to use the IO with that type. A common subcase
1222          *     is when the IO has only ports of the same type (connected or not).
1223          *  B) If several types of ports are connected, then we should guess based
1224          *     on the likeliness of the user wanting to use a given type.
1225          *     We assume that the DataTypes are ordered from the most likely to the
1226          *     least likely when iterating or comparing them with "<".
1227          *  C) If no port is connected, the same logic can be applied with all ports
1228          *     instead of connected ones. TODO: Try other ideas, for instance look at
1229          *     the last plugin output when |for_input| is false (note: when StrictIO
1230          *     the outs of the last plugin should be the same as the outs of the route
1231          *     modulo the panner which forwards non-audio anyway).
1232          * All of these constraints are respected by the following algorithm that
1233          * just returns the most likely datatype found in connected ports if any, or
1234          * available ports if any (since if all ports are of the same type, the most
1235          * likely found will be that one obviously). */
1236
1237         boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1238
1239         /* Find most likely type among connected ports */
1240         if (favor_connected) {
1241                 DataType type = DataType::NIL; /* NIL is always last so least likely */
1242                 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1243                         if (p->connected() && p->type() < type)
1244                                 type = p->type();
1245                 }
1246                 if (type != DataType::NIL) {
1247                         /* There has been a connected port (necessarily non-NIL) */
1248                         return type;
1249                 }
1250         }
1251
1252         /* Find most likely type among available ports.
1253          * The iterator stops before NIL. */
1254         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1255                 if (io->n_ports().n(*t) > 0)
1256                         return *t;
1257         }
1258
1259         /* No port at all, return the most likely datatype by default */
1260         return DataType::front();
1261 }
1262
1263 /*
1264  * Output port labelling
1265  *
1266  * Case 1: Each output has one connection, all connections are to system:playback_%i
1267  *   out 1 -> system:playback_1
1268  *   out 2 -> system:playback_2
1269  *   out 3 -> system:playback_3
1270  *   Display as: 1/2/3
1271  *
1272  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1273  *   out 1 -> ardour:track_x/in 1
1274  *   out 2 -> ardour:track_x/in 2
1275  *   Display as: track_x
1276  *
1277  * Case 3: Each output has one connection, all connections are to Jack client "program x"
1278  *   out 1 -> program x:foo
1279  *   out 2 -> program x:foo
1280  *   Display as: program x
1281  *
1282  * Case 4: No connections (Disconnected)
1283  *   Display as: -
1284  *
1285  * Default case (unusual routing):
1286  *   Display as: *number of connections*
1287  *
1288  *
1289  * Tooltips
1290  *
1291  * .-----------------------------------------------.
1292  * | Mixdown                                       |
1293  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1294  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1295  * '-----------------------------------------------'
1296  * .-----------------------------------------------.
1297  * | Guitar SM58                                   |
1298  * | Disconnected                                  |
1299  * '-----------------------------------------------'
1300  */
1301
1302 void
1303 MixerStrip::update_io_button (bool for_input)
1304 {
1305         ostringstream tooltip;
1306         ostringstream label;
1307         bool have_label = false;
1308
1309         uint32_t total_connection_count = 0;
1310         uint32_t typed_connection_count = 0;
1311         bool each_typed_port_has_one_connection = true;
1312
1313         DataType dt = guess_main_type(for_input);
1314         boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1315
1316         /* Fill in the tooltip. Also count:
1317          *  - The total number of connections.
1318          *  - The number of main-typed connections.
1319          *  - Whether each main-typed port has exactly one connection. */
1320         if (for_input) {
1321                 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1322                                 Gtkmm2ext::markup_escape_text (_route->name()));
1323         } else {
1324                 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1325                                 Gtkmm2ext::markup_escape_text (_route->name()));
1326         }
1327
1328         string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1329         vector<string> port_connections;
1330         for (PortSet::iterator port = io->ports().begin();
1331                                port != io->ports().end();
1332                                ++port) {
1333                 port_connections.clear();
1334                 port->get_connections(port_connections);
1335
1336                 uint32_t port_connection_count = 0;
1337
1338                 for (vector<string>::iterator i = port_connections.begin();
1339                                               i != port_connections.end();
1340                                               ++i) {
1341                         ++port_connection_count;
1342
1343                         if (port_connection_count == 1) {
1344                                 tooltip << endl << Gtkmm2ext::markup_escape_text (
1345                                                 port->name().substr(port->name().find("/") + 1));
1346                                 tooltip << arrow;
1347                         } else {
1348                                 tooltip << ", ";
1349                         }
1350
1351                         tooltip << Gtkmm2ext::markup_escape_text(*i);
1352                 }
1353
1354                 total_connection_count += port_connection_count;
1355                 if (port->type() == dt) {
1356                         typed_connection_count += port_connection_count;
1357                         each_typed_port_has_one_connection &= (port_connection_count == 1);
1358                 }
1359
1360         }
1361
1362         if (total_connection_count == 0) {
1363                 tooltip << endl << _("Disconnected");
1364         }
1365
1366         if (typed_connection_count == 0) {
1367                 label << "-";
1368                 have_label = true;
1369         }
1370
1371         /* Are all main-typed channels connected to the same route ? */
1372         if (!have_label) {
1373                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1374                 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1375                                                        route != routes->end();
1376                                                        ++route) {
1377                         boost::shared_ptr<IO> dest_io =
1378                                 for_input ? (*route)->output() : (*route)->input();
1379                         if (io->bundle()->connected_to(dest_io->bundle(),
1380                                                        _session->engine(),
1381                                                        dt, true)) {
1382                                 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1383                                 have_label = true;
1384                                 break;
1385                         }
1386                 }
1387         }
1388
1389         /* Are all main-typed channels connected to the same (user) bundle ? */
1390         if (!have_label) {
1391                 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1392                 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1393                                                   bundle != bundles->end();
1394                                                   ++bundle) {
1395                         if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1396                                 continue;
1397                         if (io->bundle()->connected_to(*bundle, _session->engine(),
1398                                                        dt, true)) {
1399                                 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1400                                 have_label = true;
1401                                 break;
1402                         }
1403                 }
1404         }
1405
1406         /* Is each main-typed channel only connected to a physical output ? */
1407         if (!have_label && each_typed_port_has_one_connection) {
1408                 ostringstream temp_label;
1409                 vector<string> phys;
1410                 string playorcapture;
1411                 if (for_input) {
1412                         _session->engine().get_physical_inputs(dt, phys);
1413                         playorcapture = "capture_";
1414                 } else {
1415                         _session->engine().get_physical_outputs(dt, phys);
1416                         playorcapture = "playback_";
1417                 }
1418                 for (PortSet::iterator port = io->ports().begin(dt);
1419                                        port != io->ports().end(dt);
1420                                        ++port) {
1421                         string pn = "";
1422                         for (vector<string>::iterator s = phys.begin();
1423                                                       s != phys.end();
1424                                                       ++s) {
1425                                 if (!port->connected_to(*s))
1426                                         continue;
1427                                 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1428                                 if (pn.empty()) {
1429                                         string::size_type start = (*s).find(playorcapture);
1430                                         if (start != string::npos) {
1431                                                 pn = (*s).substr(start + playorcapture.size());
1432                                         }
1433                                 }
1434                                 break;
1435                         }
1436                         if (pn.empty()) {
1437                                 temp_label.str(""); /* erase the failed attempt */
1438                                 break;
1439                         }
1440                         if (port != io->ports().begin(dt))
1441                                 temp_label << "/";
1442                         temp_label << pn;
1443                 }
1444
1445                 if (!temp_label.str().empty()) {
1446                         label << temp_label.str();
1447                         have_label = true;
1448                 }
1449         }
1450
1451         /* Is each main-typed channel connected to a single and different port with
1452          * the same client name (e.g. another JACK client) ? */
1453         if (!have_label && each_typed_port_has_one_connection) {
1454                 string maybe_client = "";
1455                 vector<string> connections;
1456                 for (PortSet::iterator port = io->ports().begin(dt);
1457                                        port != io->ports().end(dt);
1458                                        ++port) {
1459                         port_connections.clear();
1460                         port->get_connections(port_connections);
1461                         string connection = port_connections.front();
1462
1463                         vector<string>::iterator i = connections.begin();
1464                         while (i != connections.end() && *i != connection) {
1465                                 ++i;
1466                         }
1467                         if (i != connections.end())
1468                                 break; /* duplicate connection */
1469                         connections.push_back(connection);
1470
1471                         connection = connection.substr(0, connection.find(":"));
1472                         if (maybe_client.empty())
1473                                 maybe_client = connection;
1474                         if (maybe_client != connection)
1475                                 break;
1476                 }
1477                 if (connections.size() == io->n_ports().n(dt)) {
1478                         label << maybe_client;
1479                         have_label = true;
1480                 }
1481         }
1482
1483         /* Odd configuration */
1484         if (!have_label) {
1485                 label << "*" << total_connection_count << "*";
1486         }
1487
1488         if (total_connection_count > typed_connection_count) {
1489                 label << "\u2295"; /* circled plus */
1490         }
1491
1492         /* Actually set the properties of the button */
1493         char * cstr = new char[tooltip.str().size() + 1];
1494         strcpy(cstr, tooltip.str().c_str());
1495
1496         if (for_input) {
1497                 input_button.set_text (label.str());
1498                 set_tooltip (&input_button, cstr);
1499         } else {
1500                 output_button.set_text (label.str());
1501                 set_tooltip (&output_button, cstr);
1502         }
1503
1504         delete [] cstr;
1505 }
1506
1507 void
1508 MixerStrip::update_input_display ()
1509 {
1510         update_io_button (true);
1511         panners.setup_pan ();
1512
1513         if (has_audio_outputs ()) {
1514                 panners.show_all ();
1515         } else {
1516                 panners.hide_all ();
1517         }
1518
1519 }
1520
1521 void
1522 MixerStrip::update_output_display ()
1523 {
1524         update_io_button (false);
1525         gpm.setup_meters ();
1526         panners.setup_pan ();
1527
1528         if (has_audio_outputs ()) {
1529                 panners.show_all ();
1530         } else {
1531                 panners.hide_all ();
1532         }
1533 }
1534
1535 void
1536 MixerStrip::fast_update ()
1537 {
1538         gpm.update_meters ();
1539 }
1540
1541 void
1542 MixerStrip::diskstream_changed ()
1543 {
1544         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1545 }
1546
1547 void
1548 MixerStrip::io_changed_proxy ()
1549 {
1550         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1551         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1552 }
1553
1554 void
1555 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1556 {
1557         boost::shared_ptr<Port> a = wa.lock ();
1558         boost::shared_ptr<Port> b = wb.lock ();
1559
1560         if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1561                 update_input_display ();
1562                 set_width_enum (_width, this);
1563         }
1564
1565         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1566                 update_output_display ();
1567                 set_width_enum (_width, this);
1568         }
1569 }
1570
1571 void
1572 MixerStrip::setup_comment_button ()
1573 {
1574         std::string comment = _route->comment();
1575
1576         set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1577
1578         if (comment.empty ()) {
1579                 _comment_button.set_name ("generic button");
1580                 _comment_button.set_text (_width  == Wide ? _("Comments") : _("Cmt"));
1581                 return;
1582         }
1583
1584         _comment_button.set_name ("comment button");
1585
1586         string::size_type pos = comment.find_first_of (" \t\n");
1587         if (pos != string::npos) {
1588                 comment = comment.substr (0, pos);
1589         }
1590         if (comment.empty()) {
1591                 _comment_button.set_text (_width  == Wide ? _("Comments") : _("Cmt"));
1592         } else {
1593                 _comment_button.set_text (comment);
1594         }
1595 }
1596
1597 bool
1598 MixerStrip::select_route_group (GdkEventButton *ev)
1599 {
1600         using namespace Menu_Helpers;
1601
1602         if (ev->button == 1) {
1603
1604                 if (group_menu == 0) {
1605
1606                         PropertyList* plist = new PropertyList();
1607
1608                         plist->add (Properties::group_gain, true);
1609                         plist->add (Properties::group_mute, true);
1610                         plist->add (Properties::group_solo, true);
1611
1612                         group_menu = new RouteGroupMenu (_session, plist);
1613                 }
1614
1615                 WeakRouteList r;
1616                 r.push_back (route ());
1617                 group_menu->build (r);
1618
1619                 RouteGroup *rg = _route->route_group();
1620
1621                 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1622                                                rg ? rg->name() : _("No Group"),
1623                                                1, ev->time);
1624         }
1625
1626         return true;
1627 }
1628
1629 void
1630 MixerStrip::route_group_changed ()
1631 {
1632         ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1633
1634         RouteGroup *rg = _route->route_group();
1635
1636         if (rg) {
1637                 group_button.set_text (PBD::short_version (rg->name(), 5));
1638         } else {
1639                 switch (_width) {
1640                 case Wide:
1641                         group_button.set_text (_("Grp"));
1642                         break;
1643                 case Narrow:
1644                         group_button.set_text (_("~G"));
1645                         break;
1646                 }
1647         }
1648 }
1649
1650 void
1651 MixerStrip::route_color_changed ()
1652 {
1653         using namespace ARDOUR_UI_UTILS;
1654         name_button.modify_bg (STATE_NORMAL, color());
1655         number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1656         reset_strip_style ();
1657 }
1658
1659 void
1660 MixerStrip::show_passthru_color ()
1661 {
1662         reset_strip_style ();
1663 }
1664
1665
1666 void
1667 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1668 {
1669         boost::shared_ptr<Processor> processor (p.lock ());
1670         if (!processor || !processor->display_to_user()) {
1671                 return;
1672         }
1673         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1674 #ifdef MIXBUS
1675         if (pi && pi->is_channelstrip ()) {
1676                 return;
1677         }
1678 #endif
1679         if (pi) {
1680                 ++_plugin_insert_cnt;
1681         }
1682 }
1683 void
1684 MixerStrip::build_route_ops_menu ()
1685 {
1686         using namespace Menu_Helpers;
1687         route_ops_menu = new Menu;
1688         route_ops_menu->set_name ("ArdourContextMenu");
1689
1690         MenuList& items = route_ops_menu->items();
1691
1692         items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1693
1694         items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1695
1696         items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1697
1698         items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1699
1700         if (!Profile->get_mixbus()) {
1701                 items.push_back (SeparatorElem());
1702         }
1703
1704         if (!_route->is_master()
1705 #ifdef MIXBUS
1706                         && !_route->mixbus()
1707 #endif
1708                         ) {
1709                 if (Profile->get_mixbus()) {
1710                         items.push_back (SeparatorElem());
1711                 }
1712                 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1713         }
1714
1715         if (!Profile->get_mixbus()) {
1716                 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1717                 /* do not allow rename if the track is record-enabled */
1718                 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1719         }
1720
1721         items.push_back (SeparatorElem());
1722         items.push_back (CheckMenuElem (_("Active")));
1723         Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1724         i->set_active (_route->active());
1725         i->set_sensitive(! _session->transport_rolling());
1726         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1727
1728         if (!Profile->get_mixbus ()) {
1729                 items.push_back (SeparatorElem());
1730                 items.push_back (CheckMenuElem (_("Strict I/O")));
1731                 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1732                 i->set_active (_route->strict_io());
1733                 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1734         }
1735
1736         if (is_track()) {
1737                 items.push_back (SeparatorElem());
1738
1739                 Gtk::Menu* dio_menu = new Menu;
1740                 MenuList& dio_items = dio_menu->items();
1741                 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1742                 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1743                 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1744
1745                 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1746         }
1747
1748         _plugin_insert_cnt = 0;
1749         _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1750         if (_plugin_insert_cnt > 0) {
1751                 items.push_back (SeparatorElem());
1752                 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1753         }
1754
1755         if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1756                 items.push_back (MenuElem (_("Patch Selector..."),
1757                                         sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1758         }
1759
1760         if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1761                 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1762                 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1763                 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1764         }
1765
1766         items.push_back (SeparatorElem());
1767         items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1768
1769         items.push_back (SeparatorElem());
1770         items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1771         denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1772         denormal_menu_item->set_active (_route->denormal_protection());
1773
1774         if (_route) {
1775                 /* note that this relies on selection being shared across editor and
1776                    mixer (or global to the backend, in the future), which is the only
1777                    sane thing for users anyway.
1778                 */
1779
1780                 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1781                 if (stav) {
1782                         Selection& selection (PublicEditor::instance().get_selection());
1783                         if (!selection.selected (stav)) {
1784                                 selection.set (stav);
1785                         }
1786
1787                         if (!_route->is_master()) {
1788                                 items.push_back (SeparatorElem());
1789                                 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1790                         }
1791
1792                         items.push_back (SeparatorElem());
1793                         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1794                 }
1795         }
1796 }
1797
1798 gboolean
1799 MixerStrip::name_button_button_press (GdkEventButton* ev)
1800 {
1801         if (ev->button == 1 || ev->button == 3) {
1802                 list_route_operations ();
1803
1804                 if (ev->button == 1) {
1805                         Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1806                                                        1, ev->time);
1807                 } else {
1808                         route_ops_menu->popup (3, ev->time);
1809                 }
1810
1811                 return true;
1812         }
1813
1814         return false;
1815 }
1816
1817 gboolean
1818 MixerStrip::number_button_button_press (GdkEventButton* ev)
1819 {
1820         if (  ev->button == 3 ) {
1821                 list_route_operations ();
1822
1823                 route_ops_menu->popup (1, ev->time);
1824
1825                 return true;
1826         }
1827
1828         return false;
1829 }
1830
1831 void
1832 MixerStrip::list_route_operations ()
1833 {
1834         delete route_ops_menu;
1835         build_route_ops_menu ();
1836 }
1837
1838 void
1839 MixerStrip::set_selected (bool yn)
1840 {
1841         AxisView::set_selected (yn);
1842
1843         if (selected()) {
1844                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1845                 global_frame.set_name ("MixerStripSelectedFrame");
1846         } else {
1847                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1848                 global_frame.set_name ("MixerStripFrame");
1849         }
1850
1851         global_frame.queue_draw ();
1852
1853 //      if (!yn)
1854 //              processor_box.deselect_all_processors();
1855 }
1856
1857 void
1858 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1859 {
1860         if (what_changed.contains (ARDOUR::Properties::name)) {
1861                 name_changed ();
1862         }
1863 }
1864
1865 void
1866 MixerStrip::name_changed ()
1867 {
1868         switch (_width) {
1869                 case Wide:
1870                         name_button.set_text (_route->name());
1871                         break;
1872                 case Narrow:
1873                         name_button.set_text (PBD::short_version (_route->name(), 5));
1874                         break;
1875         }
1876
1877         set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1878
1879         if (_session->config.get_track_name_number()) {
1880                 const int64_t track_number = _route->track_number ();
1881                 if (track_number == 0) {
1882                         number_label.set_text ("-");
1883                 } else {
1884                         number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1885                 }
1886         } else {
1887                 number_label.set_text ("");
1888         }
1889 }
1890
1891 void
1892 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1893 {
1894         input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1895 }
1896
1897 void
1898 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1899 {
1900         output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1901 }
1902
1903 void
1904 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1905 {
1906         name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1907 }
1908
1909 void
1910 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1911 {
1912         _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1913 }
1914
1915 bool
1916 MixerStrip::width_button_pressed (GdkEventButton* ev)
1917 {
1918         if (ev->button != 1) {
1919                 return false;
1920         }
1921
1922         if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1923                 switch (_width) {
1924                 case Wide:
1925                         _mixer.set_strip_width (Narrow, true);
1926                         break;
1927
1928                 case Narrow:
1929                         _mixer.set_strip_width (Wide, true);
1930                         break;
1931                 }
1932         } else {
1933                 switch (_width) {
1934                 case Wide:
1935                         set_width_enum (Narrow, this);
1936                         break;
1937                 case Narrow:
1938                         set_width_enum (Wide, this);
1939                         break;
1940                 }
1941         }
1942
1943         return true;
1944 }
1945
1946 void
1947 MixerStrip::hide_clicked ()
1948 {
1949         // LAME fix to reset the button status for when it is redisplayed (part 1)
1950         hide_button.set_sensitive(false);
1951
1952         if (_embedded) {
1953                 Hiding(); /* EMIT_SIGNAL */
1954         } else {
1955                 _mixer.hide_strip (this);
1956         }
1957
1958         // (part 2)
1959         hide_button.set_sensitive(true);
1960 }
1961
1962 void
1963 MixerStrip::set_embedded (bool yn)
1964 {
1965         _embedded = yn;
1966 }
1967
1968 void
1969 MixerStrip::map_frozen ()
1970 {
1971         ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1972
1973         boost::shared_ptr<AudioTrack> at = audio_track();
1974
1975         if (at) {
1976                 switch (at->freeze_state()) {
1977                 case AudioTrack::Frozen:
1978                         processor_box.set_sensitive (false);
1979                         hide_redirect_editors ();
1980                         break;
1981                 default:
1982                         processor_box.set_sensitive (true);
1983                         // XXX need some way, maybe, to retoggle redirect editors
1984                         break;
1985                 }
1986         } else {
1987                 processor_box.set_sensitive (true);
1988         }
1989         RouteUI::map_frozen ();
1990 }
1991
1992 void
1993 MixerStrip::hide_redirect_editors ()
1994 {
1995         _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1996 }
1997
1998 void
1999 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
2000 {
2001         boost::shared_ptr<Processor> processor (p.lock ());
2002         if (!processor) {
2003                 return;
2004         }
2005
2006         Gtk::Window* w = processor_box.get_processor_ui (processor);
2007
2008         if (w) {
2009                 w->hide ();
2010         }
2011 }
2012
2013 void
2014 MixerStrip::reset_strip_style ()
2015 {
2016         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2017
2018                 gpm.set_fader_name ("SendStripBase");
2019
2020         } else {
2021
2022                 if (is_midi_track()) {
2023                         if (_route->active()) {
2024                                 set_name ("MidiTrackStripBase");
2025                         } else {
2026                                 set_name ("MidiTrackStripBaseInactive");
2027                         }
2028                         gpm.set_fader_name ("MidiTrackFader");
2029                 } else if (is_audio_track()) {
2030                         if (_route->active()) {
2031                                 set_name ("AudioTrackStripBase");
2032                         } else {
2033                                 set_name ("AudioTrackStripBaseInactive");
2034                         }
2035                         gpm.set_fader_name ("AudioTrackFader");
2036                 } else {
2037                         if (_route->active()) {
2038                                 set_name ("AudioBusStripBase");
2039                         } else {
2040                                 set_name ("AudioBusStripBaseInactive");
2041                         }
2042                         gpm.set_fader_name ("AudioBusFader");
2043
2044                         /* (no MIDI busses yet) */
2045                 }
2046         }
2047 }
2048
2049
2050 string
2051 MixerStrip::meter_point_string (MeterPoint mp)
2052 {
2053         switch (_width) {
2054         case Wide:
2055                 switch (mp) {
2056                 case MeterInput:
2057                         return _("In");
2058                         break;
2059
2060                 case MeterPreFader:
2061                         return _("Pre");
2062                         break;
2063
2064                 case MeterPostFader:
2065                         return _("Post");
2066                         break;
2067
2068                 case MeterOutput:
2069                         return _("Out");
2070                         break;
2071
2072                 case MeterCustom:
2073                 default:
2074                         return _("Custom");
2075                         break;
2076                 }
2077                 break;
2078         case Narrow:
2079                 switch (mp) {
2080                 case MeterInput:
2081                         return S_("Meter|In");
2082                         break;
2083
2084                 case MeterPreFader:
2085                         return S_("Meter|Pr");
2086                         break;
2087
2088                 case MeterPostFader:
2089                         return S_("Meter|Po");
2090                         break;
2091
2092                 case MeterOutput:
2093                         return S_("Meter|O");
2094                         break;
2095
2096                 case MeterCustom:
2097                 default:
2098                         return S_("Meter|C");
2099                         break;
2100                 }
2101                 break;
2102         }
2103
2104         return string();
2105 }
2106
2107 /** Called when the monitor-section state */
2108 void
2109 MixerStrip::monitor_changed ()
2110 {
2111         assert (monitor_section_button);
2112         if (_session->monitor_active()) {
2113                 monitor_section_button->set_name ("master monitor section button active");
2114         } else {
2115                 monitor_section_button->set_name ("master monitor section button normal");
2116         }
2117 }
2118
2119 void
2120 MixerStrip::monitor_section_added_or_removed ()
2121 {
2122         assert (monitor_section_button);
2123         if (mute_button->get_parent()) {
2124                 mute_button->get_parent()->remove(*mute_button);
2125         }
2126         if (monitor_section_button->get_parent()) {
2127                 monitor_section_button->get_parent()->remove(*monitor_section_button);
2128         }
2129         if (_session && _session->monitor_out ()) {
2130                 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2131                 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2132                 mute_button->show();
2133                 monitor_section_button->show();
2134         } else {
2135                 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2136                 mute_button->show();
2137         }
2138 }
2139
2140 /** Called when the metering point has changed */
2141 void
2142 MixerStrip::meter_changed ()
2143 {
2144         gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2145         gpm.setup_meters ();
2146         // reset peak when meter point changes
2147         gpm.reset_peak_display();
2148 }
2149
2150 /** The bus that we are displaying sends to has changed, or been turned off.
2151  *  @param send_to New bus that we are displaying sends to, or 0.
2152  */
2153 void
2154 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2155 {
2156         RouteUI::bus_send_display_changed (send_to);
2157
2158         if (send_to) {
2159                 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2160
2161                 if (send) {
2162                         show_send (send);
2163                 } else {
2164                         revert_to_default_display ();
2165                 }
2166         } else {
2167                 revert_to_default_display ();
2168         }
2169 }
2170
2171 void
2172 MixerStrip::drop_send ()
2173 {
2174         boost::shared_ptr<Send> current_send;
2175
2176         if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2177                 current_send->set_metering (false);
2178         }
2179
2180         send_gone_connection.disconnect ();
2181         input_button.set_sensitive (true);
2182         output_button.set_sensitive (true);
2183         group_button.set_sensitive (true);
2184         set_invert_sensitive (true);
2185         gpm.meter_point_button.set_sensitive (true);
2186         mute_button->set_sensitive (true);
2187         solo_button->set_sensitive (true);
2188         solo_isolated_led->set_sensitive (true);
2189         solo_safe_led->set_sensitive (true);
2190         monitor_input_button->set_sensitive (true);
2191         monitor_disk_button->set_sensitive (true);
2192         _comment_button.set_sensitive (true);
2193         trim_control.set_sensitive (true);
2194         if (midi_input_enable_button) {
2195                 midi_input_enable_button->set_sensitive (true);
2196         }
2197         control_slave_ui.set_sensitive (true);
2198         RouteUI::check_rec_enable_sensitivity ();
2199         set_button_names (); // update solo button visual state
2200 }
2201
2202 void
2203 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2204 {
2205         _current_delivery = d;
2206         DeliveryChanged (_current_delivery);
2207 }
2208
2209 void
2210 MixerStrip::show_send (boost::shared_ptr<Send> send)
2211 {
2212         assert (send != 0);
2213
2214         drop_send ();
2215
2216         set_current_delivery (send);
2217
2218         send->meter()->set_meter_type (_route->meter_type ());
2219         send->set_metering (true);
2220         _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2221
2222         gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2223         gain_meter().setup_meters ();
2224
2225         uint32_t const in = _current_delivery->pans_required();
2226         uint32_t const out = _current_delivery->pan_outs();
2227
2228         panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2229         panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2230         panner_ui().setup_pan ();
2231         panner_ui().set_send_drawing_mode (true);
2232         panner_ui().show_all ();
2233
2234         input_button.set_sensitive (false);
2235         group_button.set_sensitive (false);
2236         set_invert_sensitive (false);
2237         gpm.meter_point_button.set_sensitive (false);
2238         mute_button->set_sensitive (false);
2239         solo_button->set_sensitive (false);
2240         rec_enable_button->set_sensitive (false);
2241         solo_isolated_led->set_sensitive (false);
2242         solo_safe_led->set_sensitive (false);
2243         monitor_input_button->set_sensitive (false);
2244         monitor_disk_button->set_sensitive (false);
2245         _comment_button.set_sensitive (false);
2246         trim_control.set_sensitive (false);
2247         if (midi_input_enable_button) {
2248                 midi_input_enable_button->set_sensitive (false);
2249         }
2250         control_slave_ui.set_sensitive (false);
2251
2252         if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2253                 output_button.set_sensitive (false);
2254         }
2255
2256         reset_strip_style ();
2257 }
2258
2259 void
2260 MixerStrip::revert_to_default_display ()
2261 {
2262         drop_send ();
2263
2264         set_current_delivery (_route->main_outs ());
2265
2266         gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2267         gain_meter().setup_meters ();
2268
2269         panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2270         update_panner_choices();
2271         panner_ui().setup_pan ();
2272         panner_ui().set_send_drawing_mode (false);
2273
2274         if (has_audio_outputs ()) {
2275                 panners.show_all ();
2276         } else {
2277                 panners.hide_all ();
2278         }
2279
2280         reset_strip_style ();
2281 }
2282
2283 void
2284 MixerStrip::set_button_names ()
2285 {
2286         switch (_width) {
2287         case Wide:
2288                 mute_button->set_text (_("Mute"));
2289                 monitor_input_button->set_text (_("In"));
2290                 monitor_disk_button->set_text (_("Disk"));
2291                 if (monitor_section_button) {
2292                         monitor_section_button->set_text (_("Mon"));
2293                 }
2294
2295                 if (_route && _route->solo_safe_control()->solo_safe()) {
2296                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2297                 } else {
2298                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2299                 }
2300                 if (!Config->get_solo_control_is_listen_control()) {
2301                         solo_button->set_text (_("Solo"));
2302                 } else {
2303                         switch (Config->get_listen_position()) {
2304                         case AfterFaderListen:
2305                                 solo_button->set_text (_("AFL"));
2306                                 break;
2307                         case PreFaderListen:
2308                                 solo_button->set_text (_("PFL"));
2309                                 break;
2310                         }
2311                 }
2312                 solo_isolated_led->set_text (_("Iso"));
2313                 solo_safe_led->set_text (S_("SoloLock|Lock"));
2314                 break;
2315
2316         default:
2317                 mute_button->set_text (S_("Mute|M"));
2318                 monitor_input_button->set_text (S_("MonitorInput|I"));
2319                 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2320                 if (monitor_section_button) {
2321                         monitor_section_button->set_text (S_("Mon|O"));
2322                 }
2323
2324                 if (_route && _route->solo_safe_control()->solo_safe()) {
2325                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2326                 } else {
2327                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2328                 }
2329                 if (!Config->get_solo_control_is_listen_control()) {
2330                         solo_button->set_text (S_("Solo|S"));
2331                 } else {
2332                         switch (Config->get_listen_position()) {
2333                         case AfterFaderListen:
2334                                 solo_button->set_text (S_("AfterFader|A"));
2335                                 break;
2336                         case PreFaderListen:
2337                                 solo_button->set_text (S_("Prefader|P"));
2338                                 break;
2339                         }
2340                 }
2341
2342                 solo_isolated_led->set_text (S_("SoloIso|I"));
2343                 solo_safe_led->set_text (S_("SoloLock|L"));
2344                 break;
2345         }
2346
2347         if (_route) {
2348                 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2349         } else {
2350                 gpm.meter_point_button.set_text ("");
2351         }
2352 }
2353
2354 PluginSelector*
2355 MixerStrip::plugin_selector()
2356 {
2357         return _mixer.plugin_selector();
2358 }
2359
2360 void
2361 MixerStrip::hide_things ()
2362 {
2363         processor_box.hide_things ();
2364 }
2365
2366 bool
2367 MixerStrip::input_active_button_press (GdkEventButton*)
2368 {
2369         /* nothing happens on press */
2370         return true;
2371 }
2372
2373 bool
2374 MixerStrip::input_active_button_release (GdkEventButton* ev)
2375 {
2376         boost::shared_ptr<MidiTrack> mt = midi_track ();
2377
2378         if (!mt) {
2379                 return true;
2380         }
2381
2382         boost::shared_ptr<RouteList> rl (new RouteList);
2383
2384         rl->push_back (route());
2385
2386         _session->set_exclusive_input_active (rl, !mt->input_active(),
2387                                               Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2388
2389         return true;
2390 }
2391
2392 void
2393 MixerStrip::midi_input_status_changed ()
2394 {
2395         if (midi_input_enable_button) {
2396                 boost::shared_ptr<MidiTrack> mt = midi_track ();
2397                 assert (mt);
2398                 midi_input_enable_button->set_active (mt->input_active ());
2399         }
2400 }
2401
2402 string
2403 MixerStrip::state_id () const
2404 {
2405         return string_compose ("strip %1", _route->id().to_s());
2406 }
2407
2408 void
2409 MixerStrip::parameter_changed (string p)
2410 {
2411         if (p == _visibility.get_state_name()) {
2412                 /* The user has made changes to the mixer strip visibility, so get
2413                    our VisibilityGroup to reflect these changes in our widgets.
2414                 */
2415                 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2416         } else if (p == "track-name-number") {
2417                 name_changed ();
2418                 update_track_number_visibility();
2419         }
2420 }
2421
2422 /** Called to decide whether the solo isolate / solo lock button visibility should
2423  *  be overridden from that configured by the user.  We do this for the master bus.
2424  *
2425  *  @return optional value that is present if visibility state should be overridden.
2426  */
2427 boost::optional<bool>
2428 MixerStrip::override_solo_visibility () const
2429 {
2430         if (_route && _route->is_master ()) {
2431                 return boost::optional<bool> (false);
2432         }
2433
2434         return boost::optional<bool> ();
2435 }
2436
2437 void
2438 MixerStrip::add_input_port (DataType t)
2439 {
2440         _route->input()->add_port ("", this, t);
2441 }
2442
2443 void
2444 MixerStrip::add_output_port (DataType t)
2445 {
2446         _route->output()->add_port ("", this, t);
2447 }
2448
2449 void
2450 MixerStrip::route_active_changed ()
2451 {
2452         reset_strip_style ();
2453 }
2454
2455 void
2456 MixerStrip::copy_processors ()
2457 {
2458         processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2459 }
2460
2461 void
2462 MixerStrip::cut_processors ()
2463 {
2464         processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2465 }
2466
2467 void
2468 MixerStrip::paste_processors ()
2469 {
2470         processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2471 }
2472
2473 void
2474 MixerStrip::select_all_processors ()
2475 {
2476         processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2477 }
2478
2479 void
2480 MixerStrip::deselect_all_processors ()
2481 {
2482         processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2483 }
2484
2485 bool
2486 MixerStrip::delete_processors ()
2487 {
2488         return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2489 }
2490
2491 void
2492 MixerStrip::toggle_processors ()
2493 {
2494         processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2495 }
2496
2497 void
2498 MixerStrip::ab_plugins ()
2499 {
2500         processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2501 }
2502
2503 bool
2504 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2505 {
2506         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2507                 return false;
2508         }
2509         if (ev->button == 3) {
2510                 popup_level_meter_menu (ev);
2511                 return true;
2512         }
2513
2514         return false;
2515 }
2516
2517 void
2518 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2519 {
2520         using namespace Gtk::Menu_Helpers;
2521
2522         Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
2523         MenuList& items = m->items ();
2524
2525         RadioMenuItem::Group group;
2526
2527         PBD::Unwinder<bool> uw (_suspend_menu_callbacks, true);
2528         add_level_meter_item_point (items, group, _("Input"), MeterInput);
2529         add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2530         add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2531         add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2532         add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2533
2534         if (gpm.meter_channels().n_audio() == 0) {
2535                 m->popup (ev->button, ev->time);
2536                 return;
2537         }
2538
2539         RadioMenuItem::Group tgroup;
2540         items.push_back (SeparatorElem());
2541
2542         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2543         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2544         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms),  MeterKrms);
2545         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2546         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2547         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2548         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2549         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2550         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2551         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2552         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU),  MeterVU);
2553
2554         int _strip_type;
2555         if (_route->is_master()) {
2556                 _strip_type = 4;
2557         }
2558         else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2559                         && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2560                 /* non-master bus */
2561                 _strip_type = 3;
2562         }
2563         else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2564                 _strip_type = 2;
2565         }
2566         else {
2567                 _strip_type = 1;
2568         }
2569
2570         MeterType cmt = _route->meter_type();
2571         const std::string cmn = ArdourMeter::meter_type_string(cmt);
2572
2573         items.push_back (SeparatorElem());
2574         items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2575                                 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2576         items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2577                                 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2578         items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2579                                 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2580
2581         m->popup (ev->button, ev->time);
2582 }
2583
2584 void
2585 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2586                 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2587 {
2588         using namespace Menu_Helpers;
2589
2590         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2591         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2592         i->set_active (_route->meter_point() == point);
2593 }
2594
2595 void
2596 MixerStrip::set_meter_point (MeterPoint p)
2597 {
2598         if (_suspend_menu_callbacks) return;
2599         _route->set_meter_point (p);
2600 }
2601
2602 void
2603 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2604                 RadioMenuItem::Group& group, string const & name, MeterType type)
2605 {
2606         using namespace Menu_Helpers;
2607
2608         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2609         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2610         i->set_active (_route->meter_type() == type);
2611 }
2612
2613 void
2614 MixerStrip::set_meter_type (MeterType t)
2615 {
2616         if (_suspend_menu_callbacks) return;
2617         _route->set_meter_type (t);
2618 }
2619
2620 void
2621 MixerStrip::update_track_number_visibility ()
2622 {
2623         DisplaySuspender ds;
2624         bool show_label = _session->config.get_track_name_number();
2625
2626         if (_route && _route->is_master()) {
2627                 show_label = false;
2628         }
2629
2630         if (show_label) {
2631                 number_label.show ();
2632                 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2633                 // except the width of the number label is subtracted from the name-hbox, so we
2634                 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2635                 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2636                 if (tnw & 1) --tnw;
2637                 number_label.set_size_request(tnw, -1);
2638                 number_label.show ();
2639         } else {
2640                 number_label.hide ();
2641         }
2642 }
2643
2644 Gdk::Color
2645 MixerStrip::color () const
2646 {
2647         return route_color ();
2648 }
2649
2650 bool
2651 MixerStrip::marked_for_display () const
2652 {
2653         return !_route->presentation_info().hidden();
2654 }
2655
2656 bool
2657 MixerStrip::set_marked_for_display (bool yn)
2658 {
2659         return RouteUI::mark_hidden (!yn);
2660 }
2661
2662 void
2663 MixerStrip::hide_master_spacer (bool yn)
2664 {
2665         if (_mixer_owned && route()->is_master() && !yn) {
2666                 spacer.show();
2667         } else {
2668                 spacer.hide();
2669         }
2670 }