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