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