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