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