fix clicking when processors become active/inactive; reduce crazy 2.5sec delay for...
[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 <algorithm>
21
22 #include <sigc++/bind.h>
23
24 #include "pbd/convert.h"
25 #include "pbd/enumwriter.h"
26 #include "pbd/replace_all.h"
27
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
30 #include <gtkmm2ext/choice.h>
31 #include <gtkmm2ext/stop_signal.h>
32 #include <gtkmm2ext/doi.h>
33 #include <gtkmm2ext/slider_controller.h>
34 #include <gtkmm2ext/bindable_button.h>
35
36 #include "ardour/ardour.h"
37 #include "ardour/amp.h"
38 #include "ardour/session.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/route.h"
41 #include "ardour/route_group.h"
42 #include "ardour/audio_track.h"
43 #include "ardour/audio_diskstream.h"
44 #include "ardour/panner.h"
45 #include "ardour/send.h"
46 #include "ardour/processor.h"
47 #include "ardour/profile.h"
48 #include "ardour/ladspa_plugin.h"
49 #include "ardour/user_bundle.h"
50
51 #include "ardour_ui.h"
52 #include "ardour_dialog.h"
53 #include "mixer_strip.h"
54 #include "mixer_ui.h"
55 #include "keyboard.h"
56 #include "public_editor.h"
57 #include "send_ui.h"
58 #include "io_selector.h"
59 #include "utils.h"
60 #include "gui_thread.h"
61 #include "route_group_menu.h"
62
63 #include "i18n.h"
64
65 using namespace sigc;
66 using namespace ARDOUR;
67 using namespace PBD;
68 using namespace Gtk;
69 using namespace Gtkmm2ext;
70 using namespace std;
71
72 sigc::signal<void,boost::shared_ptr<Route> > MixerStrip::SwitchIO;
73
74 int MixerStrip::scrollbar_height = 0;
75
76 MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
77         : AxisView(sess)
78         , RouteUI (sess)
79         ,_mixer(mx)
80         , _mixer_owned (in_mixer)
81         , processor_box (sess, mx.plugin_selector(), mx.selection(), this, in_mixer)
82         , gpm (sess)
83         , panners (sess)
84         , button_table (3, 2)
85         , middle_button_table (1, 2)
86         , bottom_button_table (1, 2)
87         , meter_point_label (_("pre"))
88         , comment_button (_("Comments"))
89                          
90 {
91         init ();
92         
93         if (!_mixer_owned) {
94                 /* the editor mixer strip: don't destroy it every time
95                    the underlying route goes away.
96                 */
97                 
98                 self_destruct = false;
99         }
100 }
101
102 MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
103         : AxisView(sess)
104         , RouteUI (sess)
105         ,_mixer(mx)
106         , _mixer_owned (in_mixer)
107         , processor_box (sess, mx.plugin_selector(), mx.selection(), this, in_mixer)
108         , gpm (sess)
109         , panners (sess)
110         , button_table (3, 2)
111         , middle_button_table (1, 2)
112         , bottom_button_table (1, 2)
113         , meter_point_label (_("pre"))
114         , comment_button (_("Comments"))
115                          
116 {
117         init ();
118         set_button_names ();
119         set_route (rt);
120 }
121
122 void
123 MixerStrip::init ()
124 {
125         input_selector = 0;
126         output_selector = 0;
127         group_menu = 0;
128         _marked_for_display = false;
129         route_ops_menu = 0;
130         ignore_comment_edit = false;
131         ignore_toggle = false;
132         comment_window = 0;
133         comment_area = 0;
134         _width_owner = 0;
135         spacer = 0;
136
137         Gtk::Image* img;
138
139         img = manage (new Gtk::Image (::get_icon("strip_width")));
140         img->show ();
141
142         width_button.add (*img);
143
144         img = manage (new Gtk::Image (::get_icon("hide")));
145         img->show ();
146
147         hide_button.add (*img);
148
149         input_label.set_text (_("Input"));
150         ARDOUR_UI::instance()->set_tip (&input_button, _("Button 1 to choose inputs from a port matrix, button 3 to select inputs from a menu"), "");
151         input_button.add (input_label);
152         input_button.set_name ("MixerIOButton");
153         input_label.set_name ("MixerIOButtonLabel");
154         Gtkmm2ext::set_size_request_to_display_given_text (input_button, "longest label", 4, 4);
155
156         output_label.set_text (_("Output"));
157         ARDOUR_UI::instance()->set_tip (&output_button, _("Button 1 to choose outputs from a port matrix, button 3 to select inputs from a menu"), "");
158         output_button.add (output_label);
159         output_button.set_name ("MixerIOButton");
160         output_label.set_name ("MixerIOButtonLabel");
161         Gtkmm2ext::set_size_request_to_display_given_text (output_button, "longest label", 4, 4);
162
163         ARDOUR_UI::instance()->set_tip (&meter_point_button, _("Select metering point"), "");
164         meter_point_button.add (meter_point_label);
165         meter_point_button.set_name ("MixerStripMeterPreButton");
166         meter_point_label.set_name ("MixerStripMeterPreButton");
167         
168         /* TRANSLATORS: this string should be longest of the strings
169            used to describe meter points. In english, it's "input".
170         */
171         set_size_request_to_display_given_text (meter_point_button, _("tupni"), 5, 5);
172     
173         bottom_button_table.attach (meter_point_button, 1, 2, 0, 1);
174     
175         meter_point_button.signal_button_press_event().connect (mem_fun (gpm, &GainMeter::meter_press), false);
176         meter_point_button.signal_button_release_event().connect (mem_fun (gpm, &GainMeter::meter_release), false);
177
178         hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
179
180         mute_button->set_name ("MixerMuteButton");
181         solo_button->set_name ("MixerSoloButton");
182
183         button_table.set_homogeneous (true);
184         button_table.set_spacings (0);
185
186         button_table.attach (name_button, 0, 2, 0, 1);
187         button_table.attach (input_button, 0, 2, 1, 2);
188
189         middle_button_table.set_homogeneous (true);
190         middle_button_table.set_spacings (0);
191         middle_button_table.attach (*mute_button, 0, 1, 0, 1);
192         middle_button_table.attach (*solo_button, 1, 2, 0, 1);
193
194         bottom_button_table.set_col_spacings (0);
195         bottom_button_table.set_homogeneous (true);
196         bottom_button_table.attach (group_button, 0, 1, 0, 1);
197         
198         name_button.add (name_label);
199         name_button.set_name ("MixerNameButton");
200         Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
201
202         name_label.set_name ("MixerNameButtonLabel");
203         ARDOUR_UI::instance()->set_tip (&group_button, _("Mix group"), "");
204         group_button.add (group_label);
205         group_button.set_name ("MixerGroupButton");
206         group_label.set_name ("MixerGroupButtonLabel");
207
208         comment_button.set_name ("MixerCommentButton");
209
210         comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked));
211         
212         global_vpacker.set_border_width (0);
213         global_vpacker.set_spacing (0);
214
215         width_button.set_name ("MixerWidthButton");
216         hide_button.set_name ("MixerHideButton");
217         top_event_box.set_name ("MixerTopEventBox");
218
219         width_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::width_clicked));
220         hide_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::hide_clicked));
221
222         width_hide_box.pack_start (width_button, false, true);
223         width_hide_box.pack_start (top_event_box, true, true);
224         width_hide_box.pack_end (hide_button, false, true);
225         gain_meter_alignment.set_padding(0, 4, 0, 0);
226         gain_meter_alignment.add(gpm);
227
228         whvbox.pack_start (width_hide_box, true, true);
229
230         global_vpacker.pack_start (whvbox, Gtk::PACK_SHRINK);
231         global_vpacker.pack_start (button_table,Gtk::PACK_SHRINK);
232         global_vpacker.pack_start (processor_box, true, true);
233         global_vpacker.pack_start (middle_button_table,Gtk::PACK_SHRINK);
234         global_vpacker.pack_start (gain_meter_alignment,Gtk::PACK_SHRINK);
235         global_vpacker.pack_start (bottom_button_table,Gtk::PACK_SHRINK);
236         if (!is_midi_track()) {
237                 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
238         }
239         global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
240         global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
241
242         global_frame.add (global_vpacker);
243         global_frame.set_shadow_type (Gtk::SHADOW_IN);
244         global_frame.set_name ("BaseFrame");
245
246         add (global_frame);
247
248         /* force setting of visible selected status */
249
250         _selected = true;
251         set_selected (false);
252
253         _packed = false;
254         _embedded = false;
255
256         _session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped));
257         _session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running));
258
259         input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false);
260         output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false);
261
262         solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false);
263         solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false);
264         mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
265         mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
266
267         /* we don't need this if its not an audio track, but we don't know that yet and it doesn't
268            hurt (much).
269         */
270
271         rec_enable_button->set_name ("MixerRecordEnableButton");
272         rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
273         rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
274
275         /* ditto for this button and busses */
276
277         show_sends_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::show_sends_press), false);
278         show_sends_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::show_sends_release));
279
280         name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false);
281         group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_route_group), false);
282
283         _width = (Width) -1;
284
285         /* start off as a passthru strip. we'll correct this, if necessary,
286            in update_diskstream_display().
287         */
288
289         /* start off as a passthru strip. we'll correct this, if necessary,
290            in update_diskstream_display().
291         */
292
293         if (is_midi_track())
294                 set_name ("MidiTrackStripBase");
295         else
296                 set_name ("AudioTrackStripBase");
297
298         add_events (Gdk::BUTTON_RELEASE_MASK|
299                     Gdk::ENTER_NOTIFY_MASK|
300                     Gdk::LEAVE_NOTIFY_MASK|
301                     Gdk::KEY_PRESS_MASK|
302                     Gdk::KEY_RELEASE_MASK);
303
304         set_flags (get_flags() | Gtk::CAN_FOCUS);
305         
306         SwitchIO.connect (mem_fun (*this, &MixerStrip::switch_io));
307         
308 }
309
310 MixerStrip::~MixerStrip ()
311 {
312         GoingAway(); /* EMIT_SIGNAL */
313
314         delete input_selector;
315         delete output_selector;
316 }
317
318 void
319 MixerStrip::set_route (boost::shared_ptr<Route> rt)
320 {
321         if (rec_enable_button->get_parent()) {
322                 button_table.remove (*rec_enable_button);
323         }
324
325         if (show_sends_button->get_parent()) {
326                 button_table.remove (*show_sends_button);
327         }
328
329         RouteUI::set_route (rt);
330
331         delete input_selector;
332         input_selector = 0;
333
334         delete output_selector;
335         output_selector = 0;
336
337         boost::shared_ptr<Send> send;
338
339         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
340                 send->set_metering (false);
341         }
342
343         _current_delivery = _route->main_outs ();
344
345         panners.set_panner (rt->main_outs()->panner());
346         gpm.set_controls (rt, rt->shared_peak_meter(), rt->amp());
347         processor_box.set_route (rt);
348
349         if (set_color_from_route()) {
350                 set_color (unique_random_color());
351         }
352
353         if (_mixer_owned && (route()->is_master() || route()->is_control())) {
354                 
355                 if (scrollbar_height == 0) {
356                         HScrollbar scrollbar;
357                         Gtk::Requisition requisition(scrollbar.size_request ());
358                         scrollbar_height = requisition.height;
359                 }
360
361                 spacer = manage (new EventBox);
362                 spacer->set_size_request (-1, scrollbar_height);
363                 global_vpacker.pack_start (*spacer, false, false);
364         }
365
366         if (is_audio_track()) {
367
368                 boost::shared_ptr<AudioTrack> at = audio_track();
369
370                 connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
371
372                 button_table.attach (*rec_enable_button, 0, 2, 2, 3);
373                 rec_enable_button->show();
374
375         } else if (!is_track()) {
376                 /* non-master bus */
377
378                 if (!_route->is_master()) {
379                         button_table.attach (*show_sends_button, 0, 2, 2, 3);
380                         show_sends_button->show();
381                 }
382         }
383
384         if (_route->phase_invert()) {
385                 name_label.set_text (X_("Ø ") + name_label.get_text());
386         } else {
387                 name_label.set_text (_route->name());
388         }
389
390         switch (_route->meter_point()) {
391         case MeterInput:
392                 meter_point_label.set_text (_("input"));
393                 break;
394                 
395         case MeterPreFader:
396                 meter_point_label.set_text (_("pre"));
397                 break;
398                 
399         case MeterPostFader:
400                 meter_point_label.set_text (_("post"));
401                 break;
402         }
403
404         delete route_ops_menu;
405         route_ops_menu = 0;
406         
407         ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment().empty() ?
408                                                    _("Click to Add/Edit Comments"):
409                                                    _route->comment());
410
411         connections.push_back (_route->meter_change.connect (
412                         mem_fun(*this, &MixerStrip::meter_changed)));
413         connections.push_back (_route->input()->changed.connect (
414                         mem_fun(*this, &MixerStrip::input_changed)));
415         connections.push_back (_route->output()->changed.connect (
416                         mem_fun(*this, &MixerStrip::output_changed)));
417         connections.push_back (_route->route_group_changed.connect (
418                         mem_fun(*this, &MixerStrip::route_group_changed)));
419
420         if (_route->panner()) {
421                 connections.push_back (_route->panner()->Changed.connect (
422                         mem_fun(*this, &MixerStrip::connect_to_pan)));
423         }
424
425         if (is_audio_track()) {
426                 connections.push_back (audio_track()->DiskstreamChanged.connect (
427                         mem_fun(*this, &MixerStrip::diskstream_changed)));
428         }
429
430         connections.push_back (_route->NameChanged.connect (
431                         mem_fun(*this, &RouteUI::name_changed)));
432         connections.push_back (_route->comment_changed.connect (
433                         mem_fun(*this, &MixerStrip::comment_changed)));
434         connections.push_back (_route->gui_changed.connect (
435                         mem_fun(*this, &MixerStrip::route_gui_changed)));
436
437         set_stuff_from_route ();
438
439         /* now force an update of all the various elements */
440
441         processor_box.update();
442         mute_changed (0);
443         solo_changed (0);
444         name_changed ();
445         comment_changed (0);
446         route_group_changed (0);
447
448         connect_to_pan ();
449
450         panners.setup_pan ();
451
452         update_diskstream_display ();
453         update_input_display ();
454         update_output_display ();
455
456         add_events (Gdk::BUTTON_RELEASE_MASK);
457
458         processor_box.show();
459
460         if (!route()->is_master() && !route()->is_control()) {
461                 /* we don't allow master or control routes to be hidden */
462                 hide_button.show();
463         }
464
465         width_button.show();
466         width_hide_box.show();
467         whvbox.show ();
468         global_frame.show();
469         global_vpacker.show();
470         button_table.show();
471         middle_button_table.show();
472         bottom_button_table.show();
473         processor_box.show_all ();
474         gpm.show_all ();
475         panners.show_all ();
476         gain_meter_alignment.show ();
477         gain_unit_button.show();
478         gain_unit_label.show();
479         meter_point_button.show();
480         meter_point_label.show();
481         diskstream_button.show();
482         diskstream_label.show();
483         input_button.show();
484         input_label.show();
485         output_button.show();
486         output_label.show();
487         name_label.show();
488         name_button.show();
489         comment_button.show();
490         group_button.show();
491         group_label.show();
492
493         show ();
494 }
495
496 void
497 MixerStrip::set_stuff_from_route ()
498 {
499         XMLProperty *prop;
500
501         ensure_xml_node ();
502
503         /* if width is not set, it will be set by the MixerUI or editor */
504
505         if ((prop = xml_node->property ("strip-width")) != 0) {
506                 set_width_enum (Width (string_2_enum (prop->value(), _width)), this);
507         }
508
509         if ((prop = xml_node->property ("shown-mixer")) != 0) {
510                 if (prop->value() == "no") {
511                         _marked_for_display = false;
512                 } else {
513                         _marked_for_display = true;
514                 }
515         } else {
516                 /* backwards compatibility */
517                 _marked_for_display = true;
518         }
519 }
520
521 void
522 MixerStrip::set_width_enum (Width w, void* owner)
523 {
524         /* always set the gpm width again, things may be hidden */
525
526         gpm.set_width (w);
527         panners.set_width (w);
528         processor_box.set_width (w);
529
530         boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
531
532         _width_owner = owner;
533
534         ensure_xml_node ();
535         
536         _width = w;
537
538         if (_width_owner == this) {
539                 xml_node->add_property ("strip-width", enum_2_string (_width));
540         }
541
542         set_button_names ();
543
544         switch (w) {
545         case Wide:
546                 if (show_sends_button)  {
547                         ((Gtk::Label*)show_sends_button->get_child())->set_text (_("Sends"));
548                 }
549
550                 if (_route->comment() == "") {
551                         comment_button.unset_bg (STATE_NORMAL);
552                         ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
553                 } else {
554                         comment_button.modify_bg (STATE_NORMAL, color());
555                         ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
556                 }
557
558                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
559                                 gpm.astyle_string(gain_automation->automation_style()));
560                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
561                                 gpm.astate_string(gain_automation->automation_state()));
562
563                 if (_route->panner()) {
564                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
565                                         panners.astyle_string(_route->panner()->automation_style()));
566                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
567                                         panners.astate_string(_route->panner()->automation_state()));
568                 }
569
570                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
571                 set_size_request (-1, -1);
572                 break;
573
574         case Narrow:
575                 if (show_sends_button) {
576                         ((Gtk::Label*)show_sends_button->get_child())->set_text (_("Snd"));
577                 }
578
579                 if (_route->comment() == "") {
580                        comment_button.unset_bg (STATE_NORMAL);
581                        ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
582                 } else {
583                        comment_button.modify_bg (STATE_NORMAL, color());
584                        ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
585                 }
586
587                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
588                                 gpm.short_astyle_string(gain_automation->automation_style()));
589                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
590                                 gpm.short_astate_string(gain_automation->automation_state()));
591                 
592                 if (_route->panner()) {
593                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
594                         panners.short_astyle_string(_route->panner()->automation_style()));
595                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
596                         panners.short_astate_string(_route->panner()->automation_state()));
597                 }
598
599                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
600                 set_size_request (max (50, gpm.get_gm_width()), -1);
601                 break;
602         }
603         update_input_display ();
604         update_output_display ();
605         route_group_changed (0);
606         name_changed ();
607         WidthChanged ();
608 }
609
610 void
611 MixerStrip::set_packed (bool yn)
612 {
613         _packed = yn;
614
615         ensure_xml_node ();
616
617         if (_packed) {
618                 xml_node->add_property ("shown-mixer", "yes");
619         } else {
620                 xml_node->add_property ("shown-mixer", "no");
621         }
622 }
623
624
625 gint
626 MixerStrip::output_press (GdkEventButton *ev)
627 {
628         using namespace Menu_Helpers;
629         if (!_session.engine().connected()) {
630                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
631                 msg.run ();
632                 return true;
633         }
634
635         MenuList& citems = output_menu.items();
636         switch (ev->button) {
637
638         case 1:
639                 edit_output_configuration ();
640                 break;
641                 
642         case 3:
643         {
644                 output_menu.set_name ("ArdourContextMenu");
645                 citems.clear();
646                 
647                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
648                 citems.push_back (SeparatorElem());
649
650                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
651
652                 boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
653                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
654                         maybe_add_bundle_to_output_menu (*i, current);
655                 }
656
657                 boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
658                 for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
659                         maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
660                 }
661
662                 if (citems.size() == 2) {
663                         /* no routes added; remove the separator */
664                         citems.pop_back ();
665                 }
666
667                 output_menu.popup (1, ev->time);
668                 break;
669         }
670
671         default:
672                 break;
673         }
674         return TRUE;
675 }
676
677 void
678 MixerStrip::edit_output_configuration ()
679 {
680         if (output_selector == 0) {
681                 output_selector = new IOSelectorWindow (_session, _route->output());
682         } 
683
684         if (output_selector->is_visible()) {
685                 output_selector->get_toplevel()->get_window()->raise();
686         } else {
687                 output_selector->present ();
688         }
689 }
690
691 void
692 MixerStrip::edit_input_configuration ()
693 {
694         if (input_selector == 0) {
695                 input_selector = new IOSelectorWindow (_session, _route->input());
696         } 
697
698         if (input_selector->is_visible()) {
699                 input_selector->get_toplevel()->get_window()->raise();
700         } else {
701                 input_selector->present ();
702         }
703 }
704
705 gint
706 MixerStrip::input_press (GdkEventButton *ev)
707 {
708         using namespace Menu_Helpers;
709
710         MenuList& citems = input_menu.items();
711         input_menu.set_name ("ArdourContextMenu");
712         citems.clear();
713         
714         if (!_session.engine().connected()) {
715                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
716                 msg.run ();
717                 return true;
718         }
719
720         switch (ev->button) {
721
722         case 1:
723                 edit_input_configuration ();
724                 break;
725
726         case 3:
727         {
728                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
729                 citems.push_back (SeparatorElem());
730
731                 ARDOUR::BundleList current = _route->input()->bundles_connected ();
732
733                 boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
734                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
735                         maybe_add_bundle_to_input_menu (*i, current);
736                 }
737
738                 boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
739                 for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
740                         maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
741                 }
742
743                 if (citems.size() == 2) {
744                         /* no routes added; remove the separator */
745                         citems.pop_back ();
746                 }
747
748                 input_menu.popup (1, ev->time);
749                 break;
750         }
751         default:
752                 break;
753         }
754         return TRUE;
755 }
756
757 void
758 MixerStrip::bundle_input_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
759 {
760         if (ignore_toggle) {
761                 return;
762         }
763
764         ARDOUR::BundleList current = _route->input()->bundles_connected ();
765
766         if (std::find (current.begin(), current.end(), c) == current.end()) {
767                 _route->input()->connect_ports_to_bundle (c, this);
768         } else {
769                 _route->input()->disconnect_ports_from_bundle (c, this);
770         }
771 }
772
773 void
774 MixerStrip::bundle_output_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
775 {
776         if (ignore_toggle) {
777                 return;
778         }
779
780         ARDOUR::BundleList current = _route->output()->bundles_connected ();
781
782         if (std::find (current.begin(), current.end(), c) == current.end()) {
783                 _route->output()->connect_ports_to_bundle (c, this);
784         } else {
785                 _route->output()->disconnect_ports_from_bundle (c, this);
786         }
787 }
788
789 void
790 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
791 {
792         using namespace Menu_Helpers;
793
794         if (b->ports_are_outputs() == false ||
795             route()->input()->default_type() != b->type() ||
796             b->nchannels() != _route->n_inputs().get (b->type ())) {
797                 
798                 return;
799         }
800
801         MenuList& citems = input_menu.items();
802         
803         std::string n = b->name ();
804         replace_all (n, "_", " ");
805         
806         citems.push_back (CheckMenuElem (n, bind (mem_fun(*this, &MixerStrip::bundle_input_toggled), b)));
807         
808         if (std::find (current.begin(), current.end(), b) != current.end()) {
809                 ignore_toggle = true;
810                 dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
811                 ignore_toggle = false;
812         }
813 }
814
815 void
816 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
817 {
818         using namespace Menu_Helpers;
819
820         if (b->ports_are_inputs() == false ||
821             route()->output()->default_type() != b->type() ||
822             b->nchannels() != _route->n_outputs().get (b->type ())) {
823                 
824                 return;
825         }
826
827         MenuList& citems = output_menu.items();
828         
829         std::string n = b->name ();
830         replace_all (n, "_", " ");
831         
832         citems.push_back (CheckMenuElem (n, bind (mem_fun(*this, &MixerStrip::bundle_output_toggled), b)));
833         
834         if (std::find (current.begin(), current.end(), b) != current.end()) {
835                 ignore_toggle = true;
836                 dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
837                 ignore_toggle = false;
838         }
839 }
840
841 void
842 MixerStrip::update_diskstream_display ()
843 {
844         if (is_track()) {
845
846                 if (input_selector) {
847                         input_selector->hide_all ();
848                 }
849
850                 show_route_color ();
851
852         } else {
853
854                 show_passthru_color ();
855         }
856 }
857
858 void
859 MixerStrip::connect_to_pan ()
860 {
861         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::connect_to_pan));
862
863         panstate_connection.disconnect ();
864         panstyle_connection.disconnect ();
865
866         if (!_route->panner()) {
867                 return;
868         }
869
870         boost::shared_ptr<ARDOUR::AutomationControl> pan_control
871                 = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
872                                 _route->panner()->data().control(Evoral::Parameter(PanAutomation)));
873
874         if (pan_control) {
875                 panstate_connection = pan_control->alist()->automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed));
876                 panstyle_connection = pan_control->alist()->automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed));
877         }
878
879         panners.pan_changed (this);
880 }
881
882 void
883 MixerStrip::update_input_display ()
884 {
885         ARDOUR::BundleList const c = _route->input()->bundles_connected();
886
887         if (c.size() > 1) {
888                 input_label.set_text (_("Inputs"));
889         } else if (c.size() == 1) {
890                 input_label.set_text (c[0]->name ());
891         } else {
892                 switch (_width) {
893                 case Wide:
894                         input_label.set_text (_(" Input"));
895                         break;
896                 case Narrow:
897                         input_label.set_text (_("I"));
898                         break;
899                 }
900         }
901         panners.setup_pan ();
902 }
903
904 void
905 MixerStrip::update_output_display ()
906 {
907         ARDOUR::BundleList const c = _route->output()->bundles_connected ();
908
909         /* XXX: how do we represent >1 connected bundle? */
910         if (c.size() > 1) {
911                 output_label.set_text (_("Outputs"));
912         } else if (c.size() == 1) {
913                 output_label.set_text (c[0]->name());
914         } else {
915                 switch (_width) {
916                 case Wide:
917                         output_label.set_text (_("Output"));
918                         break;
919                 case Narrow:
920                         output_label.set_text (_("O"));
921                         break;
922                 }
923         }
924
925         gpm.setup_meters ();
926         panners.setup_pan ();
927 }
928
929 void
930 MixerStrip::fast_update ()
931 {
932         gpm.update_meters ();
933 }
934
935 void
936 MixerStrip::diskstream_changed ()
937 {
938         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display));
939 }       
940
941 void
942 MixerStrip::input_changed (IOChange change, void *src)
943 {
944         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_input_display));
945         set_width_enum (_width, this);
946 }
947
948 void
949 MixerStrip::output_changed (IOChange change, void *src)
950 {
951         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_output_display));
952         set_width_enum (_width, this);
953 }
954
955
956 void 
957 MixerStrip::comment_editor_done_editing() 
958 {
959         string str =  comment_area->get_buffer()->get_text();
960         if (_route->comment() != str) {
961                 _route->set_comment (str, this);
962
963                 switch (_width) {
964                    
965                 case Wide:
966                         if (! str.empty()) {
967                                 comment_button.modify_bg (STATE_NORMAL, color());
968                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
969                         } else {
970                                 comment_button.unset_bg (STATE_NORMAL);
971                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
972                         }
973                         break;
974                    
975                 case Narrow:
976                         if (! str.empty()) {
977                                 comment_button.modify_bg (STATE_NORMAL, color());
978                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
979                         } else {
980                                 comment_button.unset_bg (STATE_NORMAL);
981                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
982                         } 
983                         break;
984                 }
985                  
986                 ARDOUR_UI::instance()->tooltips().set_tip (comment_button, 
987                                 str.empty() ? _("Click to Add/Edit Comments") : str);
988         }
989
990 }
991
992 void
993 MixerStrip::comment_button_clicked ()
994 {
995         if (comment_window == 0) {
996                 setup_comment_editor ();
997         }
998
999     int x, y, cw_width, cw_height;
1000
1001         if (comment_window->is_visible()) {
1002                 comment_window->hide ();
1003                 return;
1004         }
1005
1006         comment_window->get_size (cw_width, cw_height);
1007         comment_window->get_position(x, y);
1008         comment_window->move(x, y - (cw_height / 2) - 45);
1009         /* 
1010            half the dialog height minus the comments button height 
1011            with some window decoration fudge thrown in.
1012         */
1013
1014         comment_window->show();
1015         comment_window->present();
1016 }
1017
1018 void
1019 MixerStrip::setup_comment_editor ()
1020 {
1021         string title;
1022         title = _route->name();
1023         title += _(": comment editor");
1024
1025         comment_window = new ArdourDialog (title, false);
1026         comment_window->set_position (Gtk::WIN_POS_MOUSE);
1027         comment_window->set_skip_taskbar_hint (true);
1028         comment_window->signal_hide().connect (mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1029
1030         comment_area = manage (new TextView());
1031         comment_area->set_name ("MixerTrackCommentArea");
1032         comment_area->set_size_request (110, 178);
1033         comment_area->set_wrap_mode (WRAP_WORD);
1034         comment_area->set_editable (true);
1035         comment_area->get_buffer()->set_text (_route->comment());
1036         comment_area->show ();
1037
1038         comment_window->get_vbox()->pack_start (*comment_area);
1039         comment_window->get_action_area()->hide();
1040 }
1041
1042 void
1043 MixerStrip::comment_changed (void *src)
1044 {
1045         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::comment_changed), src));
1046         
1047         if (src != this) {
1048                 ignore_comment_edit = true;
1049                 if (comment_area) {
1050                         comment_area->get_buffer()->set_text (_route->comment());
1051                 }
1052                 ignore_comment_edit = false;
1053         }
1054 }
1055
1056 void
1057 MixerStrip::set_route_group (RouteGroup *rg)
1058 {
1059         _route->set_route_group (rg, this);
1060 }
1061
1062 bool
1063 MixerStrip::select_route_group (GdkEventButton *ev)
1064 {
1065         using namespace Menu_Helpers;
1066
1067         if (ev->button == 1) {
1068
1069                 if (group_menu == 0) {
1070                         
1071                         group_menu = new RouteGroupMenu (
1072                                 _session,
1073                                 (RouteGroup::Property) (RouteGroup::Gain | RouteGroup::Mute | RouteGroup::Solo)
1074                                 );
1075                         
1076                         group_menu->GroupSelected.connect (mem_fun (*this, &MixerStrip::set_route_group));
1077                 }
1078
1079                 group_menu->popup (1, ev->time);
1080         }
1081         
1082         return true;
1083 }       
1084
1085 void
1086 MixerStrip::route_group_changed (void *ignored)
1087 {
1088         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_group_changed), ignored));
1089         
1090         RouteGroup *rg = _route->route_group();
1091
1092         if (rg) {
1093                 /* XXX: this needs a better algorithm */
1094                 string truncated = rg->name ();
1095                 if (truncated.length () > 5) {
1096                         truncated = truncated.substr (0, 5);
1097                 }
1098                 group_label.set_text (truncated);
1099         } else {
1100                 switch (_width) {
1101                 case Wide:
1102                         group_label.set_text (_("Grp"));
1103                         break;
1104                 case Narrow:
1105                         group_label.set_text (_("~G"));
1106                         break;
1107                 }
1108         }
1109 }
1110
1111
1112 void 
1113 MixerStrip::route_gui_changed (string what_changed, void* ignored)
1114 {
1115         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_gui_changed), what_changed, ignored));
1116         
1117         if (what_changed == "color") {
1118                 if (set_color_from_route () == 0) {
1119                         show_route_color ();
1120                 }
1121         }
1122 }
1123
1124 void
1125 MixerStrip::show_route_color ()
1126 {
1127         name_button.modify_bg (STATE_NORMAL, color());
1128         top_event_box.modify_bg (STATE_NORMAL, color());
1129         route_active_changed ();
1130 }
1131
1132 void
1133 MixerStrip::show_passthru_color ()
1134 {
1135         route_active_changed ();
1136 }
1137
1138 void
1139 MixerStrip::build_route_ops_menu ()
1140 {
1141         using namespace Menu_Helpers;
1142         route_ops_menu = new Menu;
1143         route_ops_menu->set_name ("ArdourContextMenu");
1144
1145         MenuList& items = route_ops_menu->items();
1146
1147         items.push_back (MenuElem (_("Save As Template"), mem_fun(*this, &RouteUI::save_as_template)));
1148         items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteUI::route_rename)));
1149         rename_menu_item = &items.back();
1150         items.push_back (SeparatorElem());
1151         items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
1152         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1153         route_active_menu_item->set_active (_route->active());
1154
1155         items.push_back (SeparatorElem());
1156
1157         items.push_back (MenuElem (_("Adjust latency"), mem_fun (*this, &RouteUI::adjust_latency)));
1158
1159         items.push_back (SeparatorElem());
1160         items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
1161         polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1162         polarity_menu_item->set_active (_route->phase_invert());
1163         items.push_back (CheckMenuElem (_("Protect against denormals"), mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1164         denormal_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1165         denormal_menu_item->set_active (_route->denormal_protection());
1166
1167         if (!Profile->get_sae()) {
1168                 build_remote_control_menu ();
1169                 items.push_back (SeparatorElem());
1170                 items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu));
1171         }
1172
1173         items.push_back (SeparatorElem());
1174         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
1175 }
1176
1177 gint
1178 MixerStrip::name_button_button_press (GdkEventButton* ev)
1179 {
1180         if (ev->button == 1 || ev->button == 3) {
1181                 list_route_operations ();
1182
1183                 /* do not allow rename if the track is record-enabled */
1184                 rename_menu_item->set_sensitive (!_route->record_enabled());
1185                 route_ops_menu->popup (1, ev->time);
1186         }
1187         return FALSE;
1188 }
1189
1190 void
1191 MixerStrip::list_route_operations ()
1192 {
1193         if (route_ops_menu == 0) {
1194                 build_route_ops_menu ();
1195         }
1196         
1197         refresh_remote_control_menu();
1198 }
1199
1200 void
1201 MixerStrip::set_selected (bool yn)
1202 {
1203         AxisView::set_selected (yn);
1204         if (_selected) {
1205                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1206                 global_frame.set_name ("MixerStripSelectedFrame");
1207         } else {
1208                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1209                 global_frame.set_name ("MixerStripFrame");
1210         }
1211         global_frame.queue_draw ();
1212 }
1213
1214 void
1215 MixerStrip::name_changed ()
1216 {
1217         switch (_width) {
1218         case Wide:
1219                 RouteUI::name_changed ();
1220                 break;
1221         case Narrow:
1222                 name_label.set_text (PBD::short_version (_route->name(), 5));
1223                 break;
1224         }
1225         if (_route->phase_invert()) {
1226                 name_label.set_text (X_("Ø ") + name_label.get_text());
1227         }
1228 }
1229
1230 void
1231 MixerStrip::width_clicked ()
1232 {
1233         switch (_width) {
1234         case Wide:
1235                 set_width_enum (Narrow, this);
1236                 break;
1237         case Narrow:
1238                 set_width_enum (Wide, this);
1239                 break;
1240         }
1241 }
1242
1243 void
1244 MixerStrip::hide_clicked ()
1245 {
1246         // LAME fix to reset the button status for when it is redisplayed (part 1)
1247         hide_button.set_sensitive(false);
1248         
1249         if (_embedded) {
1250                 Hiding(); /* EMIT_SIGNAL */
1251         } else {
1252                 _mixer.hide_strip (this);
1253         }
1254         
1255         // (part 2)
1256         hide_button.set_sensitive(true);
1257 }
1258
1259 void
1260 MixerStrip::set_embedded (bool yn)
1261 {
1262         _embedded = yn;
1263 }
1264
1265 void
1266 MixerStrip::map_frozen ()
1267 {
1268         ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::map_frozen));
1269
1270         boost::shared_ptr<AudioTrack> at = audio_track();
1271
1272         if (at) {
1273                 switch (at->freeze_state()) {
1274                 case AudioTrack::Frozen:
1275                         processor_box.set_sensitive (false);
1276                         break;
1277                 default:
1278                         processor_box.set_sensitive (true);
1279                         // XXX need some way, maybe, to retoggle redirect editors
1280                         break;
1281                 }
1282         }
1283         
1284         hide_redirect_editors ();
1285 }
1286
1287 void
1288 MixerStrip::hide_redirect_editors ()
1289 {
1290         _route->foreach_processor (mem_fun (*this, &MixerStrip::hide_processor_editor));
1291 }
1292
1293 void
1294 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1295 {
1296         boost::shared_ptr<Processor> processor (p.lock ());
1297         if (!processor) {
1298                 return;
1299         }
1300         
1301         void* gui = processor->get_gui ();
1302         
1303         if (gui) {
1304                 static_cast<Gtk::Widget*>(gui)->hide ();
1305         }
1306 }
1307
1308 void
1309 MixerStrip::route_active_changed ()
1310 {
1311         RouteUI::route_active_changed ();
1312
1313         if (is_midi_track()) {
1314                 if (_route->active()) {
1315                         set_name ("MidiTrackStripBase");
1316                         gpm.set_meter_strip_name ("MidiTrackStripBase");
1317                 } else {
1318                         set_name ("MidiTrackStripBaseInactive");
1319                         gpm.set_meter_strip_name ("MidiTrackStripBaseInactive");
1320                 }
1321                 gpm.set_fader_name ("MidiTrackFader");
1322         } else if (is_audio_track()) {
1323                 if (_route->active()) {
1324                         set_name ("AudioTrackStripBase");
1325                         gpm.set_meter_strip_name ("AudioTrackMetrics");
1326                 } else {
1327                         set_name ("AudioTrackStripBaseInactive");
1328                         gpm.set_meter_strip_name ("AudioTrackMetricsInactive");
1329                 }
1330                 gpm.set_fader_name ("AudioTrackFader");
1331         } else {
1332                 if (_route->active()) {
1333                         set_name ("AudioBusStripBase");
1334                         gpm.set_meter_strip_name ("AudioBusMetrics");
1335                 } else {
1336                         set_name ("AudioBusStripBaseInactive");
1337                         gpm.set_meter_strip_name ("AudioBusMetricsInactive");
1338                 }
1339                 gpm.set_fader_name ("AudioBusFader");
1340                 
1341                 /* (no MIDI busses yet) */
1342         }
1343 }
1344
1345 RouteGroup*
1346 MixerStrip::route_group() const
1347 {
1348         return _route->route_group();
1349 }
1350
1351 void
1352 MixerStrip::engine_stopped ()
1353 {
1354 }
1355
1356 void
1357 MixerStrip::engine_running ()
1358 {
1359 }
1360
1361 void
1362 MixerStrip::meter_changed (void *src)
1363 {
1364         ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
1365
1366         switch (_route->meter_point()) {
1367         case MeterInput:
1368                 meter_point_label.set_text (_("input"));
1369                 break;
1370
1371         case MeterPreFader:
1372                 meter_point_label.set_text (_("pre"));
1373                 break;
1374                 
1375         case MeterPostFader:
1376                 meter_point_label.set_text (_("post"));
1377                 break;
1378         }
1379
1380         gpm.setup_meters ();
1381         // reset peak when meter point changes
1382         gpm.reset_peak_display();
1383         set_width_enum (_width, this);
1384 }
1385
1386 void
1387 MixerStrip::switch_io (boost::shared_ptr<Route> target)
1388 {
1389         if (_route == target || _route->is_master()) {
1390                 /* don't change the display for the target or the master bus */
1391                 return;
1392         } else if (!is_track() && show_sends_button) {
1393                 /* make sure our show sends button is inactive, and we no longer blink,
1394                    since we're not the target.
1395                 */
1396                 send_blink_connection.disconnect ();
1397                 show_sends_button->set_active (false);
1398                 show_sends_button->set_state (STATE_NORMAL);
1399         }
1400
1401         if (!target) {
1402                 /* switch back to default */
1403                 revert_to_default_display ();
1404                 return;
1405         }
1406         
1407         boost::shared_ptr<Send> send;
1408
1409         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
1410                 send->set_metering (false);
1411         }
1412         
1413         _current_delivery = _route->internal_send_for (target);
1414
1415         cerr << "internal send from " << _route->name() << " to " << target->name() << " = " 
1416              << _current_delivery << endl;
1417
1418         if (_current_delivery) {
1419                 send = boost::dynamic_pointer_cast<Send>(_current_delivery);
1420                 send->set_metering (true);
1421                 _current_delivery->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display));
1422                 gain_meter().set_controls (_route, send->meter(), send->amp());
1423                 panner_ui().set_panner (_current_delivery->panner());
1424
1425         } else {
1426                 _current_delivery = _route->main_outs ();
1427                 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp());
1428                 panner_ui().set_panner (_route->main_outs()->panner());
1429         }
1430         
1431         gain_meter().setup_meters ();
1432         panner_ui().setup_pan ();
1433 }
1434
1435
1436 void
1437 MixerStrip::revert_to_default_display ()
1438 {
1439         show_sends_button->set_active (false);
1440         
1441         boost::shared_ptr<Send> send;
1442
1443         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
1444                 send->set_metering (false);
1445         }
1446         
1447         _current_delivery = _route->main_outs();
1448
1449         gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp());
1450         gain_meter().setup_meters ();
1451         panner_ui().set_panner (_route->main_outs()->panner());
1452         panner_ui().setup_pan ();
1453 }
1454
1455 void
1456 MixerStrip::set_button_names ()
1457 {
1458         switch (_width) {
1459         case Wide:
1460                 rec_enable_button_label.set_text (_("Rec"));
1461                 mute_button_label.set_text (_("Mute"));
1462                 if (!Config->get_solo_control_is_listen_control()) {
1463                         solo_button_label.set_text (_("Solo"));
1464                 } else {
1465                         switch (Config->get_listen_position()) {
1466                         case AfterFaderListen:
1467                                 solo_button_label.set_text (_("AFL"));
1468                                 break;
1469                         case PreFaderListen:
1470                                 solo_button_label.set_text (_("PFL"));
1471                                 break;
1472                         }
1473                 }
1474                 break;
1475
1476         default:
1477                 rec_enable_button_label.set_text (_("R"));
1478                 mute_button_label.set_text (_("M"));
1479                 if (!Config->get_solo_control_is_listen_control()) {
1480                         solo_button_label.set_text (_("S"));
1481                 } else {
1482                         switch (Config->get_listen_position()) {
1483                         case AfterFaderListen:
1484                                 solo_button_label.set_text (_("A"));
1485                                 break;
1486                         case PreFaderListen:
1487                                 solo_button_label.set_text (_("P"));
1488                                 break;
1489                         }
1490                 }
1491                 break;
1492                 
1493         }
1494 }
1495
1496 bool
1497 MixerStrip::on_key_press_event (GdkEventKey* ev)
1498 {
1499         GdkEventButton fake;
1500         fake.type = GDK_BUTTON_PRESS;
1501         fake.button = 1;
1502         fake.state = ev->state;
1503
1504         switch (ev->keyval) {
1505         case GDK_m:
1506                 mute_press (&fake);
1507                 return true;
1508                 break;
1509                 
1510         case GDK_s:
1511                 solo_press (&fake);
1512                 return true;
1513                 break;
1514                 
1515         case GDK_r:
1516                 rec_enable_press (&fake);
1517                 return true;
1518                 break;
1519                 
1520         case GDK_e:
1521                 show_sends_press (&fake);
1522                 return true;
1523                 break;                  
1524                 
1525         case GDK_g:
1526                 if (ev->state & Keyboard::PrimaryModifier) {
1527                         step_gain_down ();
1528                 } else {
1529                         step_gain_up ();
1530                 }
1531                 return true;
1532                 break;
1533
1534         case GDK_0:
1535                 if (_route) {
1536                         _route->set_gain (1.0, this);
1537                 }
1538                 return true;
1539                 
1540         default:
1541                 break;
1542         }
1543
1544         return false;
1545 }
1546
1547
1548 bool
1549 MixerStrip::on_key_release_event (GdkEventKey* ev)
1550 {
1551         GdkEventButton fake;
1552         fake.type = GDK_BUTTON_RELEASE;
1553         fake.button = 1;
1554         fake.state = ev->state;
1555
1556         switch (ev->keyval) {
1557         case GDK_m:
1558                 mute_release (&fake);
1559                 return true;
1560                 break;
1561                 
1562         case GDK_s:
1563                 solo_release (&fake);
1564                 return true;
1565                 break;
1566                 
1567         case GDK_r:
1568                 rec_enable_release (&fake);
1569                 return true;
1570                 break;
1571                 
1572         case GDK_e:
1573                 show_sends_release (&fake);
1574                 return true;
1575                 break;                  
1576                 
1577         case GDK_g:
1578                 return true;
1579                 break;
1580                 
1581         default:
1582                 break;
1583         }
1584
1585         return false;
1586 }
1587
1588 bool
1589 MixerStrip::on_enter_notify_event (GdkEventCrossing* ev)
1590 {
1591         Keyboard::magic_widget_grab_focus ();
1592         grab_focus ();
1593         return false;
1594 }
1595
1596 bool
1597 MixerStrip::on_leave_notify_event (GdkEventCrossing* ev)
1598 {
1599         switch (ev->detail) {
1600         case GDK_NOTIFY_INFERIOR:
1601                 break;
1602         default:
1603                 Keyboard::magic_widget_drop_focus ();
1604         }
1605
1606         return false;
1607 }