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