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