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