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