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