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