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