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