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