Make capitalization consistent and other minor spelling corrections.
[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         map_frozen();
673
674         show ();
675 }
676
677 void
678 MixerStrip::set_stuff_from_route ()
679 {
680         /* if width is not set, it will be set by the MixerUI or editor */
681
682         string str = gui_property ("strip-width");
683         if (!str.empty()) {
684                 set_width_enum (Width (string_2_enum (str, _width)), this);
685         }
686 }
687
688 void
689 MixerStrip::set_width_enum (Width w, void* owner)
690 {
691         /* always set the gpm width again, things may be hidden */
692
693         gpm.set_width (w);
694         panners.set_width (w);
695
696         boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
697
698         _width_owner = owner;
699
700         _width = w;
701
702         if (_width_owner == this) {
703                 set_gui_property ("strip-width", enum_2_string (_width));
704         }
705
706         set_button_names ();
707
708         const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
709
710         switch (w) {
711         case Wide:
712
713                 if (show_sends_button)  {
714                         show_sends_button->set_text (_("Aux"));
715                 }
716
717                 gpm.gain_automation_style_button.set_text (
718                                 gpm.astyle_string(gain_automation->automation_style()));
719                 gpm.gain_automation_state_button.set_text (
720                                 gpm.astate_string(gain_automation->automation_state()));
721
722                 if (_route->panner()) {
723                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
724                                         panners.astyle_string(_route->panner()->automation_style()));
725                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
726                                         panners.astate_string(_route->panner()->automation_state()));
727                 }
728
729                 {
730                         // panners expect an even number of horiz. pixels
731                         int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
732                         width &= ~1;
733                         set_size_request (width, -1);
734                 }
735                 break;
736
737         case Narrow:
738
739                 if (show_sends_button) {
740                         show_sends_button->set_text (_("Snd"));
741                 }
742
743                 gpm.gain_automation_style_button.set_text (
744                                 gpm.short_astyle_string(gain_automation->automation_style()));
745                 gpm.gain_automation_state_button.set_text (
746                                 gpm.short_astate_string(gain_automation->automation_state()));
747                 gain_meter().setup_meters (); // recalc meter width
748
749                 if (_route->panner()) {
750                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
751                         panners.short_astyle_string(_route->panner()->automation_style()));
752                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
753                         panners.short_astate_string(_route->panner()->automation_state()));
754                 }
755
756                 {
757                         // panners expect an even number of horiz. pixels
758                         int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
759                         width &= ~1;
760                         set_size_request (width, -1);
761                 }
762                 break;
763         }
764
765         processor_box.set_width (w);
766
767         update_input_display ();
768         update_output_display ();
769         setup_comment_button ();
770         route_group_changed ();
771         name_changed ();
772         WidthChanged ();
773 }
774
775 void
776 MixerStrip::set_packed (bool yn)
777 {
778         _packed = yn;
779
780         if (_packed) {
781                 set_gui_property ("visible", true);
782         } else {
783                 set_gui_property ("visible", false);
784         }
785 }
786
787
788 struct RouteCompareByName {
789         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
790                 return a->name().compare (b->name()) < 0;
791         }
792 };
793
794 gint
795 MixerStrip::output_release (GdkEventButton *ev)
796 {
797         switch (ev->button) {
798         case 3:
799                 edit_output_configuration ();
800                 break;
801         }
802
803         return false;
804 }
805
806 gint
807 MixerStrip::output_press (GdkEventButton *ev)
808 {
809         using namespace Menu_Helpers;
810         if (!_session->engine().connected()) {
811                 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
812                 msg.run ();
813                 return true;
814         }
815
816         MenuList& citems = output_menu.items();
817         switch (ev->button) {
818
819         case 3:
820                 return false;  //wait for the mouse-up to pop the dialog
821
822         case 1:
823         {
824                 output_menu.set_name ("ArdourContextMenu");
825                 citems.clear ();
826                 output_menu_bundles.clear ();
827
828                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
829
830                 citems.push_back (SeparatorElem());
831                 uint32_t const n_with_separator = citems.size ();
832
833                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
834
835                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
836
837                 /* give user bundles first chance at being in the menu */
838
839                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
840                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
841                                 maybe_add_bundle_to_output_menu (*i, current);
842                         }
843                 }
844
845                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
846                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
847                                 maybe_add_bundle_to_output_menu (*i, current);
848                         }
849                 }
850
851                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
852                 RouteList copy = *routes;
853                 copy.sort (RouteCompareByName ());
854                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
855                         maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
856                 }
857
858                 if (citems.size() == n_with_separator) {
859                         /* no routes added; remove the separator */
860                         citems.pop_back ();
861                 }
862
863                 citems.push_back (SeparatorElem());
864
865                 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
866                         citems.push_back (
867                                 MenuElem (
868                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
869                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
870                                         )
871                                 );
872                 }
873
874                 citems.push_back (SeparatorElem());
875                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
876
877                 output_menu.popup (1, ev->time);
878                 break;
879         }
880
881         default:
882                 break;
883         }
884         return TRUE;
885 }
886
887 gint
888 MixerStrip::input_release (GdkEventButton *ev)
889 {
890         switch (ev->button) {
891
892         case 3:
893                 edit_input_configuration ();
894                 break;
895         default:
896                 break;
897
898         }
899
900         return false;
901 }
902
903
904 gint
905 MixerStrip::input_press (GdkEventButton *ev)
906 {
907         using namespace Menu_Helpers;
908
909         MenuList& citems = input_menu.items();
910         input_menu.set_name ("ArdourContextMenu");
911         citems.clear();
912
913         if (!_session->engine().connected()) {
914                 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
915                 msg.run ();
916                 return true;
917         }
918
919         if (_session->actively_recording() && _route->record_enabled())
920                 return true;
921
922         switch (ev->button) {
923
924         case 3:
925                 return false;  //don't handle the mouse-down here.  wait for mouse-up to pop the menu
926
927         case 1:
928         {
929                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
930
931                 citems.push_back (SeparatorElem());
932                 uint32_t const n_with_separator = citems.size ();
933
934                 input_menu_bundles.clear ();
935
936                 ARDOUR::BundleList current = _route->input()->bundles_connected ();
937
938                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
939
940                 /* give user bundles first chance at being in the menu */
941
942                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
943                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
944                                 maybe_add_bundle_to_input_menu (*i, current);
945                         }
946                 }
947
948                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
949                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
950                                 maybe_add_bundle_to_input_menu (*i, current);
951                         }
952                 }
953
954                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
955                 RouteList copy = *routes;
956                 copy.sort (RouteCompareByName ());
957                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
958                         maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
959                 }
960
961                 if (citems.size() == n_with_separator) {
962                         /* no routes added; remove the separator */
963                         citems.pop_back ();
964                 }
965
966                 citems.push_back (SeparatorElem());
967                 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
968                         citems.push_back (
969                                 MenuElem (
970                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
971                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
972                                         )
973                                 );
974                 }
975
976                 citems.push_back (SeparatorElem());
977                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
978
979                 input_menu.popup (1, ev->time);
980
981                 break;
982         }
983         default:
984                 break;
985         }
986         return TRUE;
987 }
988
989 void
990 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
991 {
992         if (ignore_toggle) {
993                 return;
994         }
995
996         ARDOUR::BundleList current = _route->input()->bundles_connected ();
997
998         if (std::find (current.begin(), current.end(), c) == current.end()) {
999                 _route->input()->connect_ports_to_bundle (c, true, this);
1000         } else {
1001                 _route->input()->disconnect_ports_from_bundle (c, this);
1002         }
1003 }
1004
1005 void
1006 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1007 {
1008         if (ignore_toggle) {
1009                 return;
1010         }
1011
1012         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1013
1014         if (std::find (current.begin(), current.end(), c) == current.end()) {
1015                 _route->output()->connect_ports_to_bundle (c, true, this);
1016         } else {
1017                 _route->output()->disconnect_ports_from_bundle (c, this);
1018         }
1019 }
1020
1021 void
1022 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1023 {
1024         using namespace Menu_Helpers;
1025
1026         if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1027                 return;
1028         }
1029
1030         list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1031         while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1032                 ++i;
1033         }
1034
1035         if (i != input_menu_bundles.end()) {
1036                 return;
1037         }
1038
1039         input_menu_bundles.push_back (b);
1040
1041         MenuList& citems = input_menu.items();
1042
1043         std::string n = b->name ();
1044         replace_all (n, "_", " ");
1045
1046         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1047 }
1048
1049 void
1050 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1051 {
1052         using namespace Menu_Helpers;
1053
1054         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1055                 return;
1056         }
1057
1058         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1059         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1060                 ++i;
1061         }
1062
1063         if (i != output_menu_bundles.end()) {
1064                 return;
1065         }
1066
1067         output_menu_bundles.push_back (b);
1068
1069         MenuList& citems = output_menu.items();
1070
1071         std::string n = b->name ();
1072         replace_all (n, "_", " ");
1073
1074         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1075 }
1076
1077 void
1078 MixerStrip::update_diskstream_display ()
1079 {
1080         if (is_track() && input_selector) {
1081                         input_selector->hide_all ();
1082         }
1083
1084         route_color_changed ();
1085 }
1086
1087 void
1088 MixerStrip::connect_to_pan ()
1089 {
1090         ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1091
1092         panstate_connection.disconnect ();
1093         panstyle_connection.disconnect ();
1094
1095         if (!_route->panner()) {
1096                 return;
1097         }
1098
1099         boost::shared_ptr<Pannable> p = _route->pannable ();
1100
1101         p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1102         p->automation_style_changed.connect (panstyle_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_style_changed, &panners), gui_context());
1103
1104         /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1105          * However, that only works a panner was previously set.
1106          *
1107          * PannerUI must remain subscribed to _panshell->Changed() in case
1108          * we switch the panner eg. AUX-Send and back
1109          * _route->panner_shell()->Changed() vs _panshell->Changed
1110          */
1111         if (panners._panner == 0) {
1112                 panners.panshell_changed ();
1113         }
1114         update_panner_choices();
1115 }
1116
1117 void
1118 MixerStrip::update_panner_choices ()
1119 {
1120         ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1121         if (!_route->panner_shell()) { return; }
1122
1123         uint32_t in = _route->output()->n_ports().n_audio();
1124         uint32_t out = in;
1125         if (_route->panner()) {
1126                 in = _route->panner()->in().n_audio();
1127         }
1128
1129         panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1130 }
1131
1132 /*
1133  * Output port labelling
1134  * =====================
1135  *
1136  * Case 1: Each output has one connection, all connections are to system:playback_%i
1137  *   out 1 -> system:playback_1
1138  *   out 2 -> system:playback_2
1139  *   out 3 -> system:playback_3
1140  *   Display as: 1/2/3
1141  *
1142  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1143  *   out 1 -> ardour:track_x/in 1
1144  *   out 2 -> ardour:track_x/in 2
1145  *   Display as: track_x
1146  *
1147  * Case 3: Each output has one connection, all connections are to Jack client "program x"
1148  *   out 1 -> program x:foo
1149  *   out 2 -> program x:foo
1150  *   Display as: program x
1151  *
1152  * Case 4: No connections (Disconnected)
1153  *   Display as: -
1154  *
1155  * Default case (unusual routing):
1156  *   Display as: *number of connections*
1157  *
1158  * Tooltips
1159  * ========
1160  * .-----------------------------------------------.
1161  * | Mixdown                                       |
1162  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1163  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1164  * '-----------------------------------------------'
1165  * .-----------------------------------------------.
1166  * | Guitar SM58                                   |
1167  * | Disconnected                                  |
1168  * '-----------------------------------------------'
1169  */
1170
1171 void
1172 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1173 {
1174         uint32_t io_count;
1175         uint32_t io_index;
1176         boost::shared_ptr<Port> port;
1177         vector<string> port_connections;
1178
1179         uint32_t total_connection_count = 0;
1180         uint32_t io_connection_count = 0;
1181         uint32_t ardour_connection_count = 0;
1182         uint32_t system_connection_count = 0;
1183         uint32_t other_connection_count = 0;
1184         uint32_t typed_connection_count = 0;
1185
1186         ostringstream label;
1187
1188         bool have_label = false;
1189         bool each_io_has_one_connection = true;
1190
1191         string connection_name;
1192         string ardour_track_name;
1193         string other_connection_type;
1194         string system_ports;
1195         string system_port;
1196
1197         ostringstream tooltip;
1198         char * tooltip_cstr;
1199
1200         //to avoid confusion, the button caption should only show connections that match the datatype of the track
1201         DataType dt = DataType::AUDIO;
1202         if ( boost::dynamic_pointer_cast<MidiTrack>(route) != 0 ) {
1203                 dt = DataType::MIDI;
1204                 // avoid further confusion with Midi-tracks that have a synth.
1205                 // Audio-ports may be connected, but button says "Disconnected"
1206                 tooltip << _("MIDI ");
1207         }
1208
1209         if (for_input) {
1210                 io_count = route->n_inputs().n_total();
1211                 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1212         } else {
1213                 io_count = route->n_outputs().n_total();
1214                 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1215         }
1216
1217
1218         for (io_index = 0; io_index < io_count; ++io_index) {
1219                 if (for_input) {
1220                         port = route->input()->nth (io_index);
1221                 } else {
1222                         port = route->output()->nth (io_index);
1223                 }
1224
1225                 port_connections.clear ();
1226                 port->get_connections(port_connections);
1227
1228                 //ignore any port connections that don't match our DataType
1229                 if (port->type() != dt) {
1230                         if (!port_connections.empty()) {
1231                                 ++typed_connection_count;
1232                         }
1233                         continue;
1234                 }
1235
1236                 io_connection_count = 0;
1237
1238                 if (!port_connections.empty()) {
1239                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1240                                 string pn = "";
1241                                 string& connection_name (*i);
1242
1243                                 if (connection_name.find("system:") == 0) {
1244                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1245                                 }
1246
1247                                 if (io_connection_count == 0) {
1248                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1249                                                 << " -> "
1250                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1251                                 } else {
1252                                         tooltip << ", "
1253                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1254                                 }
1255
1256                                 if (connection_name.find("ardour:") == 0) {
1257                                         if (ardour_track_name.empty()) {
1258                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1259                                                 string::size_type slash = connection_name.find("/");
1260                                                 if (slash != string::npos) {
1261                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1262                                                 }
1263                                         }
1264
1265                                         if (connection_name.find(ardour_track_name) == 0) {
1266                                                 ++ardour_connection_count;
1267                                         }
1268                                 } else if (!pn.empty()) {
1269                                         if (system_ports.empty()) {
1270                                                 system_ports += pn;
1271                                         } else {
1272                                                 system_ports += "/" + pn;
1273                                         }
1274                                         if (connection_name.find("system:") == 0) {
1275                                                 ++system_connection_count;
1276                                         }
1277                                 } else if (connection_name.find("system:midi_") == 0) {
1278                                         if (for_input) {
1279                                                 // "system:midi_capture_123" -> "123"
1280                                                 system_port = "M " + connection_name.substr(20);
1281                                         } else {
1282                                                 // "system:midi_playback_123" -> "123"
1283                                                 system_port = "M " + connection_name.substr(21);
1284                                         }
1285
1286                                         if (system_ports.empty()) {
1287                                                 system_ports += system_port;
1288                                         } else {
1289                                                 system_ports += "/" + system_port;
1290                                         }
1291
1292                                         ++system_connection_count;
1293
1294                                 } else if (connection_name.find("system:") == 0) {
1295                                         if (for_input) {
1296                                                 // "system:capture_123" -> "123"
1297                                                 system_port = connection_name.substr(15);
1298                                         } else {
1299                                                 // "system:playback_123" -> "123"
1300                                                 system_port = connection_name.substr(16);
1301                                         }
1302
1303                                         if (system_ports.empty()) {
1304                                                 system_ports += system_port;
1305                                         } else {
1306                                                 system_ports += "/" + system_port;
1307                                         }
1308
1309                                         ++system_connection_count;
1310                                 } else {
1311                                         if (other_connection_type.empty()) {
1312                                                 // "jamin:in 1" -> "jamin:"
1313                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1314                                         }
1315
1316                                         if (connection_name.find(other_connection_type) == 0) {
1317                                                 ++other_connection_count;
1318                                         }
1319                                 }
1320
1321                                 ++total_connection_count;
1322                                 ++io_connection_count;
1323                         }
1324                 }
1325
1326                 if (io_connection_count != 1) {
1327                         each_io_has_one_connection = false;
1328                 }
1329         }
1330
1331         if (total_connection_count == 0) {
1332                 tooltip << endl << _("Disconnected");
1333         }
1334
1335         tooltip_cstr = new char[tooltip.str().size() + 1];
1336         strcpy(tooltip_cstr, tooltip.str().c_str());
1337
1338         if (for_input) {
1339                 set_tooltip (&input_button, tooltip_cstr);
1340         } else {
1341                 set_tooltip (&output_button, tooltip_cstr);
1342         }
1343
1344         if (each_io_has_one_connection) {
1345                 if (total_connection_count == ardour_connection_count) {
1346                         // all connections are to the same track in ardour
1347                         // "ardour:Master/" -> "Master"
1348                         string::size_type slash = ardour_track_name.find("/");
1349                         if (slash != string::npos) {
1350                                 label << ardour_track_name.substr(7, slash - 7);
1351                                 have_label = true;
1352                         }
1353                 }
1354                 else if (total_connection_count == system_connection_count) {
1355                         // all connections are to system ports
1356                         label << system_ports;
1357                         have_label = true;
1358                 }
1359                 else if (total_connection_count == other_connection_count) {
1360                         // all connections are to the same external program eg jamin
1361                         // "jamin:" -> "jamin"
1362                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1363                         have_label = true;
1364                 }
1365         }
1366
1367         if (!have_label) {
1368                 if (total_connection_count == 0) {
1369                         // Disconnected
1370                         label << "-";
1371                 } else {
1372                         // Odd configuration
1373                         label << "*" << total_connection_count << "*";
1374                 }
1375                 if (typed_connection_count > 0) {
1376                         label << "\u2295"; // circled plus
1377                 }
1378         }
1379
1380         if (for_input) {
1381                 input_button.set_text (label.str());
1382         } else {
1383                 output_button.set_text (label.str());
1384         }
1385 }
1386
1387 void
1388 MixerStrip::update_input_display ()
1389 {
1390         update_io_button (_route, _width, true);
1391         panners.setup_pan ();
1392
1393         if (has_audio_outputs ()) {
1394                 panners.show_all ();
1395         } else {
1396                 panners.hide_all ();
1397         }
1398
1399 }
1400
1401 void
1402 MixerStrip::update_output_display ()
1403 {
1404         update_io_button (_route, _width, false);
1405         gpm.setup_meters ();
1406         panners.setup_pan ();
1407
1408         if (has_audio_outputs ()) {
1409                 panners.show_all ();
1410         } else {
1411                 panners.hide_all ();
1412         }
1413 }
1414
1415 void
1416 MixerStrip::fast_update ()
1417 {
1418         gpm.update_meters ();
1419 }
1420
1421 void
1422 MixerStrip::diskstream_changed ()
1423 {
1424         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1425 }
1426
1427 void
1428 MixerStrip::io_changed_proxy ()
1429 {
1430         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1431 }
1432
1433 void
1434 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1435 {
1436         boost::shared_ptr<Port> a = wa.lock ();
1437         boost::shared_ptr<Port> b = wb.lock ();
1438
1439         if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1440                 update_input_display ();
1441                 set_width_enum (_width, this);
1442         }
1443
1444         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1445                 update_output_display ();
1446                 set_width_enum (_width, this);
1447         }
1448 }
1449
1450 void
1451 MixerStrip::setup_comment_button ()
1452 {
1453         switch (_width) {
1454
1455         case Wide:
1456                 if (_route->comment().empty ()) {
1457                         _comment_button.unset_bg (STATE_NORMAL);
1458                         _comment_button.set_text (_("Comments"));
1459                 } else {
1460                         _comment_button.modify_bg (STATE_NORMAL, color ());
1461                         _comment_button.set_text (_("*Comments*"));
1462                 }
1463                 break;
1464
1465         case Narrow:
1466                 if (_route->comment().empty ()) {
1467                         _comment_button.unset_bg (STATE_NORMAL);
1468                         _comment_button.set_text (_("Cmt"));
1469                 } else {
1470                         _comment_button.modify_bg (STATE_NORMAL, color ());
1471                         _comment_button.set_text (_("*Cmt*"));
1472                 }
1473                 break;
1474         }
1475
1476         set_tooltip (
1477                 _comment_button, _route->comment().empty() ? _("Click to add/edit comments") : _route->comment()
1478                 );
1479
1480 }
1481
1482 bool
1483 MixerStrip::select_route_group (GdkEventButton *ev)
1484 {
1485         using namespace Menu_Helpers;
1486
1487         if (ev->button == 1) {
1488
1489                 if (group_menu == 0) {
1490
1491                         PropertyList* plist = new PropertyList();
1492
1493                         plist->add (Properties::gain, true);
1494                         plist->add (Properties::mute, true);
1495                         plist->add (Properties::solo, true);
1496
1497                         group_menu = new RouteGroupMenu (_session, plist);
1498                 }
1499
1500                 WeakRouteList r;
1501                 r.push_back (route ());
1502                 group_menu->build (r);
1503                 group_menu->menu()->popup (1, ev->time);
1504         }
1505
1506         return true;
1507 }
1508
1509 void
1510 MixerStrip::route_group_changed ()
1511 {
1512         ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1513
1514         RouteGroup *rg = _route->route_group();
1515
1516         if (rg) {
1517                 group_button.set_text (PBD::short_version (rg->name(), 5));
1518         } else {
1519                 switch (_width) {
1520                 case Wide:
1521                         group_button.set_text (_("Grp"));
1522                         break;
1523                 case Narrow:
1524                         group_button.set_text (_("~G"));
1525                         break;
1526                 }
1527         }
1528 }
1529
1530 void
1531 MixerStrip::route_color_changed ()
1532 {
1533         name_button.modify_bg (STATE_NORMAL, color());
1534         number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1535         reset_strip_style ();
1536 }
1537
1538 void
1539 MixerStrip::show_passthru_color ()
1540 {
1541         reset_strip_style ();
1542 }
1543
1544 void
1545 MixerStrip::build_route_ops_menu ()
1546 {
1547         using namespace Menu_Helpers;
1548         route_ops_menu = new Menu;
1549         route_ops_menu->set_name ("ArdourContextMenu");
1550
1551         MenuList& items = route_ops_menu->items();
1552
1553         items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1554
1555         items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1556
1557         items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1558
1559         items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1560
1561         items.push_back (SeparatorElem());
1562
1563         if (!_route->is_master()) {
1564                 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1565         }
1566         items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1567         rename_menu_item = &items.back();
1568
1569         items.push_back (SeparatorElem());
1570         items.push_back (CheckMenuElem (_("Active")));
1571         Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1572         i->set_active (_route->active());
1573         i->set_sensitive(! _session->transport_rolling());
1574         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1575
1576         items.push_back (SeparatorElem());
1577
1578         items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1579
1580         items.push_back (SeparatorElem());
1581         items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1582         denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1583         denormal_menu_item->set_active (_route->denormal_protection());
1584
1585         if (!Profile->get_sae()) {
1586                 items.push_back (SeparatorElem());
1587                 items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
1588         }
1589
1590         if (_route) {
1591                 /* note that this relies on selection being shared across editor and
1592                    mixer (or global to the backend, in the future), which is the only
1593                    sane thing for users anyway.
1594                 */
1595
1596                 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1597                 if (rtav) {
1598                         Selection& selection (PublicEditor::instance().get_selection());
1599                         if (!selection.selected (rtav)) {
1600                                 selection.set (rtav);
1601                         }
1602
1603                         if (!_route->is_master()) {
1604                                 items.push_back (SeparatorElem());
1605                                 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1606                         }
1607         
1608                         items.push_back (SeparatorElem());
1609                         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1610                 }
1611         }
1612 }
1613
1614 gboolean
1615 MixerStrip::name_button_button_press (GdkEventButton* ev)
1616 {
1617         if (ev->button == 3) {
1618                 list_route_operations ();
1619
1620                 /* do not allow rename if the track is record-enabled */
1621                 rename_menu_item->set_sensitive (!_route->record_enabled());
1622                 route_ops_menu->popup (1, ev->time);
1623
1624                 return true;
1625         }
1626
1627         return false;
1628 }
1629
1630 gboolean
1631 MixerStrip::name_button_button_release (GdkEventButton* ev)
1632 {
1633         if (ev->button == 1) {
1634                 list_route_operations ();
1635
1636                 /* do not allow rename if the track is record-enabled */
1637                 rename_menu_item->set_sensitive (!_route->record_enabled());
1638                 route_ops_menu->popup (1, ev->time);
1639         }
1640
1641         return false;
1642 }
1643
1644 gboolean
1645 MixerStrip::number_button_button_press (GdkEventButton* ev)
1646 {
1647         if (  ev->button == 3 ) {
1648                 list_route_operations ();
1649
1650                 /* do not allow rename if the track is record-enabled */
1651                 rename_menu_item->set_sensitive (!_route->record_enabled());
1652                 route_ops_menu->popup (1, ev->time);
1653
1654                 return true;
1655         }
1656
1657         return false;
1658 }
1659
1660 void
1661 MixerStrip::list_route_operations ()
1662 {
1663         delete route_ops_menu;
1664         build_route_ops_menu ();
1665 }
1666
1667 void
1668 MixerStrip::set_selected (bool yn)
1669 {
1670         AxisView::set_selected (yn);
1671         if (_selected) {
1672                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1673                 global_frame.set_name ("MixerStripSelectedFrame");
1674         } else {
1675                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1676                 global_frame.set_name ("MixerStripFrame");
1677         }
1678         global_frame.queue_draw ();
1679
1680 //      if (!yn)
1681 //              processor_box.deselect_all_processors();
1682 }
1683
1684 void
1685 MixerStrip::property_changed (const PropertyChange& what_changed)
1686 {
1687         RouteUI::property_changed (what_changed);
1688
1689         if (what_changed.contains (ARDOUR::Properties::name)) {
1690                 name_changed ();
1691         }
1692 }
1693
1694 void
1695 MixerStrip::name_changed ()
1696 {
1697         switch (_width) {
1698                 case Wide:
1699                         name_button.set_text (_route->name());
1700                         break;
1701                 case Narrow:
1702                         name_button.set_text (PBD::short_version (_route->name(), 5));
1703                         break;
1704         }
1705
1706         set_tooltip (name_button, _route->name());
1707
1708         if (_session->config.get_track_name_number()) {
1709                 const int64_t track_number = _route->track_number ();
1710                 if (track_number == 0) {
1711                         number_label.set_text ("-");
1712                 } else {
1713                         number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
1714                 }
1715         } else {
1716                 number_label.set_text ("");
1717         }
1718 }
1719
1720 void
1721 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1722 {
1723         input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1724 }
1725
1726 void
1727 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1728 {
1729         output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1730 }
1731
1732 void
1733 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1734 {
1735         name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1736 }
1737
1738 bool
1739 MixerStrip::width_button_pressed (GdkEventButton* ev)
1740 {
1741         if (ev->button != 1) {
1742                 return false;
1743         }
1744
1745         if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1746                 switch (_width) {
1747                 case Wide:
1748                         _mixer.set_strip_width (Narrow, true);
1749                         break;
1750
1751                 case Narrow:
1752                         _mixer.set_strip_width (Wide, true);
1753                         break;
1754                 }
1755         } else {
1756                 switch (_width) {
1757                 case Wide:
1758                         set_width_enum (Narrow, this);
1759                         break;
1760                 case Narrow:
1761                         set_width_enum (Wide, this);
1762                         break;
1763                 }
1764         }
1765
1766         return true;
1767 }
1768
1769 void
1770 MixerStrip::hide_clicked ()
1771 {
1772         // LAME fix to reset the button status for when it is redisplayed (part 1)
1773         hide_button.set_sensitive(false);
1774
1775         if (_embedded) {
1776                 Hiding(); /* EMIT_SIGNAL */
1777         } else {
1778                 _mixer.hide_strip (this);
1779         }
1780
1781         // (part 2)
1782         hide_button.set_sensitive(true);
1783 }
1784
1785 void
1786 MixerStrip::set_embedded (bool yn)
1787 {
1788         _embedded = yn;
1789 }
1790
1791 void
1792 MixerStrip::map_frozen ()
1793 {
1794         ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1795
1796         boost::shared_ptr<AudioTrack> at = audio_track();
1797
1798         if (at) {
1799                 switch (at->freeze_state()) {
1800                 case AudioTrack::Frozen:
1801                         processor_box.set_sensitive (false);
1802                         hide_redirect_editors ();
1803                         break;
1804                 default:
1805                         processor_box.set_sensitive (true);
1806                         // XXX need some way, maybe, to retoggle redirect editors
1807                         break;
1808                 }
1809         } else {
1810                 processor_box.set_sensitive (true);
1811         }
1812 }
1813
1814 void
1815 MixerStrip::hide_redirect_editors ()
1816 {
1817         _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1818 }
1819
1820 void
1821 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1822 {
1823         boost::shared_ptr<Processor> processor (p.lock ());
1824         if (!processor) {
1825                 return;
1826         }
1827
1828         Gtk::Window* w = processor_box.get_processor_ui (processor);
1829
1830         if (w) {
1831                 w->hide ();
1832         }
1833 }
1834
1835 void
1836 MixerStrip::reset_strip_style ()
1837 {
1838         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1839
1840                 gpm.set_fader_name ("SendStripBase");
1841
1842         } else {
1843
1844                 if (is_midi_track()) {
1845                         if (_route->active()) {
1846                                 set_name ("MidiTrackStripBase");
1847                         } else {
1848                                 set_name ("MidiTrackStripBaseInactive");
1849                         }
1850                         gpm.set_fader_name ("MidiTrackFader");
1851                 } else if (is_audio_track()) {
1852                         if (_route->active()) {
1853                                 set_name ("AudioTrackStripBase");
1854                         } else {
1855                                 set_name ("AudioTrackStripBaseInactive");
1856                         }
1857                         gpm.set_fader_name ("AudioTrackFader");
1858                 } else {
1859                         if (_route->active()) {
1860                                 set_name ("AudioBusStripBase");
1861                         } else {
1862                                 set_name ("AudioBusStripBaseInactive");
1863                         }
1864                         gpm.set_fader_name ("AudioBusFader");
1865
1866                         /* (no MIDI busses yet) */
1867                 }
1868         }
1869 }
1870
1871
1872 void
1873 MixerStrip::engine_stopped ()
1874 {
1875 }
1876
1877 void
1878 MixerStrip::engine_running ()
1879 {
1880 }
1881
1882 string
1883 MixerStrip::meter_point_string (MeterPoint mp)
1884 {
1885         switch (_width) {
1886         case Wide:
1887                 switch (mp) {
1888                 case MeterInput:
1889                         return _("In");
1890                         break;
1891
1892                 case MeterPreFader:
1893                         return _("Pre");
1894                         break;
1895
1896                 case MeterPostFader:
1897                         return _("Post");
1898                         break;
1899
1900                 case MeterOutput:
1901                         return _("Out");
1902                         break;
1903
1904                 case MeterCustom:
1905                 default:
1906                         return _("Custom");
1907                         break;
1908                 }
1909                 break;
1910         case Narrow:
1911                 switch (mp) {
1912                 case MeterInput:
1913                         return S_("Meter|In");
1914                         break;
1915
1916                 case MeterPreFader:
1917                         return S_("Meter|Pr");
1918                         break;
1919
1920                 case MeterPostFader:
1921                         return S_("Meter|Po");
1922                         break;
1923
1924                 case MeterOutput:
1925                         return S_("Meter|O");
1926                         break;
1927
1928                 case MeterCustom:
1929                 default:
1930                         return S_("Meter|C");
1931                         break;
1932                 }
1933                 break;
1934         }
1935
1936         return string();
1937 }
1938
1939 /** Called when the metering point has changed */
1940 void
1941 MixerStrip::meter_changed ()
1942 {
1943         meter_point_button.set_text (meter_point_string (_route->meter_point()));
1944         gpm.setup_meters ();
1945         // reset peak when meter point changes
1946         gpm.reset_peak_display();
1947 }
1948
1949 /** The bus that we are displaying sends to has changed, or been turned off.
1950  *  @param send_to New bus that we are displaying sends to, or 0.
1951  */
1952 void
1953 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
1954 {
1955         RouteUI::bus_send_display_changed (send_to);
1956
1957         if (send_to) {
1958                 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
1959
1960                 if (send) {
1961                         show_send (send);
1962                 } else {
1963                         revert_to_default_display ();
1964                 }
1965         } else {
1966                 revert_to_default_display ();
1967         }
1968 }
1969
1970 void
1971 MixerStrip::drop_send ()
1972 {
1973         boost::shared_ptr<Send> current_send;
1974
1975         if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
1976                 current_send->set_metering (false);
1977         }
1978
1979         send_gone_connection.disconnect ();
1980         input_button.set_sensitive (true);
1981         output_button.set_sensitive (true);
1982         group_button.set_sensitive (true);
1983         set_invert_sensitive (true);
1984         meter_point_button.set_sensitive (true);
1985         mute_button->set_sensitive (true);
1986         solo_button->set_sensitive (true);
1987         rec_enable_button->set_sensitive (true);
1988         solo_isolated_led->set_sensitive (true);
1989         solo_safe_led->set_sensitive (true);
1990         monitor_input_button->set_sensitive (true);
1991         monitor_disk_button->set_sensitive (true);
1992         _comment_button.set_sensitive (true);
1993 }
1994
1995 void
1996 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
1997 {
1998         _current_delivery = d;
1999         DeliveryChanged (_current_delivery);
2000 }
2001
2002 void
2003 MixerStrip::show_send (boost::shared_ptr<Send> send)
2004 {
2005         assert (send != 0);
2006
2007         drop_send ();
2008
2009         set_current_delivery (send);
2010
2011         send->meter()->set_type(_route->shared_peak_meter()->get_type());
2012         send->set_metering (true);
2013         _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2014
2015         gain_meter().set_controls (_route, send->meter(), send->amp());
2016         gain_meter().setup_meters ();
2017
2018         uint32_t const in = _current_delivery->pans_required();
2019         uint32_t const out = _current_delivery->pan_outs();
2020
2021         panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2022         panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2023         panner_ui().setup_pan ();
2024         panner_ui().set_send_drawing_mode (true);
2025         panner_ui().show_all ();
2026
2027         input_button.set_sensitive (false);
2028         group_button.set_sensitive (false);
2029         set_invert_sensitive (false);
2030         meter_point_button.set_sensitive (false);
2031         mute_button->set_sensitive (false);
2032         solo_button->set_sensitive (false);
2033         rec_enable_button->set_sensitive (false);
2034         solo_isolated_led->set_sensitive (false);
2035         solo_safe_led->set_sensitive (false);
2036         monitor_input_button->set_sensitive (false);
2037         monitor_disk_button->set_sensitive (false);
2038         _comment_button.set_sensitive (false);
2039
2040         if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2041                 output_button.set_sensitive (false);
2042         }
2043
2044         reset_strip_style ();
2045 }
2046
2047 void
2048 MixerStrip::revert_to_default_display ()
2049 {
2050         drop_send ();
2051
2052         set_current_delivery (_route->main_outs ());
2053
2054         gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp());
2055         gain_meter().setup_meters ();
2056
2057         panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2058         update_panner_choices();
2059         panner_ui().setup_pan ();
2060         panner_ui().set_send_drawing_mode (false);
2061
2062         if (has_audio_outputs ()) {
2063                 panners.show_all ();
2064         } else {
2065                 panners.hide_all ();
2066         }
2067
2068         reset_strip_style ();
2069 }
2070
2071 void
2072 MixerStrip::set_button_names ()
2073 {
2074         switch (_width) {
2075         case Wide:
2076                 mute_button->set_text (_("Mute"));
2077                 monitor_input_button->set_text (_("In"));
2078                 monitor_disk_button->set_text (_("Disk"));
2079
2080                 if (_route && _route->solo_safe()) {
2081                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2082                 } else {
2083                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2084                 }
2085                 if (!Config->get_solo_control_is_listen_control()) {
2086                         solo_button->set_text (_("Solo"));
2087                 } else {
2088                         switch (Config->get_listen_position()) {
2089                         case AfterFaderListen:
2090                                 solo_button->set_text (_("AFL"));
2091                                 break;
2092                         case PreFaderListen:
2093                                 solo_button->set_text (_("PFL"));
2094                                 break;
2095                         }
2096                 }
2097                 solo_isolated_led->set_text (_("Iso"));
2098                 solo_safe_led->set_text (S_("SoloLock|Lock"));
2099                 break;
2100
2101         default:
2102                 mute_button->set_text (S_("Mute|M"));
2103                 monitor_input_button->set_text (S_("MonitorInput|I"));
2104                 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2105
2106                 if (_route && _route->solo_safe()) {
2107                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2108                 } else {
2109                         solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2110                 }
2111                 if (!Config->get_solo_control_is_listen_control()) {
2112                         solo_button->set_text (S_("Solo|S"));
2113                 } else {
2114                         switch (Config->get_listen_position()) {
2115                         case AfterFaderListen:
2116                                 solo_button->set_text (S_("AfterFader|A"));
2117                                 break;
2118                         case PreFaderListen:
2119                                 solo_button->set_text (S_("Prefader|P"));
2120                                 break;
2121                         }
2122                 }
2123
2124                 solo_isolated_led->set_text (S_("SoloIso|I"));
2125                 solo_safe_led->set_text (S_("SoloLock|L"));
2126                 break;
2127         }
2128
2129         if (_route) {
2130                 meter_point_button.set_text (meter_point_string (_route->meter_point()));
2131         } else {
2132                 meter_point_button.set_text ("");
2133         }
2134 }
2135
2136 PluginSelector*
2137 MixerStrip::plugin_selector()
2138 {
2139         return _mixer.plugin_selector();
2140 }
2141
2142 void
2143 MixerStrip::hide_things ()
2144 {
2145         processor_box.hide_things ();
2146 }
2147
2148 bool
2149 MixerStrip::input_active_button_press (GdkEventButton*)
2150 {
2151         /* nothing happens on press */
2152         return true;
2153 }
2154
2155 bool
2156 MixerStrip::input_active_button_release (GdkEventButton* ev)
2157 {
2158         boost::shared_ptr<MidiTrack> mt = midi_track ();
2159
2160         if (!mt) {
2161                 return true;
2162         }
2163
2164         boost::shared_ptr<RouteList> rl (new RouteList);
2165
2166         rl->push_back (route());
2167
2168         _session->set_exclusive_input_active (rl, !mt->input_active(),
2169                                               Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2170
2171         return true;
2172 }
2173
2174 void
2175 MixerStrip::midi_input_status_changed ()
2176 {
2177         if (midi_input_enable_button) {
2178                 boost::shared_ptr<MidiTrack> mt = midi_track ();
2179                 assert (mt);
2180                 midi_input_enable_button->set_active (mt->input_active ());
2181         }
2182 }
2183
2184 string
2185 MixerStrip::state_id () const
2186 {
2187         return string_compose ("strip %1", _route->id().to_s());
2188 }
2189
2190 void
2191 MixerStrip::parameter_changed (string p)
2192 {
2193         if (p == _visibility.get_state_name()) {
2194                 /* The user has made changes to the mixer strip visibility, so get
2195                    our VisibilityGroup to reflect these changes in our widgets.
2196                 */
2197                 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2198         }
2199         else if (p == "track-name-number") {
2200                 name_changed ();
2201         }
2202 }
2203
2204 /** Called to decide whether the solo isolate / solo lock button visibility should
2205  *  be overridden from that configured by the user.  We do this for the master bus.
2206  *
2207  *  @return optional value that is present if visibility state should be overridden.
2208  */
2209 boost::optional<bool>
2210 MixerStrip::override_solo_visibility () const
2211 {
2212         if (_route && _route->is_master ()) {
2213                 return boost::optional<bool> (false);
2214         }
2215
2216         return boost::optional<bool> ();
2217 }
2218
2219 void
2220 MixerStrip::add_input_port (DataType t)
2221 {
2222         _route->input()->add_port ("", this, t);
2223 }
2224
2225 void
2226 MixerStrip::add_output_port (DataType t)
2227 {
2228         _route->output()->add_port ("", this, t);
2229 }
2230
2231 void
2232 MixerStrip::route_active_changed ()
2233 {
2234         reset_strip_style ();
2235 }
2236
2237 void
2238 MixerStrip::copy_processors ()
2239 {
2240         processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2241 }
2242
2243 void
2244 MixerStrip::cut_processors ()
2245 {
2246         processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2247 }
2248
2249 void
2250 MixerStrip::paste_processors ()
2251 {
2252         processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2253 }
2254
2255 void
2256 MixerStrip::select_all_processors ()
2257 {
2258         processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2259 }
2260
2261 void
2262 MixerStrip::deselect_all_processors ()
2263 {
2264         processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2265 }
2266
2267 bool
2268 MixerStrip::delete_processors ()
2269 {
2270         return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2271 }
2272
2273 void
2274 MixerStrip::toggle_processors ()
2275 {
2276         processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2277 }
2278
2279 void
2280 MixerStrip::ab_plugins ()
2281 {
2282         processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2283 }
2284
2285 bool
2286 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2287 {
2288         if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2289                 return false;
2290         }
2291         if (ev->button == 3) {
2292                 popup_level_meter_menu (ev);
2293                 return true;
2294         }
2295
2296         return false;
2297 }
2298
2299 void
2300 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2301 {
2302         using namespace Gtk::Menu_Helpers;
2303
2304         Gtk::Menu* m = manage (new Menu);
2305         MenuList& items = m->items ();
2306
2307         RadioMenuItem::Group group;
2308
2309         _suspend_menu_callbacks = true;
2310         add_level_meter_item_point (items, group, _("Input"), MeterInput);
2311         add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2312         add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2313         add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2314         add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2315
2316         if (gpm.meter_channels().n_audio() == 0) {
2317                 m->popup (ev->button, ev->time);
2318                 _suspend_menu_callbacks = false;
2319                 return;
2320         }
2321
2322         RadioMenuItem::Group tgroup;
2323         items.push_back (SeparatorElem());
2324
2325         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2326         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2327         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms),  MeterKrms);
2328         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2329         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2330         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2331         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2332         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2333         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2334         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2335         add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU),  MeterVU);
2336
2337         int _strip_type;
2338         if (_route->is_master()) {
2339                 _strip_type = 4;
2340         }
2341         else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2342                         && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2343                 /* non-master bus */
2344                 _strip_type = 3;
2345         }
2346         else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2347                 _strip_type = 2;
2348         }
2349         else {
2350                 _strip_type = 1;
2351         }
2352
2353         MeterType cmt = _route->meter_type();
2354         const std::string cmn = ArdourMeter::meter_type_string(cmt);
2355
2356         items.push_back (SeparatorElem());
2357         items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2358                                 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2359         items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2360                                 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2361         items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2362                                 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2363
2364         m->popup (ev->button, ev->time);
2365         _suspend_menu_callbacks = false;
2366 }
2367
2368 void
2369 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2370                 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2371 {
2372         using namespace Menu_Helpers;
2373
2374         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2375         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2376         i->set_active (_route->meter_point() == point);
2377 }
2378
2379 void
2380 MixerStrip::set_meter_point (MeterPoint p)
2381 {
2382         if (_suspend_menu_callbacks) return;
2383         _route->set_meter_point (p);
2384 }
2385
2386 void
2387 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2388                 RadioMenuItem::Group& group, string const & name, MeterType type)
2389 {
2390         using namespace Menu_Helpers;
2391
2392         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2393         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2394         i->set_active (_route->meter_type() == type);
2395 }
2396
2397 void
2398 MixerStrip::set_meter_type (MeterType t)
2399 {
2400         if (_suspend_menu_callbacks) return;
2401         gpm.set_type (t);
2402 }