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