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