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