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