writable session patch, forward ported from 2.X
[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 MixerStrip::~MixerStrip ()
310 {
311         GoingAway(); /* EMIT_SIGNAL */
312
313         delete input_selector;
314         delete output_selector;
315 }
316
317 void
318 MixerStrip::set_route (boost::shared_ptr<Route> rt)
319 {
320         if (rec_enable_button->get_parent()) {
321                 button_table.remove (*rec_enable_button);
322         }
323
324         if (show_sends_button->get_parent()) {
325                 button_table.remove (*show_sends_button);
326         }
327
328         RouteUI::set_route (rt);
329
330         delete input_selector;
331         input_selector = 0;
332
333         delete output_selector;
334         output_selector = 0;
335
336         boost::shared_ptr<Send> send;
337
338         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
339                 send->set_metering (false);
340         }
341
342         _current_delivery = _route->main_outs ();
343
344         panners.set_panner (rt->main_outs()->panner());
345         gpm.set_controls (rt, rt->shared_peak_meter(), rt->amp());
346         processor_box.set_route (rt);
347
348         if (set_color_from_route()) {
349                 set_color (unique_random_color());
350         }
351
352         if (_mixer_owned && (route()->is_master() || route()->is_control())) {
353                 
354                 if (scrollbar_height == 0) {
355                         HScrollbar scrollbar;
356                         Gtk::Requisition requisition(scrollbar.size_request ());
357                         scrollbar_height = requisition.height;
358                 }
359
360                 spacer = manage (new EventBox);
361                 spacer->set_size_request (-1, scrollbar_height);
362                 global_vpacker.pack_start (*spacer, false, false);
363         }
364
365         if (is_audio_track()) {
366
367                 boost::shared_ptr<AudioTrack> at = audio_track();
368
369                 connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
370
371                 button_table.attach (*rec_enable_button, 0, 2, 2, 3);
372                 rec_enable_button->set_sensitive (_session.writable());
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
883 /*
884  * Output port labelling
885  * =====================
886  * 
887  * Case 1: Each output has one connection, all connections are to system:playback_%i
888  *   out 1 -> system:playback_1
889  *   out 2 -> system:playback_2
890  *   out 3 -> system:playback_3
891  *   Display as: 1/2/3
892  *
893  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
894  *   out 1 -> ardour:track_x/in 1
895  *   out 2 -> ardour:track_x/in 2
896  *   Display as: track_x
897  * 
898  * Case 3: Each output has one connection, all connections are to Jack client "program x"
899  *   out 1 -> program x:foo
900  *   out 2 -> program x:foo
901  *   Display as: program x
902  *
903  * Case 4: No connections (Disconnected)
904  *   Display as: -
905  * 
906  * Default case (unusual routing):
907  *   Display as: *number of connections*
908  *
909  * Tooltips
910  * ========
911  * .-----------------------------------------------.
912  * | Mixdown                                       |
913  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
914  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
915  * '-----------------------------------------------'
916  * .-----------------------------------------------.
917  * | Guitar SM58                                   |
918  * | Disconnected                                  |
919  * '-----------------------------------------------'
920  */
921
922 void
923 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
924 {
925         uint32_t io_count;
926         uint32_t io_index;
927         Port *port;
928         vector<string> connections;
929         
930         uint32_t total_connection_count = 0;
931         uint32_t io_connection_count = 0;
932         uint32_t ardour_connection_count = 0;
933         uint32_t system_connection_count = 0;
934         uint32_t other_connection_count = 0;
935   
936         ostringstream label;
937         string label_string;
938         char * label_cstr;
939
940         bool have_label = false;
941         bool each_io_has_one_connection = true;
942
943         string connection_name;
944         string ardour_track_name;
945         string other_connection_type;
946         string system_ports;
947         string system_port;
948         
949         ostringstream tooltip;
950         char * tooltip_cstr;
951         
952         tooltip << route->name();
953
954         if (for_input) {
955                 io_count = route->n_inputs().n_total();
956         } else {
957                 io_count = route->n_outputs().n_total();
958         }    
959         
960         for (io_index = 0; io_index < io_count; ++io_index) {
961                 if (for_input) {
962                         port = route->input()->nth (io_index);
963                 } else {
964                         port = route->output()->nth (io_index);
965                 }
966                 
967                 port->get_connections(connections);
968                 io_connection_count = 0;
969
970                 if (!connections.empty()) {
971                         for (vector<string>::iterator i = connections.begin(); i != connections.end(); ++i) {
972                                 string& connection_name (*i);
973
974                                 if (io_connection_count == 0) {
975                                         tooltip << endl << port->name().substr(port->name().find("/") + 1) << " -> " << connection_name;
976                                 } else {
977                                         tooltip << ", " << connection_name;
978                                 }
979                                 
980                                 if (connection_name.find("ardour:") == 0) {
981                                         if (ardour_track_name.empty()) {
982                                                 // "ardour:Master/in 1" -> "ardour:Master/"
983                                                 string::size_type slash = connection_name.find("/");
984                                                 if (slash != string::npos) {
985                                                         ardour_track_name = connection_name.substr(0, slash + 1);
986                                                 }
987                                         }
988                                         
989                                         if (connection_name.find(ardour_track_name) == 0) {
990                                                 ++ardour_connection_count;
991                                         }
992                                 } else if (connection_name.find("system:") == 0) {
993                                         if (for_input) {
994                                                 // "system:capture_123" -> "123"
995                                                 system_port = connection_name.substr(15);
996                                         } else {
997                                                 // "system:playback_123" -> "123"
998                                                 system_port = connection_name.substr(16);
999                                         }
1000                                         
1001                                         if (system_ports.empty()) {
1002                                                 system_ports += system_port;
1003                                         } else {
1004                                                 system_ports += "/" + system_port;
1005                                         }
1006                                         
1007                                         ++system_connection_count;
1008                                 } else {
1009                                         if (other_connection_type.empty()) {
1010                                                 // "jamin:in 1" -> "jamin:"
1011                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1012                                         }
1013                                         
1014                                         if (connection_name.find(other_connection_type) == 0) {
1015                                                 ++other_connection_count;
1016                                         }
1017                                 }
1018                                 
1019                                 ++total_connection_count;
1020                                 ++io_connection_count;
1021                         }
1022                 } 
1023                 
1024                 if (io_connection_count != 1) {
1025                         each_io_has_one_connection = false;
1026                 }
1027         }
1028         
1029         if (total_connection_count == 0) {
1030                 tooltip << endl << _("Disconnected");
1031         }
1032         
1033         tooltip_cstr = new char[tooltip.str().size() + 1];
1034         strcpy(tooltip_cstr, tooltip.str().c_str());
1035         
1036         if (for_input) {
1037                 ARDOUR_UI::instance()->set_tip (&input_button, tooltip_cstr, "");
1038         } else {
1039                 ARDOUR_UI::instance()->set_tip (&output_button, tooltip_cstr, "");
1040         }  
1041         
1042         if (each_io_has_one_connection) {
1043                 if ((total_connection_count == ardour_connection_count)) {
1044                         // all connections are to the same track in ardour
1045                         // "ardour:Master/" -> "Master"
1046                         string::size_type slash = ardour_track_name.find("/");
1047                         if (slash != string::npos) {
1048                                 label << ardour_track_name.substr(7, slash - 7);
1049                                 have_label = true;
1050                         }
1051                 }
1052                 else if (total_connection_count == system_connection_count) {
1053                         // all connections are to system ports
1054                         label << system_ports;
1055                         have_label = true;
1056                 }
1057                 else if (total_connection_count == other_connection_count) {
1058                         // all connections are to the same external program eg jamin
1059                         // "jamin:" -> "jamin"
1060                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1061                         have_label = true;
1062                 }
1063         }
1064         
1065         if (!have_label) {
1066                 if (total_connection_count == 0) {
1067                         // Disconnected
1068                         label << "-";
1069                 } else {
1070                         // Odd configuration
1071                         label << "*" << total_connection_count << "*";
1072                 }
1073         }
1074         
1075         switch (width) {
1076         case Wide:
1077                 label_string = label.str().substr(0, 6);
1078                 break;
1079         case Narrow:
1080                 label_string = label.str().substr(0, 3);
1081                 break;
1082         }
1083         
1084         label_cstr = new char[label_string.size() + 1];
1085         strcpy(label_cstr, label_string.c_str());
1086         
1087         if (for_input) {
1088                 input_label.set_text (label_cstr);
1089         } else {
1090                 output_label.set_text (label_cstr);
1091         }
1092 }
1093
1094 void
1095 MixerStrip::update_input_display ()
1096 {
1097         update_io_button (_route, _width, true);
1098         panners.setup_pan ();
1099 }
1100
1101 void
1102 MixerStrip::update_output_display ()
1103 {
1104         update_io_button (_route, _width, false);
1105         gpm.setup_meters ();
1106         panners.setup_pan ();
1107 }
1108
1109 void
1110 MixerStrip::fast_update ()
1111 {
1112         gpm.update_meters ();
1113 }
1114
1115 void
1116 MixerStrip::diskstream_changed ()
1117 {
1118         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display));
1119 }       
1120
1121 void
1122 MixerStrip::input_changed (IOChange /*change*/, void */*src*/)
1123 {
1124         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_input_display));
1125         set_width_enum (_width, this);
1126 }
1127
1128 void
1129 MixerStrip::output_changed (IOChange /*change*/, void */*src*/)
1130 {
1131         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_output_display));
1132         set_width_enum (_width, this);
1133 }
1134
1135
1136 void 
1137 MixerStrip::comment_editor_done_editing() 
1138 {
1139         string str =  comment_area->get_buffer()->get_text();
1140         if (_route->comment() != str) {
1141                 _route->set_comment (str, this);
1142
1143                 switch (_width) {
1144                    
1145                 case Wide:
1146                         if (! str.empty()) {
1147                                 comment_button.modify_bg (STATE_NORMAL, color());
1148                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
1149                         } else {
1150                                 comment_button.unset_bg (STATE_NORMAL);
1151                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
1152                         }
1153                         break;
1154                    
1155                 case Narrow:
1156                         if (! str.empty()) {
1157                                 comment_button.modify_bg (STATE_NORMAL, color());
1158                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
1159                         } else {
1160                                 comment_button.unset_bg (STATE_NORMAL);
1161                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
1162                         } 
1163                         break;
1164                 }
1165                  
1166                 ARDOUR_UI::instance()->tooltips().set_tip (comment_button, 
1167                                 str.empty() ? _("Click to Add/Edit Comments") : str);
1168         }
1169
1170 }
1171
1172 void
1173 MixerStrip::comment_button_clicked ()
1174 {
1175         if (comment_window == 0) {
1176                 setup_comment_editor ();
1177         }
1178
1179     int x, y, cw_width, cw_height;
1180
1181         if (comment_window->is_visible()) {
1182                 comment_window->hide ();
1183                 return;
1184         }
1185
1186         comment_window->get_size (cw_width, cw_height);
1187         comment_window->get_position(x, y);
1188         comment_window->move(x, y - (cw_height / 2) - 45);
1189         /* 
1190            half the dialog height minus the comments button height 
1191            with some window decoration fudge thrown in.
1192         */
1193
1194         comment_window->show();
1195         comment_window->present();
1196 }
1197
1198 void
1199 MixerStrip::setup_comment_editor ()
1200 {
1201         string title;
1202         title = _route->name();
1203         title += _(": comment editor");
1204
1205         comment_window = new ArdourDialog (title, false);
1206         comment_window->set_position (Gtk::WIN_POS_MOUSE);
1207         comment_window->set_skip_taskbar_hint (true);
1208         comment_window->signal_hide().connect (mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1209
1210         comment_area = manage (new TextView());
1211         comment_area->set_name ("MixerTrackCommentArea");
1212         comment_area->set_size_request (110, 178);
1213         comment_area->set_wrap_mode (WRAP_WORD);
1214         comment_area->set_editable (true);
1215         comment_area->get_buffer()->set_text (_route->comment());
1216         comment_area->show ();
1217
1218         comment_window->get_vbox()->pack_start (*comment_area);
1219         comment_window->get_action_area()->hide();
1220 }
1221
1222 void
1223 MixerStrip::comment_changed (void *src)
1224 {
1225         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::comment_changed), src));
1226         
1227         if (src != this) {
1228                 ignore_comment_edit = true;
1229                 if (comment_area) {
1230                         comment_area->get_buffer()->set_text (_route->comment());
1231                 }
1232                 ignore_comment_edit = false;
1233         }
1234 }
1235
1236 void
1237 MixerStrip::set_route_group (RouteGroup *rg)
1238 {
1239         _route->set_route_group (rg, this);
1240 }
1241
1242 bool
1243 MixerStrip::select_route_group (GdkEventButton *ev)
1244 {
1245         using namespace Menu_Helpers;
1246
1247         if (ev->button == 1) {
1248
1249                 if (group_menu == 0) {
1250                         
1251                         group_menu = new RouteGroupMenu (
1252                                 _session,
1253                                 (RouteGroup::Property) (RouteGroup::Gain | RouteGroup::Mute | RouteGroup::Solo)
1254                                 );
1255                         
1256                         group_menu->GroupSelected.connect (mem_fun (*this, &MixerStrip::set_route_group));
1257                 }
1258
1259                 group_menu->popup (1, ev->time);
1260         }
1261         
1262         return true;
1263 }       
1264
1265 void
1266 MixerStrip::route_group_changed (void *ignored)
1267 {
1268         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_group_changed), ignored));
1269         
1270         RouteGroup *rg = _route->route_group();
1271
1272         if (rg) {
1273                 /* XXX: this needs a better algorithm */
1274                 string truncated = rg->name ();
1275                 if (truncated.length () > 5) {
1276                         truncated = truncated.substr (0, 5);
1277                 }
1278                 group_label.set_text (truncated);
1279         } else {
1280                 switch (_width) {
1281                 case Wide:
1282                         group_label.set_text (_("Grp"));
1283                         break;
1284                 case Narrow:
1285                         group_label.set_text (_("~G"));
1286                         break;
1287                 }
1288         }
1289 }
1290
1291
1292 void 
1293 MixerStrip::route_gui_changed (string what_changed, void* ignored)
1294 {
1295         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_gui_changed), what_changed, ignored));
1296         
1297         if (what_changed == "color") {
1298                 if (set_color_from_route () == 0) {
1299                         show_route_color ();
1300                 }
1301         }
1302 }
1303
1304 void
1305 MixerStrip::show_route_color ()
1306 {
1307         name_button.modify_bg (STATE_NORMAL, color());
1308         top_event_box.modify_bg (STATE_NORMAL, color());
1309         route_active_changed ();
1310 }
1311
1312 void
1313 MixerStrip::show_passthru_color ()
1314 {
1315         route_active_changed ();
1316 }
1317
1318 void
1319 MixerStrip::build_route_ops_menu ()
1320 {
1321         using namespace Menu_Helpers;
1322         route_ops_menu = new Menu;
1323         route_ops_menu->set_name ("ArdourContextMenu");
1324
1325         MenuList& items = route_ops_menu->items();
1326
1327         items.push_back (MenuElem (_("Save As Template"), mem_fun(*this, &RouteUI::save_as_template)));
1328         items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteUI::route_rename)));
1329         rename_menu_item = &items.back();
1330         items.push_back (SeparatorElem());
1331         items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
1332         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1333         route_active_menu_item->set_active (_route->active());
1334
1335         items.push_back (SeparatorElem());
1336
1337         items.push_back (MenuElem (_("Adjust latency"), mem_fun (*this, &RouteUI::adjust_latency)));
1338
1339         items.push_back (SeparatorElem());
1340         items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
1341         polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1342         polarity_menu_item->set_active (_route->phase_invert());
1343         items.push_back (CheckMenuElem (_("Protect against denormals"), mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1344         denormal_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1345         denormal_menu_item->set_active (_route->denormal_protection());
1346
1347         if (!Profile->get_sae()) {
1348                 items.push_back (SeparatorElem());
1349                 items.push_back (MenuElem (_("Remote Control ID..."), mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
1350         }
1351
1352         items.push_back (SeparatorElem());
1353         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
1354 }
1355
1356 gint
1357 MixerStrip::name_button_button_press (GdkEventButton* ev)
1358 {
1359         if (ev->button == 1 || ev->button == 3) {
1360                 list_route_operations ();
1361
1362                 /* do not allow rename if the track is record-enabled */
1363                 rename_menu_item->set_sensitive (!_route->record_enabled());
1364                 route_ops_menu->popup (1, ev->time);
1365         }
1366         return FALSE;
1367 }
1368
1369 void
1370 MixerStrip::list_route_operations ()
1371 {
1372         if (route_ops_menu == 0) {
1373                 build_route_ops_menu ();
1374         }
1375 }
1376
1377 void
1378 MixerStrip::set_selected (bool yn)
1379 {
1380         AxisView::set_selected (yn);
1381         if (_selected) {
1382                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1383                 global_frame.set_name ("MixerStripSelectedFrame");
1384         } else {
1385                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1386                 global_frame.set_name ("MixerStripFrame");
1387         }
1388         global_frame.queue_draw ();
1389 }
1390
1391 void
1392 MixerStrip::name_changed ()
1393 {
1394         switch (_width) {
1395         case Wide:
1396                 RouteUI::name_changed ();
1397                 break;
1398         case Narrow:
1399                 name_label.set_text (PBD::short_version (_route->name(), 5));
1400                 break;
1401         }
1402         if (_route->phase_invert()) {
1403                 name_label.set_text (X_("Ø ") + name_label.get_text());
1404         }
1405 }
1406
1407 void
1408 MixerStrip::width_clicked ()
1409 {
1410         switch (_width) {
1411         case Wide:
1412                 set_width_enum (Narrow, this);
1413                 break;
1414         case Narrow:
1415                 set_width_enum (Wide, this);
1416                 break;
1417         }
1418 }
1419
1420 void
1421 MixerStrip::hide_clicked ()
1422 {
1423         // LAME fix to reset the button status for when it is redisplayed (part 1)
1424         hide_button.set_sensitive(false);
1425         
1426         if (_embedded) {
1427                 Hiding(); /* EMIT_SIGNAL */
1428         } else {
1429                 _mixer.hide_strip (this);
1430         }
1431         
1432         // (part 2)
1433         hide_button.set_sensitive(true);
1434 }
1435
1436 void
1437 MixerStrip::set_embedded (bool yn)
1438 {
1439         _embedded = yn;
1440 }
1441
1442 void
1443 MixerStrip::map_frozen ()
1444 {
1445         ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::map_frozen));
1446
1447         boost::shared_ptr<AudioTrack> at = audio_track();
1448
1449         if (at) {
1450                 switch (at->freeze_state()) {
1451                 case AudioTrack::Frozen:
1452                         processor_box.set_sensitive (false);
1453                         break;
1454                 default:
1455                         processor_box.set_sensitive (true);
1456                         // XXX need some way, maybe, to retoggle redirect editors
1457                         break;
1458                 }
1459         }
1460         
1461         hide_redirect_editors ();
1462 }
1463
1464 void
1465 MixerStrip::hide_redirect_editors ()
1466 {
1467         _route->foreach_processor (mem_fun (*this, &MixerStrip::hide_processor_editor));
1468 }
1469
1470 void
1471 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1472 {
1473         boost::shared_ptr<Processor> processor (p.lock ());
1474         if (!processor) {
1475                 return;
1476         }
1477         
1478         void* gui = processor->get_gui ();
1479         
1480         if (gui) {
1481                 static_cast<Gtk::Widget*>(gui)->hide ();
1482         }
1483 }
1484
1485 void
1486 MixerStrip::route_active_changed ()
1487 {
1488         RouteUI::route_active_changed ();
1489
1490         if (is_midi_track()) {
1491                 if (_route->active()) {
1492                         set_name ("MidiTrackStripBase");
1493                         gpm.set_meter_strip_name ("MidiTrackStripBase");
1494                 } else {
1495                         set_name ("MidiTrackStripBaseInactive");
1496                         gpm.set_meter_strip_name ("MidiTrackStripBaseInactive");
1497                 }
1498                 gpm.set_fader_name ("MidiTrackFader");
1499         } else if (is_audio_track()) {
1500                 if (_route->active()) {
1501                         set_name ("AudioTrackStripBase");
1502                         gpm.set_meter_strip_name ("AudioTrackMetrics");
1503                 } else {
1504                         set_name ("AudioTrackStripBaseInactive");
1505                         gpm.set_meter_strip_name ("AudioTrackMetricsInactive");
1506                 }
1507                 gpm.set_fader_name ("AudioTrackFader");
1508         } else {
1509                 if (_route->active()) {
1510                         set_name ("AudioBusStripBase");
1511                         gpm.set_meter_strip_name ("AudioBusMetrics");
1512                 } else {
1513                         set_name ("AudioBusStripBaseInactive");
1514                         gpm.set_meter_strip_name ("AudioBusMetricsInactive");
1515                 }
1516                 gpm.set_fader_name ("AudioBusFader");
1517                 
1518                 /* (no MIDI busses yet) */
1519         }
1520 }
1521
1522 RouteGroup*
1523 MixerStrip::route_group() const
1524 {
1525         return _route->route_group();
1526 }
1527
1528 void
1529 MixerStrip::engine_stopped ()
1530 {
1531 }
1532
1533 void
1534 MixerStrip::engine_running ()
1535 {
1536 }
1537
1538 void
1539 MixerStrip::meter_changed (void *src)
1540 {
1541         ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
1542
1543         switch (_route->meter_point()) {
1544         case MeterInput:
1545                 meter_point_label.set_text (_("input"));
1546                 break;
1547
1548         case MeterPreFader:
1549                 meter_point_label.set_text (_("pre"));
1550                 break;
1551                 
1552         case MeterPostFader:
1553                 meter_point_label.set_text (_("post"));
1554                 break;
1555         }
1556
1557         gpm.setup_meters ();
1558         // reset peak when meter point changes
1559         gpm.reset_peak_display();
1560         set_width_enum (_width, this);
1561 }
1562
1563 void
1564 MixerStrip::switch_io (boost::shared_ptr<Route> target)
1565 {
1566         if (_route == target || _route->is_master()) {
1567                 /* don't change the display for the target or the master bus */
1568                 return;
1569         } else if (!is_track() && show_sends_button) {
1570                 /* make sure our show sends button is inactive, and we no longer blink,
1571                    since we're not the target.
1572                 */
1573                 send_blink_connection.disconnect ();
1574                 show_sends_button->set_active (false);
1575                 show_sends_button->set_state (STATE_NORMAL);
1576         }
1577
1578         if (!target) {
1579                 /* switch back to default */
1580                 revert_to_default_display ();
1581                 return;
1582         }
1583         
1584         boost::shared_ptr<Send> send;
1585
1586         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
1587                 send->set_metering (false);
1588         }
1589         
1590         _current_delivery = _route->internal_send_for (target);
1591
1592         cerr << "internal send from " << _route->name() << " to " << target->name() << " = " 
1593              << _current_delivery << endl;
1594
1595         if (_current_delivery) {
1596                 send = boost::dynamic_pointer_cast<Send>(_current_delivery);
1597                 send->set_metering (true);
1598                 _current_delivery->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display));
1599                 gain_meter().set_controls (_route, send->meter(), send->amp());
1600                 panner_ui().set_panner (_current_delivery->panner());
1601
1602         } else {
1603                 _current_delivery = _route->main_outs ();
1604                 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp());
1605                 panner_ui().set_panner (_route->main_outs()->panner());
1606         }
1607         
1608         gain_meter().setup_meters ();
1609         panner_ui().setup_pan ();
1610 }
1611
1612
1613 void
1614 MixerStrip::revert_to_default_display ()
1615 {
1616         show_sends_button->set_active (false);
1617         
1618         boost::shared_ptr<Send> send;
1619
1620         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
1621                 send->set_metering (false);
1622         }
1623         
1624         _current_delivery = _route->main_outs();
1625
1626         gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp());
1627         gain_meter().setup_meters ();
1628         panner_ui().set_panner (_route->main_outs()->panner());
1629         panner_ui().setup_pan ();
1630 }
1631
1632 void
1633 MixerStrip::set_button_names ()
1634 {
1635         switch (_width) {
1636         case Wide:
1637                 rec_enable_button_label.set_text (_("Rec"));
1638                 mute_button_label.set_text (_("Mute"));
1639                 if (!Config->get_solo_control_is_listen_control()) {
1640                         solo_button_label.set_text (_("Solo"));
1641                 } else {
1642                         switch (Config->get_listen_position()) {
1643                         case AfterFaderListen:
1644                                 solo_button_label.set_text (_("AFL"));
1645                                 break;
1646                         case PreFaderListen:
1647                                 solo_button_label.set_text (_("PFL"));
1648                                 break;
1649                         }
1650                 }
1651                 break;
1652
1653         default:
1654                 rec_enable_button_label.set_text (_("R"));
1655                 mute_button_label.set_text (_("M"));
1656                 if (!Config->get_solo_control_is_listen_control()) {
1657                         solo_button_label.set_text (_("S"));
1658                 } else {
1659                         switch (Config->get_listen_position()) {
1660                         case AfterFaderListen:
1661                                 solo_button_label.set_text (_("A"));
1662                                 break;
1663                         case PreFaderListen:
1664                                 solo_button_label.set_text (_("P"));
1665                                 break;
1666                         }
1667                 }
1668                 break;
1669                 
1670         }
1671 }
1672
1673 bool
1674 MixerStrip::on_key_press_event (GdkEventKey* ev)
1675 {
1676         GdkEventButton fake;
1677         fake.type = GDK_BUTTON_PRESS;
1678         fake.button = 1;
1679         fake.state = ev->state;
1680
1681         switch (ev->keyval) {
1682         case GDK_m:
1683                 mute_press (&fake);
1684                 return true;
1685                 break;
1686                 
1687         case GDK_s:
1688                 solo_press (&fake);
1689                 return true;
1690                 break;
1691                 
1692         case GDK_r:
1693                 rec_enable_press (&fake);
1694                 return true;
1695                 break;
1696                 
1697         case GDK_e:
1698                 show_sends_press (&fake);
1699                 return true;
1700                 break;                  
1701                 
1702         case GDK_g:
1703                 if (ev->state & Keyboard::PrimaryModifier) {
1704                         step_gain_down ();
1705                 } else {
1706                         step_gain_up ();
1707                 }
1708                 return true;
1709                 break;
1710
1711         case GDK_0:
1712                 if (_route) {
1713                         _route->set_gain (1.0, this);
1714                 }
1715                 return true;
1716                 
1717         default:
1718                 break;
1719         }
1720
1721         return false;
1722 }
1723
1724
1725 bool
1726 MixerStrip::on_key_release_event (GdkEventKey* ev)
1727 {
1728         GdkEventButton fake;
1729         fake.type = GDK_BUTTON_RELEASE;
1730         fake.button = 1;
1731         fake.state = ev->state;
1732
1733         switch (ev->keyval) {
1734         case GDK_m:
1735                 mute_release (&fake);
1736                 return true;
1737                 break;
1738                 
1739         case GDK_s:
1740                 solo_release (&fake);
1741                 return true;
1742                 break;
1743                 
1744         case GDK_r:
1745                 rec_enable_release (&fake);
1746                 return true;
1747                 break;
1748                 
1749         case GDK_e:
1750                 show_sends_release (&fake);
1751                 return true;
1752                 break;                  
1753                 
1754         case GDK_g:
1755                 return true;
1756                 break;
1757                 
1758         default:
1759                 break;
1760         }
1761
1762         return false;
1763 }
1764
1765 bool
1766 MixerStrip::on_enter_notify_event (GdkEventCrossing*)
1767 {
1768         Keyboard::magic_widget_grab_focus ();
1769         grab_focus ();
1770         return false;
1771 }
1772
1773 bool
1774 MixerStrip::on_leave_notify_event (GdkEventCrossing* ev)
1775 {
1776         switch (ev->detail) {
1777         case GDK_NOTIFY_INFERIOR:
1778                 break;
1779         default:
1780                 Keyboard::magic_widget_drop_focus ();
1781         }
1782
1783         return false;
1784 }