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