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