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