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