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