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