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