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