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