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