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