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