use new method in MidiPatchManager to use MIDNAM data when setting a MidiTimeAxisView
[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         gpm.gain_automation_state_button.set_text (GainMeterBase::short_astate_string (gain_automation->automation_state()));
786
787         if (_route->panner()) {
788                 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (GainMeterBase::short_astate_string (_route->panner()->automation_state()));
789         }
790
791         switch (w) {
792         case Wide:
793
794                 if (show_sends_button)  {
795                         show_sends_button->set_text (_("Aux"));
796                 }
797
798                 {
799                         // panners expect an even number of horiz. pixels
800                         int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
801                         width &= ~1;
802                         set_size_request (width, -1);
803                 }
804                 break;
805
806         case Narrow:
807
808                 if (show_sends_button) {
809                         show_sends_button->set_text (_("Snd"));
810                 }
811
812                 gain_meter().setup_meters (); // recalc meter width
813
814                 {
815                         // panners expect an even number of horiz. pixels
816                         int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
817                         width &= ~1;
818                         set_size_request (width, -1);
819                 }
820                 break;
821         }
822
823         processor_box.set_width (w);
824
825         update_input_display ();
826         update_output_display ();
827         setup_comment_button ();
828         route_group_changed ();
829         name_changed ();
830         WidthChanged ();
831 }
832
833 void
834 MixerStrip::set_packed (bool yn)
835 {
836         _packed = yn;
837         set_gui_property ("visible", _packed);
838 }
839
840
841 struct RouteCompareByName {
842         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
843                 return a->name().compare (b->name()) < 0;
844         }
845 };
846
847 gint
848 MixerStrip::output_release (GdkEventButton *ev)
849 {
850         switch (ev->button) {
851         case 3:
852                 edit_output_configuration ();
853                 break;
854         }
855
856         return false;
857 }
858
859 gint
860 MixerStrip::output_press (GdkEventButton *ev)
861 {
862         using namespace Menu_Helpers;
863         if (!ARDOUR_UI_UTILS::engine_is_running ()) {
864                 return true;
865         }
866
867         MenuList& citems = output_menu.items();
868         switch (ev->button) {
869
870         case 3:
871                 return false;  //wait for the mouse-up to pop the dialog
872
873         case 1:
874         {
875                 output_menu.set_name ("ArdourContextMenu");
876                 citems.clear ();
877                 output_menu_bundles.clear ();
878
879                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
880
881                 citems.push_back (SeparatorElem());
882                 uint32_t const n_with_separator = citems.size ();
883
884                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
885
886                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
887
888                 /* guess the user-intended main type of the route output */
889                 DataType intended_type = guess_main_type(false);
890
891                 /* try adding the master bus first */
892                 boost::shared_ptr<Route> master = _session->master_out();
893                 if (master) {
894                         maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
895                 }
896
897                 /* then other routes inputs */
898                 RouteList copy = _session->get_routelist ();
899                 copy.sort (RouteCompareByName ());
900                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
901                         maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
902                 }
903
904                 /* then try adding user bundles, often labeled/grouped physical inputs */
905                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
906                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
907                                 maybe_add_bundle_to_output_menu (*i, current, intended_type);
908                         }
909                 }
910
911                 /* then all other bundles, including physical outs or other sofware */
912                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
913                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
914                                 maybe_add_bundle_to_output_menu (*i, current, intended_type);
915                         }
916                 }
917
918                 if (citems.size() == n_with_separator) {
919                         /* no routes added; remove the separator */
920                         citems.pop_back ();
921                 }
922
923                 citems.push_back (SeparatorElem());
924
925                 if (!ARDOUR::Profile->get_mixbus()) {
926                         bool need_separator = false;
927                         for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
928                                 if (!_route->output()->can_add_port (*i)) {
929                                         continue;
930                                 }
931                                 need_separator = true;
932                                 citems.push_back (
933                                                 MenuElem (
934                                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
935                                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
936                                                         )
937                                                 );
938                         }
939                         if (need_separator) {
940                                 citems.push_back (SeparatorElem());
941                         }
942                 }
943
944                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
945
946                 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
947                                                1, ev->time);
948
949                 break;
950         }
951
952         default:
953                 break;
954         }
955         return TRUE;
956 }
957
958 gint
959 MixerStrip::input_release (GdkEventButton *ev)
960 {
961         switch (ev->button) {
962
963         case 3:
964                 edit_input_configuration ();
965                 break;
966         default:
967                 break;
968
969         }
970
971         return false;
972 }
973
974
975 gint
976 MixerStrip::input_press (GdkEventButton *ev)
977 {
978         using namespace Menu_Helpers;
979
980         MenuList& citems = input_menu.items();
981         input_menu.set_name ("ArdourContextMenu");
982         citems.clear();
983
984         if (!ARDOUR_UI_UTILS::engine_is_running ()) {
985                 return true;
986         }
987
988         if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
989                 return true;
990
991         switch (ev->button) {
992
993         case 3:
994                 return false;  //don't handle the mouse-down here.  wait for mouse-up to pop the menu
995
996         case 1:
997         {
998                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
999
1000                 citems.push_back (SeparatorElem());
1001                 uint32_t const n_with_separator = citems.size ();
1002
1003                 input_menu_bundles.clear ();
1004
1005                 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1006
1007                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1008
1009                 /* give user bundles first chance at being in the menu */
1010
1011                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1012                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1013                                 maybe_add_bundle_to_input_menu (*i, current);
1014                         }
1015                 }
1016
1017                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1018                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1019                                 maybe_add_bundle_to_input_menu (*i, current);
1020                         }
1021                 }
1022
1023                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1024                 RouteList copy = *routes;
1025                 copy.sort (RouteCompareByName ());
1026                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1027                         maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1028                 }
1029
1030                 if (citems.size() == n_with_separator) {
1031                         /* no routes added; remove the separator */
1032                         citems.pop_back ();
1033                 }
1034
1035                 citems.push_back (SeparatorElem());
1036
1037                 bool need_separator = false;
1038                 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1039                         if (!_route->input()->can_add_port (*i)) {
1040                                 continue;
1041                         }
1042                         need_separator = true;
1043                         citems.push_back (
1044                                 MenuElem (
1045                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1046                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1047                                         )
1048                                 );
1049                 }
1050                 if (need_separator) {
1051                         citems.push_back (SeparatorElem());
1052                 }
1053
1054                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1055
1056                 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1057                                                1, ev->time);
1058
1059                 break;
1060         }
1061         default:
1062                 break;
1063         }
1064         return TRUE;
1065 }
1066
1067 void
1068 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1069 {
1070         if (ignore_toggle) {
1071                 return;
1072         }
1073
1074         _route->input()->connect_ports_to_bundle (c, true, this);
1075 }
1076
1077 void
1078 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1079 {
1080         if (ignore_toggle) {
1081                 return;
1082         }
1083
1084         _route->output()->connect_ports_to_bundle (c, true, true, this);
1085 }
1086
1087 void
1088 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1089 {
1090         using namespace Menu_Helpers;
1091
1092         if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1093                 return;
1094         }
1095
1096         list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1097         while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1098                 ++i;
1099         }
1100
1101         if (i != input_menu_bundles.end()) {
1102                 return;
1103         }
1104
1105         input_menu_bundles.push_back (b);
1106
1107         MenuList& citems = input_menu.items();
1108         citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1109 }
1110
1111 void
1112 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1113                                              DataType type)
1114 {
1115         using namespace Menu_Helpers;
1116
1117         /* The bundle should be an input one, but not ours */
1118         if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1119                 return;
1120         }
1121
1122         /* Don't add the monitor input unless we are Master */
1123         boost::shared_ptr<Route> monitor = _session->monitor_out();
1124         if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1125                 return;
1126
1127         /* It should either match exactly our outputs (if |type| is DataType::NIL)
1128          * or have the same number of |type| channels than our outputs. */
1129         if (type == DataType::NIL) {
1130                 if(b->nchannels() != _route->n_outputs())
1131                         return;
1132         } else {
1133                 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1134                         return;
1135         }
1136
1137         /* Avoid adding duplicates */
1138         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1139         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1140                 ++i;
1141         }
1142         if (i != output_menu_bundles.end()) {
1143                 return;
1144         }
1145
1146         /* Now add the bundle to the menu */
1147         output_menu_bundles.push_back (b);
1148
1149         MenuList& citems = output_menu.items();
1150         citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1151 }
1152
1153 void
1154 MixerStrip::update_diskstream_display ()
1155 {
1156         if (is_track() && input_selector) {
1157                 input_selector->hide_all ();
1158         }
1159
1160         route_color_changed ();
1161 }
1162
1163 void
1164 MixerStrip::connect_to_pan ()
1165 {
1166         ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1167
1168         panstate_connection.disconnect ();
1169         panstyle_connection.disconnect ();
1170
1171         if (!_route->panner()) {
1172                 return;
1173         }
1174
1175         boost::shared_ptr<Pannable> p = _route->pannable ();
1176
1177         p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1178
1179         /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1180          * However, that only works a panner was previously set.
1181          *
1182          * PannerUI must remain subscribed to _panshell->Changed() in case
1183          * we switch the panner eg. AUX-Send and back
1184          * _route->panner_shell()->Changed() vs _panshell->Changed
1185          */
1186         if (panners._panner == 0) {
1187                 panners.panshell_changed ();
1188         }
1189         update_panner_choices();
1190 }
1191
1192 void
1193 MixerStrip::update_panner_choices ()
1194 {
1195         ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1196         if (!_route->panner_shell()) { return; }
1197
1198         uint32_t in = _route->output()->n_ports().n_audio();
1199         uint32_t out = in;
1200         if (_route->panner()) {
1201                 in = _route->panner()->in().n_audio();
1202         }
1203
1204         panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1205 }
1206
1207 DataType
1208 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1209 {
1210         /* The heuristic follows these principles:
1211          *  A) If all ports that the user connected are of the same type, then he
1212          *     very probably intends to use the IO with that type. A common subcase
1213          *     is when the IO has only ports of the same type (connected or not).
1214          *  B) If several types of ports are connected, then we should guess based
1215          *     on the likeliness of the user wanting to use a given type.
1216          *     We assume that the DataTypes are ordered from the most likely to the
1217          *     least likely when iterating or comparing them with "<".
1218          *  C) If no port is connected, the same logic can be applied with all ports
1219          *     instead of connected ones. TODO: Try other ideas, for instance look at
1220          *     the last plugin output when |for_input| is false (note: when StrictIO
1221          *     the outs of the last plugin should be the same as the outs of the route
1222          *     modulo the panner which forwards non-audio anyway).
1223          * All of these constraints are respected by the following algorithm that
1224          * just returns the most likely datatype found in connected ports if any, or
1225          * available ports if any (since if all ports are of the same type, the most
1226          * likely found will be that one obviously). */
1227
1228         boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1229
1230         /* Find most likely type among connected ports */
1231         if (favor_connected) {
1232                 DataType type = DataType::NIL; /* NIL is always last so least likely */
1233                 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1234                         if (p->connected() && p->type() < type)
1235                                 type = p->type();
1236                 }
1237                 if (type != DataType::NIL) {
1238                         /* There has been a connected port (necessarily non-NIL) */
1239                         return type;
1240                 }
1241         }
1242
1243         /* Find most likely type among available ports.
1244          * The iterator stops before NIL. */
1245         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1246                 if (io->n_ports().n(*t) > 0)
1247                         return *t;
1248         }
1249
1250         /* No port at all, return the most likely datatype by default */
1251         return DataType::front();
1252 }
1253
1254 /*
1255  * Output port labelling
1256  *
1257  * Case 1: Each output has one connection, all connections are to system:playback_%i
1258  *   out 1 -> system:playback_1
1259  *   out 2 -> system:playback_2
1260  *   out 3 -> system:playback_3
1261  *   Display as: 1/2/3
1262  *
1263  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1264  *   out 1 -> ardour:track_x/in 1
1265  *   out 2 -> ardour:track_x/in 2
1266  *   Display as: track_x
1267  *
1268  * Case 3: Each output has one connection, all connections are to Jack client "program x"
1269  *   out 1 -> program x:foo
1270  *   out 2 -> program x:foo
1271  *   Display as: program x
1272  *
1273  * Case 4: No connections (Disconnected)
1274  *   Display as: -
1275  *
1276  * Default case (unusual routing):
1277  *   Display as: *number of connections*
1278  *
1279  *
1280  * Tooltips
1281  *
1282  * .-----------------------------------------------.
1283  * | Mixdown                                       |
1284  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1285  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1286  * '-----------------------------------------------'
1287  * .-----------------------------------------------.
1288  * | Guitar SM58                                   |
1289  * | Disconnected                                  |
1290  * '-----------------------------------------------'
1291  */
1292
1293 void
1294 MixerStrip::update_io_button (bool for_input)
1295 {
1296         ostringstream tooltip;
1297         ostringstream label;
1298         bool have_label = false;
1299
1300         uint32_t total_connection_count = 0;
1301         uint32_t typed_connection_count = 0;
1302         bool each_typed_port_has_one_connection = true;
1303
1304         DataType dt = guess_main_type(for_input);
1305         boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1306
1307         /* Fill in the tooltip. Also count:
1308          *  - The total number of connections.
1309          *  - The number of main-typed connections.
1310          *  - Whether each main-typed port has exactly one connection. */
1311         if (for_input) {
1312                 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1313                                 Gtkmm2ext::markup_escape_text (_route->name()));
1314         } else {
1315                 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1316                                 Gtkmm2ext::markup_escape_text (_route->name()));
1317         }
1318
1319         string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1320         vector<string> port_connections;
1321         for (PortSet::iterator port = io->ports().begin();
1322                                port != io->ports().end();
1323                                ++port) {
1324                 port_connections.clear();
1325                 port->get_connections(port_connections);
1326
1327                 uint32_t port_connection_count = 0;
1328
1329                 for (vector<string>::iterator i = port_connections.begin();
1330                                               i != port_connections.end();
1331                                               ++i) {
1332                         ++port_connection_count;
1333
1334                         if (port_connection_count == 1) {
1335                                 tooltip << endl << Gtkmm2ext::markup_escape_text (
1336                                                 port->name().substr(port->name().find("/") + 1));
1337                                 tooltip << arrow;
1338                         } else {
1339                                 tooltip << ", ";
1340                         }
1341
1342                         tooltip << Gtkmm2ext::markup_escape_text(*i);
1343                 }
1344
1345                 total_connection_count += port_connection_count;
1346                 if (port->type() == dt) {
1347                         typed_connection_count += port_connection_count;
1348                         each_typed_port_has_one_connection &= (port_connection_count == 1);
1349                 }
1350
1351         }
1352
1353         if (total_connection_count == 0) {
1354                 tooltip << endl << _("Disconnected");
1355         }
1356
1357         if (typed_connection_count == 0) {
1358                 label << "-";
1359                 have_label = true;
1360         }
1361
1362         /* Are all main-typed channels connected to the same route ? */
1363         if (!have_label) {
1364                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1365                 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1366                                                        route != routes->end();
1367                                                        ++route) {
1368                         boost::shared_ptr<IO> dest_io =
1369                                 for_input ? (*route)->output() : (*route)->input();
1370                         if (io->bundle()->connected_to(dest_io->bundle(),
1371                                                        _session->engine(),
1372                                                        dt, true)) {
1373                                 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1374                                 have_label = true;
1375                                 break;
1376                         }
1377                 }
1378         }
1379
1380         /* Are all main-typed channels connected to the same (user) bundle ? */
1381         if (!have_label) {
1382                 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1383                 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1384                                                   bundle != bundles->end();
1385                                                   ++bundle) {
1386                         if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1387                                 continue;
1388                         if (io->bundle()->connected_to(*bundle, _session->engine(),
1389                                                        dt, true)) {
1390                                 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1391                                 have_label = true;
1392                                 break;
1393                         }
1394                 }
1395         }
1396
1397         /* Is each main-typed channel only connected to a physical output ? */
1398         if (!have_label && each_typed_port_has_one_connection) {
1399                 ostringstream temp_label;
1400                 vector<string> phys;
1401                 string playorcapture;
1402                 if (for_input) {
1403                         _session->engine().get_physical_inputs(dt, phys);
1404                         playorcapture = "capture_";
1405                 } else {
1406                         _session->engine().get_physical_outputs(dt, phys);
1407                         playorcapture = "playback_";
1408                 }
1409                 for (PortSet::iterator port = io->ports().begin(dt);
1410                                        port != io->ports().end(dt);
1411                                        ++port) {
1412                         string pn = "";
1413                         for (vector<string>::iterator s = phys.begin();
1414                                                       s != phys.end();
1415                                                       ++s) {
1416                                 if (!port->connected_to(*s))
1417                                         continue;
1418                                 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1419                                 if (pn.empty()) {
1420                                         string::size_type start = (*s).find(playorcapture);
1421                                         if (start != string::npos) {
1422                                                 pn = (*s).substr(start + playorcapture.size());
1423                                         }
1424                                 }
1425                                 break;
1426                         }
1427                         if (pn.empty()) {
1428                                 temp_label.str(""); /* erase the failed attempt */
1429                                 break;
1430                         }
1431                         if (port != io->ports().begin(dt))
1432                                 temp_label << "/";
1433                         temp_label << pn;
1434                 }
1435
1436                 if (!temp_label.str().empty()) {
1437                         label << temp_label.str();
1438                         have_label = true;
1439                 }
1440         }
1441
1442         /* Is each main-typed channel connected to a single and different port with
1443          * the same client name (e.g. another JACK client) ? */
1444         if (!have_label && each_typed_port_has_one_connection) {
1445                 string maybe_client = "";
1446                 vector<string> connections;
1447                 for (PortSet::iterator port = io->ports().begin(dt);
1448                                        port != io->ports().end(dt);
1449                                        ++port) {
1450                         port_connections.clear();
1451                         port->get_connections(port_connections);
1452                         string connection = port_connections.front();
1453
1454                         vector<string>::iterator i = connections.begin();
1455                         while (i != connections.end() && *i != connection) {
1456                                 ++i;
1457                         }
1458                         if (i != connections.end())
1459                                 break; /* duplicate connection */
1460                         connections.push_back(connection);
1461
1462                         connection = connection.substr(0, connection.find(":"));
1463                         if (maybe_client.empty())
1464                                 maybe_client = connection;
1465                         if (maybe_client != connection)
1466                                 break;
1467                 }
1468                 if (connections.size() == io->n_ports().n(dt)) {
1469                         label << maybe_client;
1470                         have_label = true;
1471                 }
1472         }
1473
1474         /* Odd configuration */
1475         if (!have_label) {
1476                 label << "*" << total_connection_count << "*";
1477         }
1478
1479         if (total_connection_count > typed_connection_count) {
1480                 label << "\u2295"; /* circled plus */
1481         }
1482
1483         /* Actually set the properties of the button */
1484         char * cstr = new char[tooltip.str().size() + 1];
1485         strcpy(cstr, tooltip.str().c_str());
1486
1487         if (for_input) {
1488                 input_button.set_text (label.str());
1489                 set_tooltip (&input_button, cstr);
1490         } else {
1491                 output_button.set_text (label.str());
1492                 set_tooltip (&output_button, cstr);
1493         }
1494
1495         delete [] cstr;
1496 }
1497
1498 void
1499 MixerStrip::update_input_display ()
1500 {
1501         update_io_button (true);
1502         panners.setup_pan ();
1503
1504         if (has_audio_outputs ()) {
1505                 panners.show_all ();
1506         } else {
1507                 panners.hide_all ();
1508         }
1509
1510 }
1511
1512 void
1513 MixerStrip::update_output_display ()
1514 {
1515         update_io_button (false);
1516         gpm.setup_meters ();
1517         panners.setup_pan ();
1518
1519         if (has_audio_outputs ()) {
1520                 panners.show_all ();
1521         } else {
1522                 panners.hide_all ();
1523         }
1524 }
1525
1526 void
1527 MixerStrip::fast_update ()
1528 {
1529         gpm.update_meters ();
1530 }
1531
1532 void
1533 MixerStrip::diskstream_changed ()
1534 {
1535         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1536 }
1537
1538 void
1539 MixerStrip::io_changed_proxy ()
1540 {
1541         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1542         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1543 }
1544
1545 void
1546 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1547 {
1548         boost::shared_ptr<Port> a = wa.lock ();
1549         boost::shared_ptr<Port> b = wb.lock ();
1550
1551         if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1552                 update_input_display ();
1553                 set_width_enum (_width, this);
1554         }
1555
1556         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1557                 update_output_display ();
1558                 set_width_enum (_width, this);
1559         }
1560 }
1561
1562 void
1563 MixerStrip::setup_comment_button ()
1564 {
1565         std::string comment = _route->comment();
1566
1567         set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1568
1569         if (comment.empty ()) {
1570                 _comment_button.set_name ("generic button");
1571                 _comment_button.set_text (_width  == Wide ? _("Comments") : _("Cmt"));
1572                 return;
1573         }
1574
1575         _comment_button.set_name ("comment button");
1576
1577         string::size_type pos = comment.find_first_of (" \t\n");
1578         if (pos != string::npos) {
1579                 comment = comment.substr (0, pos);
1580         }
1581         if (comment.empty()) {
1582                 _comment_button.set_text (_width  == Wide ? _("Comments") : _("Cmt"));
1583         } else {
1584                 _comment_button.set_text (comment);
1585         }
1586 }
1587
1588 bool
1589 MixerStrip::select_route_group (GdkEventButton *ev)
1590 {
1591         using namespace Menu_Helpers;
1592
1593         if (ev->button == 1) {
1594
1595                 if (group_menu == 0) {
1596
1597                         PropertyList* plist = new PropertyList();
1598
1599                         plist->add (Properties::group_gain, true);
1600                         plist->add (Properties::group_mute, true);
1601                         plist->add (Properties::group_solo, true);
1602
1603                         group_menu = new RouteGroupMenu (_session, plist);
1604                 }
1605
1606                 WeakRouteList r;
1607                 r.push_back (route ());
1608                 group_menu->build (r);
1609
1610                 RouteGroup *rg = _route->route_group();
1611
1612                 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1613                                                rg ? rg->name() : _("No Group"),
1614                                                1, ev->time);
1615         }
1616
1617         return true;
1618 }
1619
1620 void
1621 MixerStrip::route_group_changed ()
1622 {
1623         ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1624
1625         RouteGroup *rg = _route->route_group();
1626
1627         if (rg) {
1628                 group_button.set_text (PBD::short_version (rg->name(), 5));
1629         } else {
1630                 switch (_width) {
1631                 case Wide:
1632                         group_button.set_text (_("Grp"));
1633                         break;
1634                 case Narrow:
1635                         group_button.set_text (_("~G"));
1636                         break;
1637                 }
1638         }
1639 }
1640
1641 void
1642 MixerStrip::route_color_changed ()
1643 {
1644         using namespace ARDOUR_UI_UTILS;
1645         name_button.modify_bg (STATE_NORMAL, color());
1646         number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1647         reset_strip_style ();
1648 }
1649
1650 void
1651 MixerStrip::show_passthru_color ()
1652 {
1653         reset_strip_style ();
1654 }
1655
1656
1657 void
1658 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1659 {
1660         boost::shared_ptr<Processor> processor (p.lock ());
1661         if (!processor || !processor->display_to_user()) {
1662                 return;
1663         }
1664         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1665 #ifdef MIXBUS
1666         if (pi && pi->is_channelstrip ()) {
1667                 return;
1668         }
1669 #endif
1670         if (pi) {
1671                 ++_plugin_insert_cnt;
1672         }
1673 }
1674 void
1675 MixerStrip::build_route_ops_menu ()
1676 {
1677         using namespace Menu_Helpers;
1678         route_ops_menu = new Menu;
1679         route_ops_menu->set_name ("ArdourContextMenu");
1680
1681         MenuList& items = route_ops_menu->items();
1682
1683         items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1684
1685         items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1686
1687         items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1688
1689         items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1690
1691         if (!Profile->get_mixbus()) {
1692                 items.push_back (SeparatorElem());
1693         }
1694
1695         if (!_route->is_master()
1696 #ifdef MIXBUS
1697                         && !_route->mixbus()
1698 #endif
1699                         ) {
1700                 if (Profile->get_mixbus()) {
1701                         items.push_back (SeparatorElem());
1702                 }
1703                 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1704         }
1705
1706         if (!Profile->get_mixbus()) {
1707                 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1708                 /* do not allow rename if the track is record-enabled */
1709                 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1710         }
1711
1712         items.push_back (SeparatorElem());
1713         items.push_back (CheckMenuElem (_("Active")));
1714         Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1715         i->set_active (_route->active());
1716         i->set_sensitive(! _session->transport_rolling());
1717         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1718
1719         if (!Profile->get_mixbus ()) {
1720                 items.push_back (SeparatorElem());
1721                 items.push_back (CheckMenuElem (_("Strict I/O")));
1722                 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1723                 i->set_active (_route->strict_io());
1724                 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1725         }
1726
1727         if (is_track()) {
1728                 items.push_back (SeparatorElem());
1729
1730                 Gtk::Menu* dio_menu = new Menu;
1731                 MenuList& dio_items = dio_menu->items();
1732                 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1733                 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1734                 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1735
1736                 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1737         }
1738
1739         _plugin_insert_cnt = 0;
1740         _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1741         if (_plugin_insert_cnt > 0) {
1742                 items.push_back (SeparatorElem());
1743                 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1744         }
1745
1746         if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1747                 items.push_back (MenuElem (_("Patch Selector..."),
1748                                         sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1749         }
1750
1751         if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1752                 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1753                 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1754                 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1755         }
1756
1757         items.push_back (SeparatorElem());
1758         items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1759         denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1760         denormal_menu_item->set_active (_route->denormal_protection());
1761
1762         if (_route) {
1763                 /* note that this relies on selection being shared across editor and
1764                    mixer (or global to the backend, in the future), which is the only
1765                    sane thing for users anyway.
1766                 */
1767
1768                 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1769                 if (stav) {
1770                         Selection& selection (PublicEditor::instance().get_selection());
1771                         if (!selection.selected (stav)) {
1772                                 selection.set (stav);
1773                         }
1774
1775                         if (!_route->is_master()) {
1776                                 items.push_back (SeparatorElem());
1777                                 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1778                         }
1779
1780                         items.push_back (SeparatorElem());
1781                         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1782                 }
1783         }
1784 }
1785
1786 gboolean
1787 MixerStrip::name_button_button_press (GdkEventButton* ev)
1788 {
1789         if (ev->button == 1 || ev->button == 3) {
1790                 list_route_operations ();
1791
1792                 if (ev->button == 1) {
1793                         Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1794                                                        1, ev->time);
1795                 } else {
1796                         route_ops_menu->popup (3, ev->time);
1797                 }
1798
1799                 return true;
1800         }
1801
1802         return false;
1803 }
1804
1805 gboolean
1806 MixerStrip::number_button_button_press (GdkEventButton* ev)
1807 {
1808         if (  ev->button == 3 ) {
1809                 list_route_operations ();
1810
1811                 route_ops_menu->popup (1, ev->time);
1812
1813                 return true;
1814         }
1815
1816         return false;
1817 }
1818
1819 void
1820 MixerStrip::list_route_operations ()
1821 {
1822         delete route_ops_menu;
1823         build_route_ops_menu ();
1824 }
1825
1826 void
1827 MixerStrip::set_selected (bool yn)
1828 {
1829         AxisView::set_selected (yn);
1830
1831         if (selected()) {
1832                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1833                 global_frame.set_name ("MixerStripSelectedFrame");
1834         } else {
1835                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1836                 global_frame.set_name ("MixerStripFrame");
1837         }
1838
1839         global_frame.queue_draw ();
1840
1841 //      if (!yn)
1842 //              processor_box.deselect_all_processors();
1843 }
1844
1845 void
1846 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1847 {
1848         if (what_changed.contains (ARDOUR::Properties::name)) {
1849                 name_changed ();
1850         }
1851 }
1852
1853 void
1854 MixerStrip::name_changed ()
1855 {
1856         switch (_width) {
1857                 case Wide:
1858                         name_button.set_text (_route->name());
1859                         break;
1860                 case Narrow:
1861                         name_button.set_text (PBD::short_version (_route->name(), 5));
1862                         break;
1863         }
1864
1865         set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1866
1867         if (_session->config.get_track_name_number()) {
1868                 const int64_t track_number = _route->track_number ();
1869                 if (track_number == 0) {
1870                         number_label.set_text ("-");
1871                 } else {
1872                         number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1873                 }
1874         } else {
1875                 number_label.set_text ("");
1876         }
1877 }
1878
1879 void
1880 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1881 {
1882         input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1883 }
1884
1885 void
1886 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1887 {
1888         output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1889 }
1890
1891 void
1892 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1893 {
1894         name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1895 }
1896
1897 void
1898 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1899 {
1900         _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1901 }
1902
1903 bool
1904 MixerStrip::width_button_pressed (GdkEventButton* ev)
1905 {
1906         if (ev->button != 1) {
1907                 return false;
1908         }
1909
1910         if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1911                 switch (_width) {
1912                 case Wide:
1913                         _mixer.set_strip_width (Narrow, true);
1914                         break;
1915
1916                 case Narrow:
1917                         _mixer.set_strip_width (Wide, true);
1918                         break;
1919                 }
1920         } else {
1921                 switch (_width) {
1922                 case Wide:
1923                         set_width_enum (Narrow, this);
1924                         break;
1925                 case Narrow:
1926                         set_width_enum (Wide, this);
1927                         break;
1928                 }
1929         }
1930
1931         return true;
1932 }
1933
1934 void
1935 MixerStrip::hide_clicked ()
1936 {
1937         // LAME fix to reset the button status for when it is redisplayed (part 1)
1938         hide_button.set_sensitive(false);
1939
1940         if (_embedded) {
1941                 Hiding(); /* EMIT_SIGNAL */
1942         } else {
1943                 _mixer.hide_strip (this);
1944         }
1945
1946         // (part 2)
1947         hide_button.set_sensitive(true);
1948 }
1949
1950 void
1951 MixerStrip::set_embedded (bool yn)
1952 {
1953         _embedded = yn;
1954 }
1955
1956 void
1957 MixerStrip::map_frozen ()
1958 {
1959         ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1960
1961         boost::shared_ptr<AudioTrack> at = audio_track();
1962
1963         if (at) {
1964                 switch (at->freeze_state()) {
1965                 case AudioTrack::Frozen:
1966                         processor_box.set_sensitive (false);
1967                         hide_redirect_editors ();
1968                         break;
1969                 default:
1970                         processor_box.set_sensitive (true);
1971                         // XXX need some way, maybe, to retoggle redirect editors
1972                         break;
1973                 }
1974         } else {
1975                 processor_box.set_sensitive (true);
1976         }
1977         RouteUI::map_frozen ();
1978 }
1979
1980 void
1981 MixerStrip::hide_redirect_editors ()
1982 {
1983         _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1984 }
1985
1986 void
1987 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1988 {
1989         boost::shared_ptr<Processor> processor (p.lock ());
1990         if (!processor) {
1991                 return;
1992         }
1993
1994         Gtk::Window* w = processor_box.get_processor_ui (processor);
1995
1996         if (w) {
1997                 w->hide ();
1998         }
1999 }
2000
2001 void
2002 MixerStrip::reset_strip_style ()
2003 {
2004         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2005
2006                 gpm.set_fader_name ("SendStripBase");
2007
2008         } else {
2009
2010                 if (is_midi_track()) {
2011                         if (_route->active()) {
2012                                 set_name ("MidiTrackStripBase");
2013                         } else {
2014                                 set_name ("MidiTrackStripBaseInactive");
2015                         }
2016                         gpm.set_fader_name ("MidiTrackFader");
2017                 } else if (is_audio_track()) {
2018                         if (_route->active()) {
2019                                 set_name ("AudioTrackStripBase");
2020                         } else {
2021                                 set_name ("AudioTrackStripBaseInactive");
2022                         }
2023                         gpm.set_fader_name ("AudioTrackFader");
2024                 } else {
2025                         if (_route->active()) {
2026                                 set_name ("AudioBusStripBase");
2027                         } else {
2028                                 set_name ("AudioBusStripBaseInactive");
2029                         }
2030                         gpm.set_fader_name ("AudioBusFader");
2031
2032                         /* (no MIDI busses yet) */
2033                 }
2034         }
2035 }
2036
2037
2038 string
2039 MixerStrip::meter_point_string (MeterPoint mp)
2040 {
2041         switch (_width) {
2042         case Wide:
2043                 switch (mp) {
2044                 case MeterInput:
2045                         return _("In");
2046                         break;
2047
2048                 case MeterPreFader:
2049                         return _("Pre");
2050                         break;
2051
2052                 case MeterPostFader:
2053                         return _("Post");
2054                         break;
2055
2056                 case MeterOutput:
2057                         return _("Out");
2058                         break;
2059
2060                 case MeterCustom:
2061                 default:
2062                         return _("Custom");
2063                         break;
2064                 }
2065                 break;
2066         case Narrow:
2067                 switch (mp) {
2068                 case MeterInput:
2069                         return S_("Meter|In");
2070                         break;
2071
2072                 case MeterPreFader:
2073                         return S_("Meter|Pr");
2074                         break;
2075
2076                 case MeterPostFader:
2077                         return S_("Meter|Po");
2078                         break;
2079
2080                 case MeterOutput:
2081                         return S_("Meter|O");
2082                         break;
2083
2084                 case MeterCustom:
2085                 default:
2086                         return S_("Meter|C");
2087                         break;
2088                 }
2089                 break;
2090         }
2091
2092         return string();
2093 }
2094
2095 /** Called when the monitor-section state */
2096 void
2097 MixerStrip::monitor_changed ()
2098 {
2099         assert (monitor_section_button);
2100         if (_session->monitor_active()) {
2101                 monitor_section_button->set_name ("master monitor section button active");
2102         } else {
2103                 monitor_section_button->set_name ("master monitor section button normal");
2104         }
2105 }
2106
2107 void
2108 MixerStrip::monitor_section_added_or_removed ()
2109 {
2110         assert (monitor_section_button);
2111         if (mute_button->get_parent()) {
2112                 mute_button->get_parent()->remove(*mute_button);
2113         }
2114         if (monitor_section_button->get_parent()) {
2115                 monitor_section_button->get_parent()->remove(*monitor_section_button);
2116         }
2117         if (_session && _session->monitor_out ()) {
2118                 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2119                 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2120                 mute_button->show();
2121                 monitor_section_button->show();
2122         } else {
2123                 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2124                 mute_button->show();
2125         }
2126 }
2127
2128 /** Called when the metering point has changed */
2129 void
2130 MixerStrip::meter_changed ()
2131 {
2132         gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2133         gpm.setup_meters ();
2134         // reset peak when meter point changes
2135         gpm.reset_peak_display();
2136 }
2137
2138 /** The bus that we are displaying sends to has changed, or been turned off.
2139  *  @param send_to New bus that we are displaying sends to, or 0.
2140  */
2141 void
2142 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2143 {
2144         RouteUI::bus_send_display_changed (send_to);
2145
2146         if (send_to) {
2147                 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2148
2149                 if (send) {
2150                         show_send (send);
2151                 } else {
2152                         revert_to_default_display ();
2153                 }
2154         } else {
2155                 revert_to_default_display ();
2156         }
2157 }
2158
2159 void
2160 MixerStrip::drop_send ()
2161 {
2162         boost::shared_ptr<Send> current_send;
2163
2164         if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2165                 current_send->set_metering (false);
2166         }
2167
2168         send_gone_connection.disconnect ();
2169         input_button.set_sensitive (true);
2170         output_button.set_sensitive (true);
2171         group_button.set_sensitive (true);
2172         set_invert_sensitive (true);
2173         gpm.meter_point_button.set_sensitive (true);
2174         mute_button->set_sensitive (true);
2175         solo_button->set_sensitive (true);
2176         solo_isolated_led->set_sensitive (true);
2177         solo_safe_led->set_sensitive (true);
2178         monitor_input_button->set_sensitive (true);
2179         monitor_disk_button->set_sensitive (true);
2180         _comment_button.set_sensitive (true);
2181         trim_control.set_sensitive (true);
2182         if (midi_input_enable_button) {
2183                 midi_input_enable_button->set_sensitive (true);
2184         }
2185         control_slave_ui.set_sensitive (true);
2186         RouteUI::check_rec_enable_sensitivity ();
2187         set_button_names (); // update solo button visual state
2188 }
2189
2190 void
2191 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2192 {
2193         _current_delivery = d;
2194         DeliveryChanged (_current_delivery);
2195 }
2196
2197 void
2198 MixerStrip::show_send (boost::shared_ptr<Send> send)
2199 {
2200         assert (send != 0);
2201
2202         drop_send ();
2203
2204         set_current_delivery (send);
2205
2206         send->meter()->set_meter_type (_route->meter_type ());
2207         send->set_metering (true);
2208         _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2209
2210         gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2211         gain_meter().setup_meters ();
2212
2213         uint32_t const in = _current_delivery->pans_required();
2214         uint32_t const out = _current_delivery->pan_outs();
2215
2216         panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2217         panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2218         panner_ui().setup_pan ();
2219         panner_ui().set_send_drawing_mode (true);
2220         panner_ui().show_all ();
2221
2222         input_button.set_sensitive (false);
2223         group_button.set_sensitive (false);
2224         set_invert_sensitive (false);
2225         gpm.meter_point_button.set_sensitive (false);
2226         mute_button->set_sensitive (false);
2227         solo_button->set_sensitive (false);
2228         rec_enable_button->set_sensitive (false);
2229         solo_isolated_led->set_sensitive (false);
2230         solo_safe_led->set_sensitive (false);
2231         monitor_input_button->set_sensitive (false);
2232         monitor_disk_button->set_sensitive (false);
2233         _comment_button.set_sensitive (false);
2234         trim_control.set_sensitive (false);
2235         if (midi_input_enable_button) {
2236                 midi_input_enable_button->set_sensitive (false);
2237         }
2238         control_slave_ui.set_sensitive (false);
2239
2240         if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2241                 output_button.set_sensitive (false);
2242         }
2243
2244         reset_strip_style ();
2245 }
2246
2247 void
2248 MixerStrip::revert_to_default_display ()
2249 {
2250         drop_send ();
2251
2252         set_current_delivery (_route->main_outs ());
2253
2254         gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2255         gain_meter().setup_meters ();
2256
2257         panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2258         update_panner_choices();
2259         panner_ui().setup_pan ();
2260         panner_ui().set_send_drawing_mode (false);
2261
2262         if (has_audio_outputs ()) {
2263                 panners.show_all ();
2264         } else {
2265                 panners.hide_all ();
2266         }
2267
2268         reset_strip_style ();
2269 }
2270
2271 void
2272 MixerStrip::set_button_names ()
2273 {
2274         switch (_width) {
2275         case Wide:
2276                 mute_button->set_text (_("Mute"));
2277                 monitor_input_button->set_text (_("In"));
2278                 monitor_disk_button->set_text (_("Disk"));
2279                 if (monitor_section_button) {
2280                         monitor_section_button->set_text (_("Mon"));
2281                 }
2282
2283                 if (_route && _route->solo_safe_control()->solo_safe()) {
2284                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2285                 } else {
2286                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2287                 }
2288                 if (!Config->get_solo_control_is_listen_control()) {
2289                         solo_button->set_text (_("Solo"));
2290                 } else {
2291                         switch (Config->get_listen_position()) {
2292                         case AfterFaderListen:
2293                                 solo_button->set_text (_("AFL"));
2294                                 break;
2295                         case PreFaderListen:
2296                                 solo_button->set_text (_("PFL"));
2297                                 break;
2298                         }
2299                 }
2300                 solo_isolated_led->set_text (_("Iso"));
2301                 solo_safe_led->set_text (S_("SoloLock|Lock"));
2302                 break;
2303
2304         default:
2305                 mute_button->set_text (S_("Mute|M"));
2306                 monitor_input_button->set_text (S_("MonitorInput|I"));
2307                 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2308                 if (monitor_section_button) {
2309                         monitor_section_button->set_text (S_("Mon|O"));
2310                 }
2311
2312                 if (_route && _route->solo_safe_control()->solo_safe()) {
2313                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2314                 } else {
2315                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2316                 }
2317                 if (!Config->get_solo_control_is_listen_control()) {
2318                         solo_button->set_text (S_("Solo|S"));
2319                 } else {
2320                         switch (Config->get_listen_position()) {
2321                         case AfterFaderListen:
2322                                 solo_button->set_text (S_("AfterFader|A"));
2323                                 break;
2324                         case PreFaderListen:
2325                                 solo_button->set_text (S_("Prefader|P"));
2326                                 break;
2327                         }
2328                 }
2329
2330                 solo_isolated_led->set_text (S_("SoloIso|I"));
2331                 solo_safe_led->set_text (S_("SoloLock|L"));
2332                 break;
2333         }
2334
2335         if (_route) {
2336                 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2337         } else {
2338                 gpm.meter_point_button.set_text ("");
2339         }
2340 }
2341
2342 PluginSelector*
2343 MixerStrip::plugin_selector()
2344 {
2345         return _mixer.plugin_selector();
2346 }
2347
2348 void
2349 MixerStrip::hide_things ()
2350 {
2351         processor_box.hide_things ();
2352 }
2353
2354 bool
2355 MixerStrip::input_active_button_press (GdkEventButton*)
2356 {
2357         /* nothing happens on press */
2358         return true;
2359 }
2360
2361 bool
2362 MixerStrip::input_active_button_release (GdkEventButton* ev)
2363 {
2364         boost::shared_ptr<MidiTrack> mt = midi_track ();
2365
2366         if (!mt) {
2367                 return true;
2368         }
2369
2370         boost::shared_ptr<RouteList> rl (new RouteList);
2371
2372         rl->push_back (route());
2373
2374         _session->set_exclusive_input_active (rl, !mt->input_active(),
2375                                               Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2376
2377         return true;
2378 }
2379
2380 void
2381 MixerStrip::midi_input_status_changed ()
2382 {
2383         if (midi_input_enable_button) {
2384                 boost::shared_ptr<MidiTrack> mt = midi_track ();
2385                 assert (mt);
2386                 midi_input_enable_button->set_active (mt->input_active ());
2387         }
2388 }
2389
2390 string
2391 MixerStrip::state_id () const
2392 {
2393         return string_compose ("strip %1", _route->id().to_s());
2394 }
2395
2396 void
2397 MixerStrip::parameter_changed (string p)
2398 {
2399         if (p == _visibility.get_state_name()) {
2400                 /* The user has made changes to the mixer strip visibility, so get
2401                    our VisibilityGroup to reflect these changes in our widgets.
2402                 */
2403                 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2404         } else if (p == "track-name-number") {
2405                 name_changed ();
2406                 update_track_number_visibility();
2407         }
2408 }
2409
2410 /** Called to decide whether the solo isolate / solo lock button visibility should
2411  *  be overridden from that configured by the user.  We do this for the master bus.
2412  *
2413  *  @return optional value that is present if visibility state should be overridden.
2414  */
2415 boost::optional<bool>
2416 MixerStrip::override_solo_visibility () const
2417 {
2418         if (_route && _route->is_master ()) {
2419                 return boost::optional<bool> (false);
2420         }
2421
2422         return boost::optional<bool> ();
2423 }
2424
2425 void
2426 MixerStrip::add_input_port (DataType t)
2427 {
2428         _route->input()->add_port ("", this, t);
2429 }
2430
2431 void
2432 MixerStrip::add_output_port (DataType t)
2433 {
2434         _route->output()->add_port ("", this, t);
2435 }
2436
2437 void
2438 MixerStrip::route_active_changed ()
2439 {
2440         reset_strip_style ();
2441 }
2442
2443 void
2444 MixerStrip::copy_processors ()
2445 {
2446         processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2447 }
2448
2449 void
2450 MixerStrip::cut_processors ()
2451 {
2452         processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2453 }
2454
2455 void
2456 MixerStrip::paste_processors ()
2457 {
2458         processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2459 }
2460
2461 void
2462 MixerStrip::select_all_processors ()
2463 {
2464         processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2465 }
2466
2467 void
2468 MixerStrip::deselect_all_processors ()
2469 {
2470         processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2471 }
2472
2473 bool
2474 MixerStrip::delete_processors ()
2475 {
2476         return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2477 }
2478
2479 void
2480 MixerStrip::toggle_processors ()
2481 {
2482         processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2483 }
2484
2485 void
2486 MixerStrip::ab_plugins ()
2487 {
2488         processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2489 }
2490
2491 bool
2492 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2493 {
2494         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2495                 return false;
2496         }
2497         if (ev->button == 3) {
2498                 popup_level_meter_menu (ev);
2499                 return true;
2500         }
2501
2502         return false;
2503 }
2504
2505 void
2506 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2507 {
2508         using namespace Gtk::Menu_Helpers;
2509
2510         Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
2511         MenuList& items = m->items ();
2512
2513         RadioMenuItem::Group group;
2514
2515         PBD::Unwinder<bool> uw (_suspend_menu_callbacks, true);
2516         add_level_meter_item_point (items, group, _("Input"), MeterInput);
2517         add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2518         add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2519         add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2520         add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2521
2522         if (gpm.meter_channels().n_audio() == 0) {
2523                 m->popup (ev->button, ev->time);
2524                 return;
2525         }
2526
2527         RadioMenuItem::Group tgroup;
2528         items.push_back (SeparatorElem());
2529
2530         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2531         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2532         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms),  MeterKrms);
2533         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2534         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2535         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2536         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2537         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2538         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2539         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2540         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU),  MeterVU);
2541
2542         int _strip_type;
2543         if (_route->is_master()) {
2544                 _strip_type = 4;
2545         }
2546         else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2547                         && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2548                 /* non-master bus */
2549                 _strip_type = 3;
2550         }
2551         else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2552                 _strip_type = 2;
2553         }
2554         else {
2555                 _strip_type = 1;
2556         }
2557
2558         MeterType cmt = _route->meter_type();
2559         const std::string cmn = ArdourMeter::meter_type_string(cmt);
2560
2561         items.push_back (SeparatorElem());
2562         items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2563                                 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2564         items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2565                                 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2566         items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2567                                 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2568
2569         m->popup (ev->button, ev->time);
2570 }
2571
2572 void
2573 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2574                 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2575 {
2576         using namespace Menu_Helpers;
2577
2578         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2579         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2580         i->set_active (_route->meter_point() == point);
2581 }
2582
2583 void
2584 MixerStrip::set_meter_point (MeterPoint p)
2585 {
2586         if (_suspend_menu_callbacks) return;
2587         _route->set_meter_point (p);
2588 }
2589
2590 void
2591 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2592                 RadioMenuItem::Group& group, string const & name, MeterType type)
2593 {
2594         using namespace Menu_Helpers;
2595
2596         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2597         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2598         i->set_active (_route->meter_type() == type);
2599 }
2600
2601 void
2602 MixerStrip::set_meter_type (MeterType t)
2603 {
2604         if (_suspend_menu_callbacks) return;
2605         _route->set_meter_type (t);
2606 }
2607
2608 void
2609 MixerStrip::update_track_number_visibility ()
2610 {
2611         DisplaySuspender ds;
2612         bool show_label = _session->config.get_track_name_number();
2613
2614         if (_route && _route->is_master()) {
2615                 show_label = false;
2616         }
2617
2618         if (show_label) {
2619                 number_label.show ();
2620                 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2621                 // except the width of the number label is subtracted from the name-hbox, so we
2622                 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2623                 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2624                 if (tnw & 1) --tnw;
2625                 number_label.set_size_request(tnw, -1);
2626                 number_label.show ();
2627         } else {
2628                 number_label.hide ();
2629         }
2630 }
2631
2632 Gdk::Color
2633 MixerStrip::color () const
2634 {
2635         return route_color ();
2636 }
2637
2638 bool
2639 MixerStrip::marked_for_display () const
2640 {
2641         return !_route->presentation_info().hidden();
2642 }
2643
2644 bool
2645 MixerStrip::set_marked_for_display (bool yn)
2646 {
2647         return RouteUI::mark_hidden (!yn);
2648 }
2649
2650 void
2651 MixerStrip::hide_master_spacer (bool yn)
2652 {
2653         if (_mixer_owned && route()->is_master() && !yn) {
2654                 spacer.show();
2655         } else {
2656                 spacer.hide();
2657         }
2658 }