db5d70bc85e19d97a063d746fe3964a1ceed79ba
[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                                 const size_t ppps = RouteUI::program_port_prefix.size () + 1; // "ardour:"
1369                                 label << ardour_track_name.substr (ppps, slash - ppps);
1370                                 have_label = true;
1371                         }
1372                 }
1373                 else if (total_connection_count == system_connection_count) {
1374                         // all connections are to system ports
1375                         label << system_ports;
1376                         have_label = true;
1377                 }
1378                 else if (total_connection_count == other_connection_count) {
1379                         // all connections are to the same external program eg jamin
1380                         // "jamin:" -> "jamin"
1381                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1382                         have_label = true;
1383                 }
1384         }
1385
1386         if (!have_label) {
1387                 if (total_connection_count == 0) {
1388                         // Disconnected
1389                         label << "-";
1390                 } else {
1391                         // Odd configuration
1392                         label << "*" << total_connection_count << "*";
1393                 }
1394                 if (typed_connection_count > 0) {
1395                         label << "\u2295"; // circled plus
1396                 }
1397         }
1398
1399         if (for_input) {
1400                 input_button.set_text (label.str());
1401         } else {
1402                 output_button.set_text (label.str());
1403         }
1404 }
1405
1406 void
1407 MixerStrip::update_input_display ()
1408 {
1409         update_io_button (_route, _width, true);
1410         panners.setup_pan ();
1411
1412         if (has_audio_outputs ()) {
1413                 panners.show_all ();
1414         } else {
1415                 panners.hide_all ();
1416         }
1417
1418 }
1419
1420 void
1421 MixerStrip::update_output_display ()
1422 {
1423         update_io_button (_route, _width, false);
1424         gpm.setup_meters ();
1425         panners.setup_pan ();
1426
1427         if (has_audio_outputs ()) {
1428                 panners.show_all ();
1429         } else {
1430                 panners.hide_all ();
1431         }
1432 }
1433
1434 void
1435 MixerStrip::fast_update ()
1436 {
1437         gpm.update_meters ();
1438 }
1439
1440 void
1441 MixerStrip::diskstream_changed ()
1442 {
1443         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1444 }
1445
1446 void
1447 MixerStrip::io_changed_proxy ()
1448 {
1449         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1450 }
1451
1452 void
1453 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1454 {
1455         boost::shared_ptr<Port> a = wa.lock ();
1456         boost::shared_ptr<Port> b = wb.lock ();
1457
1458         if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1459                 update_input_display ();
1460                 set_width_enum (_width, this);
1461         }
1462
1463         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1464                 update_output_display ();
1465                 set_width_enum (_width, this);
1466         }
1467 }
1468
1469 void
1470 MixerStrip::setup_comment_button ()
1471 {
1472         switch (_width) {
1473
1474         case Wide:
1475                 if (_route->comment().empty ()) {
1476                         _comment_button.unset_bg (STATE_NORMAL);
1477                         _comment_button.set_text (_("Comments"));
1478                 } else {
1479                         _comment_button.modify_bg (STATE_NORMAL, color ());
1480                         _comment_button.set_text (_("*Comments*"));
1481                 }
1482                 break;
1483
1484         case Narrow:
1485                 if (_route->comment().empty ()) {
1486                         _comment_button.unset_bg (STATE_NORMAL);
1487                         _comment_button.set_text (_("Cmt"));
1488                 } else {
1489                         _comment_button.modify_bg (STATE_NORMAL, color ());
1490                         _comment_button.set_text (_("*Cmt*"));
1491                 }
1492                 break;
1493         }
1494
1495         set_tooltip (
1496                 _comment_button, _route->comment().empty() ? _("Click to add/edit comments") : _route->comment()
1497                 );
1498
1499 }
1500
1501 bool
1502 MixerStrip::select_route_group (GdkEventButton *ev)
1503 {
1504         using namespace Menu_Helpers;
1505
1506         if (ev->button == 1) {
1507
1508                 if (group_menu == 0) {
1509
1510                         PropertyList* plist = new PropertyList();
1511
1512                         plist->add (Properties::gain, true);
1513                         plist->add (Properties::mute, true);
1514                         plist->add (Properties::solo, true);
1515
1516                         group_menu = new RouteGroupMenu (_session, plist);
1517                 }
1518
1519                 WeakRouteList r;
1520                 r.push_back (route ());
1521                 group_menu->build (r);
1522                 group_menu->menu()->popup (1, ev->time);
1523         }
1524
1525         return true;
1526 }
1527
1528 void
1529 MixerStrip::route_group_changed ()
1530 {
1531         ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1532
1533         RouteGroup *rg = _route->route_group();
1534
1535         if (rg) {
1536                 group_button.set_text (PBD::short_version (rg->name(), 5));
1537         } else {
1538                 switch (_width) {
1539                 case Wide:
1540                         group_button.set_text (_("Grp"));
1541                         break;
1542                 case Narrow:
1543                         group_button.set_text (_("~G"));
1544                         break;
1545                 }
1546         }
1547 }
1548
1549 void
1550 MixerStrip::route_color_changed ()
1551 {
1552         name_button.modify_bg (STATE_NORMAL, color());
1553         number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1554         reset_strip_style ();
1555 }
1556
1557 void
1558 MixerStrip::show_passthru_color ()
1559 {
1560         reset_strip_style ();
1561 }
1562
1563 void
1564 MixerStrip::build_route_ops_menu ()
1565 {
1566         using namespace Menu_Helpers;
1567         route_ops_menu = new Menu;
1568         route_ops_menu->set_name ("ArdourContextMenu");
1569
1570         MenuList& items = route_ops_menu->items();
1571
1572         items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1573
1574         items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1575
1576         items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1577
1578         items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1579
1580         items.push_back (SeparatorElem());
1581
1582         if (!_route->is_master()) {
1583                 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1584         }
1585         items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1586         rename_menu_item = &items.back();
1587
1588         items.push_back (SeparatorElem());
1589         items.push_back (CheckMenuElem (_("Active")));
1590         Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1591         i->set_active (_route->active());
1592         i->set_sensitive(! _session->transport_rolling());
1593         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1594
1595         if (!Profile->get_mixbus ()) {
1596                 items.push_back (SeparatorElem());
1597                 items.push_back (CheckMenuElem (_("Strict I/O")));
1598                 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1599                 i->set_active (_route->strict_io());
1600                 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1601         }
1602
1603         items.push_back (SeparatorElem());
1604
1605         items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1606
1607         items.push_back (SeparatorElem());
1608         items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1609         denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1610         denormal_menu_item->set_active (_route->denormal_protection());
1611
1612         items.push_back (SeparatorElem());
1613         items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
1614
1615         if (_route) {
1616                 /* note that this relies on selection being shared across editor and
1617                    mixer (or global to the backend, in the future), which is the only
1618                    sane thing for users anyway.
1619                 */
1620
1621                 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1622                 if (rtav) {
1623                         Selection& selection (PublicEditor::instance().get_selection());
1624                         if (!selection.selected (rtav)) {
1625                                 selection.set (rtav);
1626                         }
1627
1628                         if (!_route->is_master()) {
1629                                 items.push_back (SeparatorElem());
1630                                 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1631                         }
1632         
1633                         items.push_back (SeparatorElem());
1634                         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1635                 }
1636         }
1637 }
1638
1639 gboolean
1640 MixerStrip::name_button_button_press (GdkEventButton* ev)
1641 {
1642         if (ev->button == 3) {
1643                 list_route_operations ();
1644
1645                 /* do not allow rename if the track is record-enabled */
1646                 rename_menu_item->set_sensitive (!_route->record_enabled());
1647                 route_ops_menu->popup (1, ev->time);
1648
1649                 return true;
1650         }
1651
1652         return false;
1653 }
1654
1655 gboolean
1656 MixerStrip::name_button_button_release (GdkEventButton* ev)
1657 {
1658         if (ev->button == 1) {
1659                 list_route_operations ();
1660
1661                 /* do not allow rename if the track is record-enabled */
1662                 rename_menu_item->set_sensitive (!_route->record_enabled());
1663                 route_ops_menu->popup (1, ev->time);
1664         }
1665
1666         return false;
1667 }
1668
1669 gboolean
1670 MixerStrip::number_button_button_press (GdkEventButton* ev)
1671 {
1672         if (  ev->button == 3 ) {
1673                 list_route_operations ();
1674
1675                 /* do not allow rename if the track is record-enabled */
1676                 rename_menu_item->set_sensitive (!_route->record_enabled());
1677                 route_ops_menu->popup (1, ev->time);
1678
1679                 return true;
1680         }
1681
1682         return false;
1683 }
1684
1685 void
1686 MixerStrip::list_route_operations ()
1687 {
1688         delete route_ops_menu;
1689         build_route_ops_menu ();
1690 }
1691
1692 void
1693 MixerStrip::set_selected (bool yn)
1694 {
1695         AxisView::set_selected (yn);
1696         if (_selected) {
1697                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1698                 global_frame.set_name ("MixerStripSelectedFrame");
1699         } else {
1700                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1701                 global_frame.set_name ("MixerStripFrame");
1702         }
1703         global_frame.queue_draw ();
1704
1705 //      if (!yn)
1706 //              processor_box.deselect_all_processors();
1707 }
1708
1709 void
1710 MixerStrip::property_changed (const PropertyChange& what_changed)
1711 {
1712         RouteUI::property_changed (what_changed);
1713
1714         if (what_changed.contains (ARDOUR::Properties::name)) {
1715                 name_changed ();
1716         }
1717 }
1718
1719 void
1720 MixerStrip::name_changed ()
1721 {
1722         switch (_width) {
1723                 case Wide:
1724                         name_button.set_text (_route->name());
1725                         break;
1726                 case Narrow:
1727                         name_button.set_text (PBD::short_version (_route->name(), 5));
1728                         break;
1729         }
1730
1731         set_tooltip (name_button, _route->name());
1732
1733         if (_session->config.get_track_name_number()) {
1734                 const int64_t track_number = _route->track_number ();
1735                 if (track_number == 0) {
1736                         number_label.set_text ("-");
1737                 } else {
1738                         number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1739                 }
1740         } else {
1741                 number_label.set_text ("");
1742         }
1743 }
1744
1745 void
1746 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1747 {
1748         input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1749 }
1750
1751 void
1752 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1753 {
1754         output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1755 }
1756
1757 void
1758 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1759 {
1760         name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1761 }
1762
1763 bool
1764 MixerStrip::width_button_pressed (GdkEventButton* ev)
1765 {
1766         if (ev->button != 1) {
1767                 return false;
1768         }
1769
1770         if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1771                 switch (_width) {
1772                 case Wide:
1773                         _mixer.set_strip_width (Narrow, true);
1774                         break;
1775
1776                 case Narrow:
1777                         _mixer.set_strip_width (Wide, true);
1778                         break;
1779                 }
1780         } else {
1781                 switch (_width) {
1782                 case Wide:
1783                         set_width_enum (Narrow, this);
1784                         break;
1785                 case Narrow:
1786                         set_width_enum (Wide, this);
1787                         break;
1788                 }
1789         }
1790
1791         return true;
1792 }
1793
1794 void
1795 MixerStrip::hide_clicked ()
1796 {
1797         // LAME fix to reset the button status for when it is redisplayed (part 1)
1798         hide_button.set_sensitive(false);
1799
1800         if (_embedded) {
1801                 Hiding(); /* EMIT_SIGNAL */
1802         } else {
1803                 _mixer.hide_strip (this);
1804         }
1805
1806         // (part 2)
1807         hide_button.set_sensitive(true);
1808 }
1809
1810 void
1811 MixerStrip::set_embedded (bool yn)
1812 {
1813         _embedded = yn;
1814 }
1815
1816 void
1817 MixerStrip::map_frozen ()
1818 {
1819         ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1820
1821         boost::shared_ptr<AudioTrack> at = audio_track();
1822
1823         if (at) {
1824                 switch (at->freeze_state()) {
1825                 case AudioTrack::Frozen:
1826                         processor_box.set_sensitive (false);
1827                         hide_redirect_editors ();
1828                         break;
1829                 default:
1830                         processor_box.set_sensitive (true);
1831                         // XXX need some way, maybe, to retoggle redirect editors
1832                         break;
1833                 }
1834         } else {
1835                 processor_box.set_sensitive (true);
1836         }
1837 }
1838
1839 void
1840 MixerStrip::hide_redirect_editors ()
1841 {
1842         _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1843 }
1844
1845 void
1846 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1847 {
1848         boost::shared_ptr<Processor> processor (p.lock ());
1849         if (!processor) {
1850                 return;
1851         }
1852
1853         Gtk::Window* w = processor_box.get_processor_ui (processor);
1854
1855         if (w) {
1856                 w->hide ();
1857         }
1858 }
1859
1860 void
1861 MixerStrip::reset_strip_style ()
1862 {
1863         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1864
1865                 gpm.set_fader_name ("SendStripBase");
1866
1867         } else {
1868
1869                 if (is_midi_track()) {
1870                         if (_route->active()) {
1871                                 set_name ("MidiTrackStripBase");
1872                         } else {
1873                                 set_name ("MidiTrackStripBaseInactive");
1874                         }
1875                         gpm.set_fader_name ("MidiTrackFader");
1876                 } else if (is_audio_track()) {
1877                         if (_route->active()) {
1878                                 set_name ("AudioTrackStripBase");
1879                         } else {
1880                                 set_name ("AudioTrackStripBaseInactive");
1881                         }
1882                         gpm.set_fader_name ("AudioTrackFader");
1883                 } else {
1884                         if (_route->active()) {
1885                                 set_name ("AudioBusStripBase");
1886                         } else {
1887                                 set_name ("AudioBusStripBaseInactive");
1888                         }
1889                         gpm.set_fader_name ("AudioBusFader");
1890
1891                         /* (no MIDI busses yet) */
1892                 }
1893         }
1894 }
1895
1896
1897 void
1898 MixerStrip::engine_stopped ()
1899 {
1900 }
1901
1902 void
1903 MixerStrip::engine_running ()
1904 {
1905 }
1906
1907 string
1908 MixerStrip::meter_point_string (MeterPoint mp)
1909 {
1910         switch (_width) {
1911         case Wide:
1912                 switch (mp) {
1913                 case MeterInput:
1914                         return _("In");
1915                         break;
1916
1917                 case MeterPreFader:
1918                         return _("Pre");
1919                         break;
1920
1921                 case MeterPostFader:
1922                         return _("Post");
1923                         break;
1924
1925                 case MeterOutput:
1926                         return _("Out");
1927                         break;
1928
1929                 case MeterCustom:
1930                 default:
1931                         return _("Custom");
1932                         break;
1933                 }
1934                 break;
1935         case Narrow:
1936                 switch (mp) {
1937                 case MeterInput:
1938                         return S_("Meter|In");
1939                         break;
1940
1941                 case MeterPreFader:
1942                         return S_("Meter|Pr");
1943                         break;
1944
1945                 case MeterPostFader:
1946                         return S_("Meter|Po");
1947                         break;
1948
1949                 case MeterOutput:
1950                         return S_("Meter|O");
1951                         break;
1952
1953                 case MeterCustom:
1954                 default:
1955                         return S_("Meter|C");
1956                         break;
1957                 }
1958                 break;
1959         }
1960
1961         return string();
1962 }
1963
1964 /** Called when the monitor-section state */
1965 void
1966 MixerStrip::monitor_changed ()
1967 {
1968         assert (monitor_section_button);
1969         if (_session->monitor_active()) {
1970                 monitor_section_button->set_name ("master monitor section button active");
1971         } else {
1972                 monitor_section_button->set_name ("master monitor section button normal");
1973         }
1974 }
1975
1976 /** Called when the metering point has changed */
1977 void
1978 MixerStrip::meter_changed ()
1979 {
1980         meter_point_button.set_text (meter_point_string (_route->meter_point()));
1981         gpm.setup_meters ();
1982         // reset peak when meter point changes
1983         gpm.reset_peak_display();
1984 }
1985
1986 /** The bus that we are displaying sends to has changed, or been turned off.
1987  *  @param send_to New bus that we are displaying sends to, or 0.
1988  */
1989 void
1990 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1991 {
1992         RouteUI::bus_send_display_changed (send_to);
1993
1994         if (send_to) {
1995                 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
1996
1997                 if (send) {
1998                         show_send (send);
1999                 } else {
2000                         revert_to_default_display ();
2001                 }
2002         } else {
2003                 revert_to_default_display ();
2004         }
2005 }
2006
2007 void
2008 MixerStrip::drop_send ()
2009 {
2010         boost::shared_ptr<Send> current_send;
2011
2012         if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2013                 current_send->set_metering (false);
2014         }
2015
2016         send_gone_connection.disconnect ();
2017         input_button.set_sensitive (true);
2018         output_button.set_sensitive (true);
2019         group_button.set_sensitive (true);
2020         set_invert_sensitive (true);
2021         meter_point_button.set_sensitive (true);
2022         mute_button->set_sensitive (true);
2023         solo_button->set_sensitive (true);
2024         rec_enable_button->set_sensitive (true);
2025         solo_isolated_led->set_sensitive (true);
2026         solo_safe_led->set_sensitive (true);
2027         monitor_input_button->set_sensitive (true);
2028         monitor_disk_button->set_sensitive (true);
2029         _comment_button.set_sensitive (true);
2030 }
2031
2032 void
2033 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2034 {
2035         _current_delivery = d;
2036         DeliveryChanged (_current_delivery);
2037 }
2038
2039 void
2040 MixerStrip::show_send (boost::shared_ptr<Send> send)
2041 {
2042         assert (send != 0);
2043
2044         drop_send ();
2045
2046         set_current_delivery (send);
2047
2048         send->meter()->set_type(_route->shared_peak_meter()->get_type());
2049         send->set_metering (true);
2050         _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2051
2052         gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2053         gain_meter().setup_meters ();
2054
2055         uint32_t const in = _current_delivery->pans_required();
2056         uint32_t const out = _current_delivery->pan_outs();
2057
2058         panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2059         panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2060         panner_ui().setup_pan ();
2061         panner_ui().set_send_drawing_mode (true);
2062         panner_ui().show_all ();
2063
2064         input_button.set_sensitive (false);
2065         group_button.set_sensitive (false);
2066         set_invert_sensitive (false);
2067         meter_point_button.set_sensitive (false);
2068         mute_button->set_sensitive (false);
2069         solo_button->set_sensitive (false);
2070         rec_enable_button->set_sensitive (false);
2071         solo_isolated_led->set_sensitive (false);
2072         solo_safe_led->set_sensitive (false);
2073         monitor_input_button->set_sensitive (false);
2074         monitor_disk_button->set_sensitive (false);
2075         _comment_button.set_sensitive (false);
2076
2077         if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2078                 output_button.set_sensitive (false);
2079         }
2080
2081         reset_strip_style ();
2082 }
2083
2084 void
2085 MixerStrip::revert_to_default_display ()
2086 {
2087         drop_send ();
2088
2089         set_current_delivery (_route->main_outs ());
2090
2091         gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2092         gain_meter().setup_meters ();
2093
2094         panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2095         update_panner_choices();
2096         panner_ui().setup_pan ();
2097         panner_ui().set_send_drawing_mode (false);
2098
2099         if (has_audio_outputs ()) {
2100                 panners.show_all ();
2101         } else {
2102                 panners.hide_all ();
2103         }
2104
2105         reset_strip_style ();
2106 }
2107
2108 void
2109 MixerStrip::set_button_names ()
2110 {
2111         switch (_width) {
2112         case Wide:
2113                 mute_button->set_text (_("Mute"));
2114                 monitor_input_button->set_text (_("In"));
2115                 monitor_disk_button->set_text (_("Disk"));
2116                 if (monitor_section_button) {
2117                         monitor_section_button->set_text (_("Mon"));
2118                 }
2119
2120                 if (_route && _route->solo_safe()) {
2121                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2122                 } else {
2123                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2124                 }
2125                 if (!Config->get_solo_control_is_listen_control()) {
2126                         solo_button->set_text (_("Solo"));
2127                 } else {
2128                         switch (Config->get_listen_position()) {
2129                         case AfterFaderListen:
2130                                 solo_button->set_text (_("AFL"));
2131                                 break;
2132                         case PreFaderListen:
2133                                 solo_button->set_text (_("PFL"));
2134                                 break;
2135                         }
2136                 }
2137                 solo_isolated_led->set_text (_("Iso"));
2138                 solo_safe_led->set_text (S_("SoloLock|Lock"));
2139                 break;
2140
2141         default:
2142                 mute_button->set_text (S_("Mute|M"));
2143                 monitor_input_button->set_text (S_("MonitorInput|I"));
2144                 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2145                 if (monitor_section_button) {
2146                         monitor_section_button->set_text (S_("Mon|O"));
2147                 }
2148
2149                 if (_route && _route->solo_safe()) {
2150                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2151                 } else {
2152                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2153                 }
2154                 if (!Config->get_solo_control_is_listen_control()) {
2155                         solo_button->set_text (S_("Solo|S"));
2156                 } else {
2157                         switch (Config->get_listen_position()) {
2158                         case AfterFaderListen:
2159                                 solo_button->set_text (S_("AfterFader|A"));
2160                                 break;
2161                         case PreFaderListen:
2162                                 solo_button->set_text (S_("Prefader|P"));
2163                                 break;
2164                         }
2165                 }
2166
2167                 solo_isolated_led->set_text (S_("SoloIso|I"));
2168                 solo_safe_led->set_text (S_("SoloLock|L"));
2169                 break;
2170         }
2171
2172         if (_route) {
2173                 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2174         } else {
2175                 meter_point_button.set_text ("");
2176         }
2177 }
2178
2179 PluginSelector*
2180 MixerStrip::plugin_selector()
2181 {
2182         return _mixer.plugin_selector();
2183 }
2184
2185 void
2186 MixerStrip::hide_things ()
2187 {
2188         processor_box.hide_things ();
2189 }
2190
2191 bool
2192 MixerStrip::input_active_button_press (GdkEventButton*)
2193 {
2194         /* nothing happens on press */
2195         return true;
2196 }
2197
2198 bool
2199 MixerStrip::input_active_button_release (GdkEventButton* ev)
2200 {
2201         boost::shared_ptr<MidiTrack> mt = midi_track ();
2202
2203         if (!mt) {
2204                 return true;
2205         }
2206
2207         boost::shared_ptr<RouteList> rl (new RouteList);
2208
2209         rl->push_back (route());
2210
2211         _session->set_exclusive_input_active (rl, !mt->input_active(),
2212                                               Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2213
2214         return true;
2215 }
2216
2217 void
2218 MixerStrip::midi_input_status_changed ()
2219 {
2220         if (midi_input_enable_button) {
2221                 boost::shared_ptr<MidiTrack> mt = midi_track ();
2222                 assert (mt);
2223                 midi_input_enable_button->set_active (mt->input_active ());
2224         }
2225 }
2226
2227 string
2228 MixerStrip::state_id () const
2229 {
2230         return string_compose ("strip %1", _route->id().to_s());
2231 }
2232
2233 void
2234 MixerStrip::parameter_changed (string p)
2235 {
2236         if (p == _visibility.get_state_name()) {
2237                 /* The user has made changes to the mixer strip visibility, so get
2238                    our VisibilityGroup to reflect these changes in our widgets.
2239                 */
2240                 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2241         }
2242         else if (p == "track-name-number") {
2243                 name_changed ();
2244         }
2245         else if (p == "use-monitor-bus") {
2246                 if (monitor_section_button) {
2247                         if (mute_button->get_parent()) {
2248                                 mute_button->get_parent()->remove(*mute_button);
2249                         }
2250                         if (monitor_section_button->get_parent()) {
2251                                 monitor_section_button->get_parent()->remove(*monitor_section_button);
2252                         }
2253                         if (Config->get_use_monitor_bus ()) {
2254                                 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2255                                 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2256                                 mute_button->show();
2257                                 monitor_section_button->show();
2258                         } else {
2259                                 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2260                                 mute_button->show();
2261                         }
2262                 }
2263         }
2264 }
2265
2266 /** Called to decide whether the solo isolate / solo lock button visibility should
2267  *  be overridden from that configured by the user.  We do this for the master bus.
2268  *
2269  *  @return optional value that is present if visibility state should be overridden.
2270  */
2271 boost::optional<bool>
2272 MixerStrip::override_solo_visibility () const
2273 {
2274         if (_route && _route->is_master ()) {
2275                 return boost::optional<bool> (false);
2276         }
2277
2278         return boost::optional<bool> ();
2279 }
2280
2281 void
2282 MixerStrip::add_input_port (DataType t)
2283 {
2284         _route->input()->add_port ("", this, t);
2285 }
2286
2287 void
2288 MixerStrip::add_output_port (DataType t)
2289 {
2290         _route->output()->add_port ("", this, t);
2291 }
2292
2293 void
2294 MixerStrip::route_active_changed ()
2295 {
2296         reset_strip_style ();
2297 }
2298
2299 void
2300 MixerStrip::copy_processors ()
2301 {
2302         processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2303 }
2304
2305 void
2306 MixerStrip::cut_processors ()
2307 {
2308         processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2309 }
2310
2311 void
2312 MixerStrip::paste_processors ()
2313 {
2314         processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2315 }
2316
2317 void
2318 MixerStrip::select_all_processors ()
2319 {
2320         processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2321 }
2322
2323 void
2324 MixerStrip::deselect_all_processors ()
2325 {
2326         processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2327 }
2328
2329 bool
2330 MixerStrip::delete_processors ()
2331 {
2332         return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2333 }
2334
2335 void
2336 MixerStrip::toggle_processors ()
2337 {
2338         processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2339 }
2340
2341 void
2342 MixerStrip::ab_plugins ()
2343 {
2344         processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2345 }
2346
2347 bool
2348 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2349 {
2350         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2351                 return false;
2352         }
2353         if (ev->button == 3) {
2354                 popup_level_meter_menu (ev);
2355                 return true;
2356         }
2357
2358         return false;
2359 }
2360
2361 void
2362 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2363 {
2364         using namespace Gtk::Menu_Helpers;
2365
2366         Gtk::Menu* m = manage (new Menu);
2367         MenuList& items = m->items ();
2368
2369         RadioMenuItem::Group group;
2370
2371         _suspend_menu_callbacks = true;
2372         add_level_meter_item_point (items, group, _("Input"), MeterInput);
2373         add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2374         add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2375         add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2376         add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2377
2378         if (gpm.meter_channels().n_audio() == 0) {
2379                 m->popup (ev->button, ev->time);
2380                 _suspend_menu_callbacks = false;
2381                 return;
2382         }
2383
2384         RadioMenuItem::Group tgroup;
2385         items.push_back (SeparatorElem());
2386
2387         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2388         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2389         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms),  MeterKrms);
2390         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2391         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2392         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2393         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2394         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2395         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2396         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2397         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU),  MeterVU);
2398
2399         int _strip_type;
2400         if (_route->is_master()) {
2401                 _strip_type = 4;
2402         }
2403         else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2404                         && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2405                 /* non-master bus */
2406                 _strip_type = 3;
2407         }
2408         else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2409                 _strip_type = 2;
2410         }
2411         else {
2412                 _strip_type = 1;
2413         }
2414
2415         MeterType cmt = _route->meter_type();
2416         const std::string cmn = ArdourMeter::meter_type_string(cmt);
2417
2418         items.push_back (SeparatorElem());
2419         items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2420                                 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2421         items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2422                                 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2423         items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2424                                 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2425
2426         m->popup (ev->button, ev->time);
2427         _suspend_menu_callbacks = false;
2428 }
2429
2430 void
2431 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2432                 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2433 {
2434         using namespace Menu_Helpers;
2435
2436         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2437         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2438         i->set_active (_route->meter_point() == point);
2439 }
2440
2441 void
2442 MixerStrip::set_meter_point (MeterPoint p)
2443 {
2444         if (_suspend_menu_callbacks) return;
2445         _route->set_meter_point (p);
2446 }
2447
2448 void
2449 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2450                 RadioMenuItem::Group& group, string const & name, MeterType type)
2451 {
2452         using namespace Menu_Helpers;
2453
2454         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2455         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2456         i->set_active (_route->meter_type() == type);
2457 }
2458
2459 void
2460 MixerStrip::set_meter_type (MeterType t)
2461 {
2462         if (_suspend_menu_callbacks) return;
2463         gpm.set_type (t);
2464 }