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