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