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