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