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