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