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