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