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