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