Remove <gtkmm.h> include from header files.
[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 <gtkmm/messagedialog.h>
26
27 #include "pbd/convert.h"
28 #include "pbd/enumwriter.h"
29 #include "pbd/replace_all.h"
30 #include "pbd/stacktrace.h"
31
32 #include "ardour/amp.h"
33 #include "ardour/audio_track.h"
34 #include "ardour/audioengine.h"
35 #include "ardour/internal_send.h"
36 #include "ardour/io.h"
37 #include "ardour/meter.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/pannable.h"
40 #include "ardour/panner.h"
41 #include "ardour/panner_shell.h"
42 #include "ardour/panner_manager.h"
43 #include "ardour/port.h"
44 #include "ardour/profile.h"
45 #include "ardour/route.h"
46 #include "ardour/route_group.h"
47 #include "ardour/send.h"
48 #include "ardour/session.h"
49 #include "ardour/types.h"
50 #include "ardour/user_bundle.h"
51 #include "ardour/vca.h"
52 #include "ardour/vca_manager.h"
53
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/menu_elems.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/doi.h"
58
59 #include "widgets/tooltips.h"
60
61 #include "ardour_window.h"
62 #include "enums_convert.h"
63 #include "mixer_strip.h"
64 #include "mixer_ui.h"
65 #include "keyboard.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 "ui_config.h"
74
75 #include "pbd/i18n.h"
76
77 using namespace ARDOUR;
78 using namespace ArdourWidgets;
79 using namespace PBD;
80 using namespace Gtk;
81 using namespace Gtkmm2ext;
82 using namespace std;
83 using namespace ArdourMeter;
84
85 MixerStrip* MixerStrip::_entered_mixer_strip;
86 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
87
88 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
89         : SessionHandlePtr (sess)
90         , RouteUI (sess)
91         , _mixer(mx)
92         , _mixer_owned (in_mixer)
93         , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
94         , gpm (sess, 250)
95         , panners (sess)
96         , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
97         , rec_mon_table (2, 2)
98         , solo_iso_table (1, 2)
99         , mute_solo_table (1, 2)
100         , bottom_button_table (1, 3)
101         , monitor_section_button (0)
102         , midi_input_enable_button (0)
103         , _plugin_insert_cnt (0)
104         , _comment_button (_("Comments"))
105         , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
106         , _visibility (X_("mixer-element-visibility"))
107         , control_slave_ui (sess)
108 {
109         init ();
110
111         if (!_mixer_owned) {
112                 /* the editor mixer strip: don't destroy it every time
113                    the underlying route goes away.
114                 */
115
116                 self_destruct = false;
117         }
118 }
119
120 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
121         : SessionHandlePtr (sess)
122         , RouteUI (sess)
123         , _mixer(mx)
124         , _mixer_owned (in_mixer)
125         , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
126         , gpm (sess, 250)
127         , panners (sess)
128         , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
129         , rec_mon_table (2, 2)
130         , solo_iso_table (1, 2)
131         , mute_solo_table (1, 2)
132         , bottom_button_table (1, 3)
133         , monitor_section_button (0)
134         , midi_input_enable_button (0)
135         , _plugin_insert_cnt (0)
136         , _comment_button (_("Comments"))
137         , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
138         , _visibility (X_("mixer-element-visibility"))
139         , control_slave_ui (sess)
140 {
141         init ();
142         set_route (rt);
143 }
144
145 void
146 MixerStrip::init ()
147 {
148         _entered_mixer_strip= 0;
149         group_menu = 0;
150         route_ops_menu = 0;
151         ignore_comment_edit = false;
152         ignore_toggle = false;
153         comment_area = 0;
154         _width_owner = 0;
155
156         /* the length of this string determines the width of the mixer strip when it is set to `wide' */
157         longest_label = "longest label";
158
159         string t = _("Click to toggle the width of this mixer strip.");
160         if (_mixer_owned) {
161                 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
162         }
163
164         width_button.set_icon (ArdourIcon::StripWidth);
165         hide_button.set_tweaks (ArdourButton::Square);
166         set_tooltip (width_button, t);
167
168         hide_button.set_icon (ArdourIcon::CloseCross);
169         hide_button.set_tweaks (ArdourButton::Square);
170         set_tooltip (&hide_button, _("Hide this mixer strip"));
171
172         input_button_box.set_spacing(2);
173
174         input_button.set_text (_("Input"));
175         input_button.set_name ("mixer strip button");
176         input_button_box.pack_start (input_button, true, true);
177
178         output_button.set_text (_("Output"));
179         output_button.set_name ("mixer strip button");
180
181         bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
182
183         hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
184
185         solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
186         solo_isolated_led->show ();
187         solo_isolated_led->set_no_show_all (true);
188         solo_isolated_led->set_name (X_("solo isolate"));
189         solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
190         solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
191         UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
192
193         solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
194         solo_safe_led->show ();
195         solo_safe_led->set_no_show_all (true);
196         solo_safe_led->set_name (X_("solo safe"));
197         solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
198         solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
199         UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
200
201         solo_safe_led->set_text (S_("SoloLock|Lock"));
202         solo_isolated_led->set_text (_("Iso"));
203
204         solo_iso_table.set_homogeneous (true);
205         solo_iso_table.set_spacings (2);
206         if (!ARDOUR::Profile->get_trx()) {
207                 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
208                 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
209         }
210         solo_iso_table.show ();
211
212         rec_mon_table.set_homogeneous (true);
213         rec_mon_table.set_row_spacings (2);
214         rec_mon_table.set_col_spacings (2);
215         if (ARDOUR::Profile->get_mixbus()) {
216                 rec_mon_table.resize (1, 3);
217                 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
218                 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
219         } else if (!ARDOUR::Profile->get_trx()) {
220                 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
221                 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
222         }
223         rec_mon_table.show ();
224
225         if (solo_isolated_led) {
226                 button_size_group->add_widget (*solo_isolated_led);
227         }
228         if (solo_safe_led) {
229                 button_size_group->add_widget (*solo_safe_led);
230         }
231
232         if (!ARDOUR::Profile->get_mixbus()) {
233                 if (rec_enable_button) {
234                         button_size_group->add_widget (*rec_enable_button);
235                 }
236                 if (monitor_disk_button) {
237                         button_size_group->add_widget (*monitor_disk_button);
238                 }
239                 if (monitor_input_button) {
240                         button_size_group->add_widget (*monitor_input_button);
241                 }
242         }
243
244         mute_solo_table.set_homogeneous (true);
245         mute_solo_table.set_spacings (2);
246
247         bottom_button_table.set_spacings (2);
248         bottom_button_table.set_homogeneous (true);
249         bottom_button_table.attach (group_button, 1, 2, 0, 1);
250         bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
251
252         name_button.set_name ("mixer strip button");
253         name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
254         name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
255
256         set_tooltip (&group_button, _("Mix group"));
257         group_button.set_name ("mixer strip button");
258
259         _comment_button.set_name (X_("mixer strip button"));
260         _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261         _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
262         _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
263
264         // TODO implement ArdourKnob::on_size_request properly
265 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
266         trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
267 #undef PX_SCALE
268         trim_control.set_tooltip_prefix (_("Trim: "));
269         trim_control.set_name ("trim knob");
270         trim_control.set_no_show_all (true);
271         input_button_box.pack_start (trim_control, false, false);
272
273         global_vpacker.set_border_width (1);
274         global_vpacker.set_spacing (0);
275
276         width_button.set_name ("mixer strip button");
277         hide_button.set_name ("mixer strip button");
278
279         width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
280         hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
281
282         width_hide_box.set_spacing (2);
283         width_hide_box.pack_start (width_button, false, true);
284         width_hide_box.pack_start (number_label, true, true);
285         width_hide_box.pack_end (hide_button, false, true);
286
287         number_label.set_text ("-");
288         number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
289         number_label.set_no_show_all ();
290         number_label.set_name ("tracknumber label");
291         number_label.set_fixed_colors (0x80808080, 0x80808080);
292         number_label.set_alignment (.5, .5);
293         number_label.set_fallthrough_to_parent (true);
294         number_label.set_tweaks (ArdourButton::OccasionalText);
295
296         global_vpacker.set_spacing (2);
297         if (!ARDOUR::Profile->get_trx()) {
298                 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
299                 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
300                 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
301                 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
302                 global_vpacker.pack_start (processor_box, true, true);
303         }
304         global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
305         global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
306         global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
307         global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
308         global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
309         global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
310         global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
311         if (!ARDOUR::Profile->get_trx()) {
312                 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
313                 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
314         } else {
315                 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
316         }
317
318 #ifndef MIXBUS
319         //add a spacer underneath the master bus;
320         //this fills the area that is taken up by the scrollbar on the tracks;
321         //and therefore keeps the faders "even" across the bottom
322         int scrollbar_height = 0;
323         {
324                 Gtk::Window window (WINDOW_TOPLEVEL);
325                 HScrollbar scrollbar;
326                 window.add (scrollbar);
327                 scrollbar.set_name ("MixerWindow");
328                 scrollbar.ensure_style();
329                 Gtk::Requisition requisition(scrollbar.size_request ());
330                 scrollbar_height = requisition.height;
331         }
332         spacer.set_size_request (-1, scrollbar_height);
333         global_vpacker.pack_end (spacer, false, false);
334 #endif
335
336         global_frame.add (global_vpacker);
337         global_frame.set_shadow_type (Gtk::SHADOW_IN);
338         global_frame.set_name ("BaseFrame");
339
340         add (global_frame);
341
342         /* force setting of visible selected status */
343
344         _selected = true;
345         set_selected (false);
346
347         _packed = false;
348         _embedded = false;
349
350         _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
351         _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
352
353         input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
354         input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
355         input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
356
357         input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
358         output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
359
360         output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
361         output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
362         output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
363
364         number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
365
366         name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
367
368         group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
369
370         _width = (Width) -1;
371
372         /* start off as a passthru strip. we'll correct this, if necessary,
373            in update_diskstream_display().
374         */
375
376         /* start off as a passthru strip. we'll correct this, if necessary,
377            in update_diskstream_display().
378         */
379
380         if (is_midi_track()) {
381                 set_name ("MidiTrackStripBase");
382         } else {
383                 set_name ("AudioTrackStripBase");
384         }
385
386         add_events (Gdk::BUTTON_RELEASE_MASK|
387                     Gdk::ENTER_NOTIFY_MASK|
388                     Gdk::LEAVE_NOTIFY_MASK|
389                     Gdk::KEY_PRESS_MASK|
390                     Gdk::KEY_RELEASE_MASK);
391
392         set_flags (get_flags() | Gtk::CAN_FOCUS);
393
394         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
395                 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
396                 );
397
398         /* Add the widgets under visibility control to the VisibilityGroup; the names used here
399            must be the same as those used in RCOptionEditor so that the configuration changes
400            are recognised when they occur.
401         */
402         _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
403         _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
404         _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
405         _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
406         _visibility.add (&output_button, X_("Output"), _("Output"), false);
407         _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
408         _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
409
410         parameter_changed (X_("mixer-element-visibility"));
411         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
412         Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
413         _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
414
415         //watch for mouse enter/exit so we can do some stuff
416         signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
417         signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
418
419         gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
420 }
421
422 MixerStrip::~MixerStrip ()
423 {
424         CatchDeletion (this);
425
426         if (this ==_entered_mixer_strip)
427                 _entered_mixer_strip = NULL;
428 }
429
430 void
431 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
432 {
433         boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
434         if (sl)
435                 sl->assign(vca);
436 }
437
438 void
439 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
440 {
441         boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
442         if (sl)
443                 sl->unassign(vca);
444 }
445
446 bool
447 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
448 {
449         _entered_mixer_strip = this;
450
451         //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
452         //because the mixerstrip control is a parent that encompasses the strip
453         deselect_all_processors();
454
455         return false;
456 }
457
458 bool
459 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
460 {
461         //if we have moved outside our strip, but not into a child view, then deselect ourselves
462         if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
463                 _entered_mixer_strip= 0;
464
465                 //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
466                 gpm.gain_display.set_sensitive(false);
467                 gpm.show_gain();
468                 gpm.gain_display.set_sensitive(true);
469
470                 //if we leave this mixer strip we need to clear out any selections
471                 //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
472         }
473
474         return false;
475 }
476
477 string
478 MixerStrip::name() const
479 {
480         if (_route) {
481                 return _route->name();
482         }
483         return string();
484 }
485
486 void
487 MixerStrip::update_trim_control ()
488 {
489         if (route()->trim() && route()->trim()->active() &&
490             route()->n_inputs().n_audio() > 0) {
491                 trim_control.show ();
492                 trim_control.set_controllable (route()->trim()->gain_control());
493         } else {
494                 trim_control.hide ();
495                 boost::shared_ptr<Controllable> none;
496                 trim_control.set_controllable (none);
497         }
498 }
499
500 void
501 MixerStrip::set_route (boost::shared_ptr<Route> rt)
502 {
503         //the rec/monitor stuff only shows up for tracks.
504         //the show_sends only shows up for buses.
505         //remove them all here, and we may add them back later
506         if (show_sends_button->get_parent()) {
507                 rec_mon_table.remove (*show_sends_button);
508         }
509         if (rec_enable_button->get_parent()) {
510                 rec_mon_table.remove (*rec_enable_button);
511         }
512         if (monitor_input_button->get_parent()) {
513                 rec_mon_table.remove (*monitor_input_button);
514         }
515         if (monitor_disk_button->get_parent()) {
516                 rec_mon_table.remove (*monitor_disk_button);
517         }
518         if (group_button.get_parent()) {
519                 bottom_button_table.remove (group_button);
520         }
521
522         RouteUI::set_route (rt);
523
524         control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
525
526         /* ProcessorBox needs access to _route so that it can read
527            GUI object state.
528         */
529         processor_box.set_route (rt);
530
531         revert_to_default_display ();
532
533         /* unpack these from the parent and stuff them into our own
534            table
535         */
536
537         if (gpm.peak_display.get_parent()) {
538                 gpm.peak_display.get_parent()->remove (gpm.peak_display);
539         }
540         if (gpm.gain_display.get_parent()) {
541                 gpm.gain_display.get_parent()->remove (gpm.gain_display);
542         }
543
544         gpm.set_type (rt->meter_type());
545
546         mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
547         mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
548
549         if (solo_button->get_parent()) {
550                 mute_solo_table.remove (*solo_button);
551         }
552
553         if (mute_button->get_parent()) {
554                 mute_solo_table.remove (*mute_button);
555         }
556
557         if (route()->is_master()) {
558                 solo_button->hide ();
559                 mute_button->show ();
560                 rec_mon_table.hide ();
561                 solo_iso_table.set_sensitive(false);
562                 control_slave_ui.set_sensitive(false);
563                 if (monitor_section_button == 0) {
564                         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
565                         _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
566
567                         monitor_section_button = manage (new ArdourButton);
568                         monitor_changed ();
569                         monitor_section_button->set_related_action (act);
570                         set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
571                         mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
572                         monitor_section_button->show();
573                         monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
574                 }
575                 parameter_changed ("use-monitor-bus");
576         } else {
577                 bottom_button_table.attach (group_button, 1, 2, 0, 1);
578                 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
579                 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
580                 mute_button->show ();
581                 solo_button->show ();
582                 rec_mon_table.show ();
583                 solo_iso_table.set_sensitive(true);
584                 control_slave_ui.set_sensitive(true);
585         }
586
587         if (_mixer_owned && route()->is_master() ) {
588                 spacer.show();
589         } else {
590                 spacer.hide();
591         }
592
593         if (is_track()) {
594                 monitor_input_button->show ();
595                 monitor_disk_button->show ();
596         } else {
597                 monitor_input_button->hide();
598                 monitor_disk_button->hide ();
599         }
600
601         update_trim_control();
602
603         if (is_midi_track()) {
604                 if (midi_input_enable_button == 0) {
605                         midi_input_enable_button = manage (new ArdourButton);
606                         midi_input_enable_button->set_name ("midi input button");
607                         midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
608                         midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
609                         midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
610                         midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
611                         set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
612                 } else {
613                         input_button_box.remove (*midi_input_enable_button);
614                 }
615                 /* get current state */
616                 midi_input_status_changed ();
617                 input_button_box.pack_start (*midi_input_enable_button, false, false);
618                 /* follow changes */
619                 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
620         } else {
621                 if (midi_input_enable_button) {
622                         /* removal from the container will delete it */
623                         input_button_box.remove (*midi_input_enable_button);
624                         midi_input_enable_button = 0;
625                 }
626         }
627
628         if (is_audio_track()) {
629                 boost::shared_ptr<AudioTrack> at = audio_track();
630                 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
631         }
632
633         if (is_track ()) {
634
635                 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
636                 rec_enable_button->show();
637
638                 if (ARDOUR::Profile->get_mixbus()) {
639                         rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
640                         rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
641                 } else if (ARDOUR::Profile->get_trx()) {
642                         rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
643                 } else {
644                         rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
645                         rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
646                 }
647
648         } else {
649
650                 /* non-master bus */
651
652                 if (!_route->is_master()) {
653                         rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
654                         show_sends_button->show();
655                 }
656         }
657
658         gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
659
660         delete route_ops_menu;
661         route_ops_menu = 0;
662
663         _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
664         _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
665         _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
666         _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
667
668         _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
669
670         if (_route->panner_shell()) {
671                 update_panner_choices();
672                 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
673         }
674
675         if (is_audio_track()) {
676                 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
677         }
678
679         _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
680
681         set_stuff_from_route ();
682
683         /* now force an update of all the various elements */
684
685         update_mute_display ();
686         update_solo_display ();
687         name_changed ();
688         comment_changed ();
689         route_group_changed ();
690         update_track_number_visibility ();
691
692         connect_to_pan ();
693         panners.setup_pan ();
694
695         if (has_audio_outputs ()) {
696                 panners.show_all ();
697         } else {
698                 panners.hide_all ();
699         }
700
701         update_diskstream_display ();
702         update_input_display ();
703         update_output_display ();
704
705         add_events (Gdk::BUTTON_RELEASE_MASK);
706
707         processor_box.show ();
708
709         if (!route()->is_master() && !route()->is_monitor()) {
710                 /* we don't allow master or control routes to be hidden */
711                 hide_button.show();
712                 number_label.show();
713         }
714
715         gpm.reset_peak_display ();
716         gpm.gain_display.show ();
717         gpm.peak_display.show ();
718
719         width_button.show();
720         width_hide_box.show();
721         global_frame.show();
722         global_vpacker.show();
723         mute_solo_table.show();
724         bottom_button_table.show();
725         gpm.show_all ();
726         gpm.meter_point_button.show();
727         input_button_box.show_all();
728         output_button.show();
729         name_button.show();
730         _comment_button.show();
731         group_button.show();
732         gpm.gain_automation_state_button.show();
733
734         parameter_changed ("mixer-element-visibility");
735         map_frozen();
736
737         show ();
738 }
739
740 void
741 MixerStrip::set_stuff_from_route ()
742 {
743         /* if width is not set, it will be set by the MixerUI or editor */
744
745         Width width;
746         if (get_gui_property ("strip-width", width)) {
747                 set_width_enum (width, this);
748         }
749 }
750
751 void
752 MixerStrip::set_width_enum (Width w, void* owner)
753 {
754         /* always set the gpm width again, things may be hidden */
755
756         gpm.set_width (w);
757         panners.set_width (w);
758
759         boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
760
761         _width_owner = owner;
762
763         _width = w;
764
765         if (_width_owner == this) {
766                 set_gui_property ("strip-width", _width);
767         }
768
769         set_button_names ();
770
771         const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
772
773         switch (w) {
774         case Wide:
775
776                 if (show_sends_button)  {
777                         show_sends_button->set_text (_("Aux"));
778                 }
779
780                 gpm.gain_automation_state_button.set_text (
781                                 gpm.astate_string(gain_automation->automation_state()));
782
783                 if (_route->panner()) {
784                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
785                                         panners.astate_string(_route->panner()->automation_state()));
786                 }
787
788                 {
789                         // panners expect an even number of horiz. pixels
790                         int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
791                         width &= ~1;
792                         set_size_request (width, -1);
793                 }
794                 break;
795
796         case Narrow:
797
798                 if (show_sends_button) {
799                         show_sends_button->set_text (_("Snd"));
800                 }
801
802                 gpm.gain_automation_state_button.set_text (
803                                 gpm.short_astate_string(gain_automation->automation_state()));
804                 gain_meter().setup_meters (); // recalc meter width
805
806                 if (_route->panner()) {
807                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
808                         panners.short_astate_string(_route->panner()->automation_state()));
809                 }
810
811                 {
812                         // panners expect an even number of horiz. pixels
813                         int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
814                         width &= ~1;
815                         set_size_request (width, -1);
816                 }
817                 break;
818         }
819
820         processor_box.set_width (w);
821
822         update_input_display ();
823         update_output_display ();
824         setup_comment_button ();
825         route_group_changed ();
826         name_changed ();
827         WidthChanged ();
828 }
829
830 void
831 MixerStrip::set_packed (bool yn)
832 {
833         _packed = yn;
834         set_gui_property ("visible", _packed);
835 }
836
837
838 struct RouteCompareByName {
839         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
840                 return a->name().compare (b->name()) < 0;
841         }
842 };
843
844 gint
845 MixerStrip::output_release (GdkEventButton *ev)
846 {
847         switch (ev->button) {
848         case 3:
849                 edit_output_configuration ();
850                 break;
851         }
852
853         return false;
854 }
855
856 gint
857 MixerStrip::output_press (GdkEventButton *ev)
858 {
859         using namespace Menu_Helpers;
860         if (!_session->engine().connected()) {
861                 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
862                 msg.run ();
863                 return true;
864         }
865
866         MenuList& citems = output_menu.items();
867         switch (ev->button) {
868
869         case 3:
870                 return false;  //wait for the mouse-up to pop the dialog
871
872         case 1:
873         {
874                 output_menu.set_name ("ArdourContextMenu");
875                 citems.clear ();
876                 output_menu_bundles.clear ();
877
878                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
879
880                 citems.push_back (SeparatorElem());
881                 uint32_t const n_with_separator = citems.size ();
882
883                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
884
885                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
886
887                 /* give user bundles first chance at being in the menu */
888
889                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
890                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
891                                 maybe_add_bundle_to_output_menu (*i, current);
892                         }
893                 }
894
895                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
896                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
897                                 maybe_add_bundle_to_output_menu (*i, current);
898                         }
899                 }
900
901                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
902                 RouteList copy = *routes;
903                 copy.sort (RouteCompareByName ());
904                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
905                         maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
906                 }
907
908                 if (citems.size() == n_with_separator) {
909                         /* no routes added; remove the separator */
910                         citems.pop_back ();
911                 }
912
913                 if (!ARDOUR::Profile->get_mixbus()) {
914                         citems.push_back (SeparatorElem());
915
916                         for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
917                                 citems.push_back (
918                                                 MenuElem (
919                                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
920                                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
921                                                         )
922                                                 );
923                         }
924                 }
925
926                 citems.push_back (SeparatorElem());
927                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
928
929                 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
930                                                1, ev->time);
931
932                 break;
933         }
934
935         default:
936                 break;
937         }
938         return TRUE;
939 }
940
941 gint
942 MixerStrip::input_release (GdkEventButton *ev)
943 {
944         switch (ev->button) {
945
946         case 3:
947                 edit_input_configuration ();
948                 break;
949         default:
950                 break;
951
952         }
953
954         return false;
955 }
956
957
958 gint
959 MixerStrip::input_press (GdkEventButton *ev)
960 {
961         using namespace Menu_Helpers;
962
963         MenuList& citems = input_menu.items();
964         input_menu.set_name ("ArdourContextMenu");
965         citems.clear();
966
967         if (!_session->engine().connected()) {
968                 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
969                 msg.run ();
970                 return true;
971         }
972
973         if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
974                 return true;
975
976         switch (ev->button) {
977
978         case 3:
979                 return false;  //don't handle the mouse-down here.  wait for mouse-up to pop the menu
980
981         case 1:
982         {
983                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
984
985                 citems.push_back (SeparatorElem());
986                 uint32_t const n_with_separator = citems.size ();
987
988                 input_menu_bundles.clear ();
989
990                 ARDOUR::BundleList current = _route->input()->bundles_connected ();
991
992                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
993
994                 /* give user bundles first chance at being in the menu */
995
996                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
997                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
998                                 maybe_add_bundle_to_input_menu (*i, current);
999                         }
1000                 }
1001
1002                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1003                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1004                                 maybe_add_bundle_to_input_menu (*i, current);
1005                         }
1006                 }
1007
1008                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1009                 RouteList copy = *routes;
1010                 copy.sort (RouteCompareByName ());
1011                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1012                         maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1013                 }
1014
1015                 if (citems.size() == n_with_separator) {
1016                         /* no routes added; remove the separator */
1017                         citems.pop_back ();
1018                 }
1019
1020                 citems.push_back (SeparatorElem());
1021                 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1022                         citems.push_back (
1023                                 MenuElem (
1024                                         string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1025                                         sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1026                                         )
1027                                 );
1028                 }
1029
1030                 citems.push_back (SeparatorElem());
1031                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1032
1033                 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1034                                                1, ev->time);
1035
1036                 break;
1037         }
1038         default:
1039                 break;
1040         }
1041         return TRUE;
1042 }
1043
1044 void
1045 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1046 {
1047         if (ignore_toggle) {
1048                 return;
1049         }
1050
1051         ARDOUR::BundleList current = _route->input()->bundles_connected ();
1052
1053         if (std::find (current.begin(), current.end(), c) == current.end()) {
1054                 _route->input()->connect_ports_to_bundle (c, true, this);
1055         } else {
1056                 _route->input()->disconnect_ports_from_bundle (c, this);
1057         }
1058 }
1059
1060 void
1061 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1062 {
1063         if (ignore_toggle) {
1064                 return;
1065         }
1066
1067         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1068
1069         if (std::find (current.begin(), current.end(), c) == current.end()) {
1070                 _route->output()->connect_ports_to_bundle (c, true, this);
1071         } else {
1072                 _route->output()->disconnect_ports_from_bundle (c, this);
1073         }
1074 }
1075
1076 void
1077 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1078 {
1079         using namespace Menu_Helpers;
1080
1081         if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1082                 return;
1083         }
1084
1085         list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1086         while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1087                 ++i;
1088         }
1089
1090         if (i != input_menu_bundles.end()) {
1091                 return;
1092         }
1093
1094         input_menu_bundles.push_back (b);
1095
1096         MenuList& citems = input_menu.items();
1097         citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1098 }
1099
1100 void
1101 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1102 {
1103         using namespace Menu_Helpers;
1104
1105         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1106                 return;
1107         }
1108
1109         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1110         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1111                 ++i;
1112         }
1113
1114         if (i != output_menu_bundles.end()) {
1115                 return;
1116         }
1117
1118         output_menu_bundles.push_back (b);
1119
1120         MenuList& citems = output_menu.items();
1121         citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1122 }
1123
1124 void
1125 MixerStrip::update_diskstream_display ()
1126 {
1127         if (is_track() && input_selector) {
1128                 input_selector->hide_all ();
1129         }
1130
1131         route_color_changed ();
1132 }
1133
1134 void
1135 MixerStrip::connect_to_pan ()
1136 {
1137         ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1138
1139         panstate_connection.disconnect ();
1140         panstyle_connection.disconnect ();
1141
1142         if (!_route->panner()) {
1143                 return;
1144         }
1145
1146         boost::shared_ptr<Pannable> p = _route->pannable ();
1147
1148         p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1149
1150         /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1151          * However, that only works a panner was previously set.
1152          *
1153          * PannerUI must remain subscribed to _panshell->Changed() in case
1154          * we switch the panner eg. AUX-Send and back
1155          * _route->panner_shell()->Changed() vs _panshell->Changed
1156          */
1157         if (panners._panner == 0) {
1158                 panners.panshell_changed ();
1159         }
1160         update_panner_choices();
1161 }
1162
1163 void
1164 MixerStrip::update_panner_choices ()
1165 {
1166         ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1167         if (!_route->panner_shell()) { return; }
1168
1169         uint32_t in = _route->output()->n_ports().n_audio();
1170         uint32_t out = in;
1171         if (_route->panner()) {
1172                 in = _route->panner()->in().n_audio();
1173         }
1174
1175         panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1176 }
1177
1178 /*
1179  * Output port labelling
1180  * =====================
1181  *
1182  * Case 1: Each output has one connection, all connections are to system:playback_%i
1183  *   out 1 -> system:playback_1
1184  *   out 2 -> system:playback_2
1185  *   out 3 -> system:playback_3
1186  *   Display as: 1/2/3
1187  *
1188  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1189  *   out 1 -> ardour:track_x/in 1
1190  *   out 2 -> ardour:track_x/in 2
1191  *   Display as: track_x
1192  *
1193  * Case 3: Each output has one connection, all connections are to Jack client "program x"
1194  *   out 1 -> program x:foo
1195  *   out 2 -> program x:foo
1196  *   Display as: program x
1197  *
1198  * Case 4: No connections (Disconnected)
1199  *   Display as: -
1200  *
1201  * Default case (unusual routing):
1202  *   Display as: *number of connections*
1203  *
1204  * Tooltips
1205  * ========
1206  * .-----------------------------------------------.
1207  * | Mixdown                                       |
1208  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1209  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1210  * '-----------------------------------------------'
1211  * .-----------------------------------------------.
1212  * | Guitar SM58                                   |
1213  * | Disconnected                                  |
1214  * '-----------------------------------------------'
1215  */
1216
1217 void
1218 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1219 {
1220         uint32_t io_count;
1221         uint32_t io_index;
1222         boost::shared_ptr<IO> io;
1223         boost::shared_ptr<Port> port;
1224         vector<string> port_connections;
1225
1226         uint32_t total_connection_count = 0;
1227         uint32_t io_connection_count = 0;
1228         uint32_t ardour_connection_count = 0;
1229         uint32_t system_connection_count = 0;
1230         uint32_t other_connection_count = 0;
1231         uint32_t typed_connection_count = 0;
1232
1233         ostringstream label;
1234
1235         bool have_label = false;
1236         bool each_io_has_one_connection = true;
1237
1238         string connection_name;
1239         string ardour_track_name;
1240         string other_connection_type;
1241         string system_ports;
1242         string system_port;
1243
1244         ostringstream tooltip;
1245         char * tooltip_cstr;
1246
1247         /* To avoid confusion, the button caption only shows connections that match the expected datatype
1248          *
1249          * First of all, if the user made only connections to a given type, we should use that one since
1250          * it is very probably what the user expects. If there are several connections types, then show
1251          * audio ones as primary, which matches expectations for both audio tracks with midi control and
1252          * synthesisers. This first heuristic can be expressed with these two rules:
1253          * A) If there are connected audio ports, consider audio as primary type.
1254          * B) Else, if there are connected midi ports, consider midi as primary type.
1255          *
1256          * If there are no connected ports, then we choose the primary type based on the type of existing
1257          * but unconnected ports. Again:
1258          * C) If there are audio ports, consider audio as primary type.
1259          * D) Else, if there are midi ports, consider midi as primary type. */
1260
1261         DataType dt = DataType::AUDIO;
1262         bool match = false;
1263
1264         if (for_input) {
1265                 io = route->input();
1266         } else {
1267                 io = route->output();
1268         }
1269
1270         io_count = io->n_ports().n_total();
1271         for (io_index = 0; io_index < io_count; ++io_index) {
1272                 port = io->nth (io_index);
1273                 if (port->connected()) {
1274                         match = true;
1275                         if (port->type() == DataType::AUDIO) {
1276                                 /* Rule A) applies no matter the remaining ports */
1277                                 dt = DataType::AUDIO;
1278                                 break;
1279                         }
1280                         if (port->type() == DataType::MIDI) {
1281                                 /* Rule B) is a good candidate... */
1282                                 dt = DataType::MIDI;
1283                                 /* ...but continue the loop to check remaining ports for rule A) */
1284                         }
1285                 }
1286         }
1287
1288         if (!match) {
1289                 /* Neither rule A) nor rule B) matched */
1290                 if ( io->n_ports().n_audio() > 0 ) {
1291                         /* Rule C */
1292                         dt = DataType::AUDIO;
1293                 } else if ( io->n_ports().n_midi() > 0 ) {
1294                         /* Rule D */
1295                         dt = DataType::MIDI;
1296                 }
1297         }
1298
1299         if ( dt == DataType::MIDI ) {
1300                 tooltip << _("MIDI ");
1301         }
1302
1303         if (for_input) {
1304                 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1305         } else {
1306                 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1307         }
1308
1309         for (io_index = 0; io_index < io_count; ++io_index) {
1310                 port = io->nth (io_index);
1311
1312                 port_connections.clear ();
1313                 port->get_connections(port_connections);
1314
1315                 //ignore any port connections that don't match our DataType
1316                 if (port->type() != dt) {
1317                         if (!port_connections.empty()) {
1318                                 ++typed_connection_count;
1319                         }
1320                         continue;
1321                 }
1322
1323                 io_connection_count = 0;
1324
1325                 if (!port_connections.empty()) {
1326                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1327                                 string pn = "";
1328                                 string& connection_name (*i);
1329
1330                                 if (connection_name.find("system:") == 0) {
1331                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1332                                 }
1333
1334                                 if (io_connection_count == 0) {
1335                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1336                                                 << " -> "
1337                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1338                                 } else {
1339                                         tooltip << ", "
1340                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1341                                 }
1342
1343                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1344                                         if (ardour_track_name.empty()) {
1345                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1346                                                 string::size_type slash = connection_name.find("/");
1347                                                 if (slash != string::npos) {
1348                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1349                                                 }
1350                                         }
1351
1352                                         if (connection_name.find(ardour_track_name) == 0) {
1353                                                 ++ardour_connection_count;
1354                                         }
1355                                 } else if (!pn.empty()) {
1356                                         if (system_ports.empty()) {
1357                                                 system_ports += pn;
1358                                         } else {
1359                                                 system_ports += "/" + pn;
1360                                         }
1361                                         if (connection_name.find("system:") == 0) {
1362                                                 ++system_connection_count;
1363                                         }
1364                                 } else if (connection_name.find("system:midi_") == 0) {
1365                                         if (for_input) {
1366                                                 // "system:midi_capture_123" -> "123"
1367                                                 system_port = "M " + connection_name.substr(20);
1368                                         } else {
1369                                                 // "system:midi_playback_123" -> "123"
1370                                                 system_port = "M " + connection_name.substr(21);
1371                                         }
1372
1373                                         if (system_ports.empty()) {
1374                                                 system_ports += system_port;
1375                                         } else {
1376                                                 system_ports += "/" + system_port;
1377                                         }
1378
1379                                         ++system_connection_count;
1380
1381                                 } else if (connection_name.find("system:") == 0) {
1382                                         if (for_input) {
1383                                                 // "system:capture_123" -> "123"
1384                                                 system_port = connection_name.substr(15);
1385                                         } else {
1386                                                 // "system:playback_123" -> "123"
1387                                                 system_port = connection_name.substr(16);
1388                                         }
1389
1390                                         if (system_ports.empty()) {
1391                                                 system_ports += system_port;
1392                                         } else {
1393                                                 system_ports += "/" + system_port;
1394                                         }
1395
1396                                         ++system_connection_count;
1397                                 } else {
1398                                         if (other_connection_type.empty()) {
1399                                                 // "jamin:in 1" -> "jamin:"
1400                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1401                                         }
1402
1403                                         if (connection_name.find(other_connection_type) == 0) {
1404                                                 ++other_connection_count;
1405                                         }
1406                                 }
1407
1408                                 ++total_connection_count;
1409                                 ++io_connection_count;
1410                         }
1411                 }
1412
1413                 if (io_connection_count != 1) {
1414                         each_io_has_one_connection = false;
1415                 }
1416         }
1417
1418         if (total_connection_count == 0) {
1419                 tooltip << endl << _("Disconnected");
1420         }
1421
1422         tooltip_cstr = new char[tooltip.str().size() + 1];
1423         strcpy(tooltip_cstr, tooltip.str().c_str());
1424
1425         if (for_input) {
1426                 set_tooltip (&input_button, tooltip_cstr);
1427         } else {
1428                 set_tooltip (&output_button, tooltip_cstr);
1429         }
1430
1431         delete [] tooltip_cstr;
1432
1433         if (each_io_has_one_connection) {
1434                 if (total_connection_count == ardour_connection_count) {
1435                         // all connections are to the same track in ardour
1436                         // "ardour:Master/" -> "Master"
1437                         string::size_type slash = ardour_track_name.find("/");
1438                         if (slash != string::npos) {
1439                                 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1440                                 label << ardour_track_name.substr (ppps, slash - ppps);
1441                                 have_label = true;
1442                         }
1443                 }
1444                 else if (total_connection_count == system_connection_count) {
1445                         // all connections are to system ports
1446                         label << system_ports;
1447                         have_label = true;
1448                 }
1449                 else if (total_connection_count == other_connection_count) {
1450                         // all connections are to the same external program eg jamin
1451                         // "jamin:" -> "jamin"
1452                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1453                         have_label = true;
1454                 }
1455         }
1456
1457         if (!have_label) {
1458                 if (total_connection_count == 0) {
1459                         // Disconnected
1460                         label << "-";
1461                 } else {
1462                         // Odd configuration
1463                         label << "*" << total_connection_count << "*";
1464                 }
1465                 if (typed_connection_count > 0) {
1466                         label << "\u2295"; // circled plus
1467                 }
1468         }
1469
1470         if (for_input) {
1471                 input_button.set_text (label.str());
1472         } else {
1473                 output_button.set_text (label.str());
1474         }
1475 }
1476
1477 void
1478 MixerStrip::update_input_display ()
1479 {
1480         update_io_button (_route, _width, true);
1481         panners.setup_pan ();
1482
1483         if (has_audio_outputs ()) {
1484                 panners.show_all ();
1485         } else {
1486                 panners.hide_all ();
1487         }
1488
1489 }
1490
1491 void
1492 MixerStrip::update_output_display ()
1493 {
1494         update_io_button (_route, _width, false);
1495         gpm.setup_meters ();
1496         panners.setup_pan ();
1497
1498         if (has_audio_outputs ()) {
1499                 panners.show_all ();
1500         } else {
1501                 panners.hide_all ();
1502         }
1503 }
1504
1505 void
1506 MixerStrip::fast_update ()
1507 {
1508         gpm.update_meters ();
1509 }
1510
1511 void
1512 MixerStrip::diskstream_changed ()
1513 {
1514         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1515 }
1516
1517 void
1518 MixerStrip::io_changed_proxy ()
1519 {
1520         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1521         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1522 }
1523
1524 void
1525 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1526 {
1527         boost::shared_ptr<Port> a = wa.lock ();
1528         boost::shared_ptr<Port> b = wb.lock ();
1529
1530         if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1531                 update_input_display ();
1532                 set_width_enum (_width, this);
1533         }
1534
1535         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1536                 update_output_display ();
1537                 set_width_enum (_width, this);
1538         }
1539 }
1540
1541 void
1542 MixerStrip::setup_comment_button ()
1543 {
1544         std::string comment = _route->comment();
1545
1546         set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1547
1548         if (comment.empty ()) {
1549                 _comment_button.set_name ("generic button");
1550                 _comment_button.set_text (_width  == Wide ? _("Comments") : _("Cmt"));
1551                 return;
1552         }
1553
1554         _comment_button.set_name ("comment button");
1555
1556         string::size_type pos = comment.find_first_of (" \t\n");
1557         if (pos != string::npos) {
1558                 comment = comment.substr (0, pos);
1559         }
1560         if (comment.empty()) {
1561                 _comment_button.set_text (_width  == Wide ? _("Comments") : _("Cmt"));
1562         } else {
1563                 _comment_button.set_text (comment);
1564         }
1565 }
1566
1567 bool
1568 MixerStrip::select_route_group (GdkEventButton *ev)
1569 {
1570         using namespace Menu_Helpers;
1571
1572         if (ev->button == 1) {
1573
1574                 if (group_menu == 0) {
1575
1576                         PropertyList* plist = new PropertyList();
1577
1578                         plist->add (Properties::group_gain, true);
1579                         plist->add (Properties::group_mute, true);
1580                         plist->add (Properties::group_solo, true);
1581
1582                         group_menu = new RouteGroupMenu (_session, plist);
1583                 }
1584
1585                 WeakRouteList r;
1586                 r.push_back (route ());
1587                 group_menu->build (r);
1588
1589                 RouteGroup *rg = _route->route_group();
1590
1591                 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1592                                                rg ? rg->name() : _("No Group"),
1593                                                1, ev->time);
1594         }
1595
1596         return true;
1597 }
1598
1599 void
1600 MixerStrip::route_group_changed ()
1601 {
1602         ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1603
1604         RouteGroup *rg = _route->route_group();
1605
1606         if (rg) {
1607                 group_button.set_text (PBD::short_version (rg->name(), 5));
1608         } else {
1609                 switch (_width) {
1610                 case Wide:
1611                         group_button.set_text (_("Grp"));
1612                         break;
1613                 case Narrow:
1614                         group_button.set_text (_("~G"));
1615                         break;
1616                 }
1617         }
1618 }
1619
1620 void
1621 MixerStrip::route_color_changed ()
1622 {
1623         using namespace ARDOUR_UI_UTILS;
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 }