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