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