i/o button naming patch and imported file BWF timecode retention patch from nickm...
[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->show();
373
374         } else if (!is_track()) {
375                 /* non-master bus */
376
377                 if (!_route->is_master()) {
378                         button_table.attach (*show_sends_button, 0, 2, 2, 3);
379                         show_sends_button->show();
380                 }
381         }
382
383         if (_route->phase_invert()) {
384                 name_label.set_text (X_("Ø ") + name_label.get_text());
385         } else {
386                 name_label.set_text (_route->name());
387         }
388
389         switch (_route->meter_point()) {
390         case MeterInput:
391                 meter_point_label.set_text (_("input"));
392                 break;
393                 
394         case MeterPreFader:
395                 meter_point_label.set_text (_("pre"));
396                 break;
397                 
398         case MeterPostFader:
399                 meter_point_label.set_text (_("post"));
400                 break;
401         }
402
403         delete route_ops_menu;
404         route_ops_menu = 0;
405         
406         ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment().empty() ?
407                                                    _("Click to Add/Edit Comments"):
408                                                    _route->comment());
409
410         connections.push_back (_route->meter_change.connect (
411                         mem_fun(*this, &MixerStrip::meter_changed)));
412         connections.push_back (_route->input()->changed.connect (
413                         mem_fun(*this, &MixerStrip::input_changed)));
414         connections.push_back (_route->output()->changed.connect (
415                         mem_fun(*this, &MixerStrip::output_changed)));
416         connections.push_back (_route->route_group_changed.connect (
417                         mem_fun(*this, &MixerStrip::route_group_changed)));
418
419         if (_route->panner()) {
420                 connections.push_back (_route->panner()->Changed.connect (
421                         mem_fun(*this, &MixerStrip::connect_to_pan)));
422         }
423
424         if (is_audio_track()) {
425                 connections.push_back (audio_track()->DiskstreamChanged.connect (
426                         mem_fun(*this, &MixerStrip::diskstream_changed)));
427         }
428
429         connections.push_back (_route->NameChanged.connect (
430                         mem_fun(*this, &RouteUI::name_changed)));
431         connections.push_back (_route->comment_changed.connect (
432                         mem_fun(*this, &MixerStrip::comment_changed)));
433         connections.push_back (_route->gui_changed.connect (
434                         mem_fun(*this, &MixerStrip::route_gui_changed)));
435
436         set_stuff_from_route ();
437
438         /* now force an update of all the various elements */
439
440         processor_box.update();
441         mute_changed (0);
442         solo_changed (0);
443         name_changed ();
444         comment_changed (0);
445         route_group_changed (0);
446
447         connect_to_pan ();
448
449         panners.setup_pan ();
450
451         update_diskstream_display ();
452         update_input_display ();
453         update_output_display ();
454
455         add_events (Gdk::BUTTON_RELEASE_MASK);
456
457         processor_box.show();
458
459         if (!route()->is_master() && !route()->is_control()) {
460                 /* we don't allow master or control routes to be hidden */
461                 hide_button.show();
462         }
463
464         width_button.show();
465         width_hide_box.show();
466         whvbox.show ();
467         global_frame.show();
468         global_vpacker.show();
469         button_table.show();
470         middle_button_table.show();
471         bottom_button_table.show();
472         processor_box.show_all ();
473         gpm.show_all ();
474         panners.show_all ();
475         gain_meter_alignment.show ();
476         gain_unit_button.show();
477         gain_unit_label.show();
478         meter_point_button.show();
479         meter_point_label.show();
480         diskstream_button.show();
481         diskstream_label.show();
482         input_button.show();
483         input_label.show();
484         output_button.show();
485         output_label.show();
486         name_label.show();
487         name_button.show();
488         comment_button.show();
489         group_button.show();
490         group_label.show();
491
492         show ();
493 }
494
495 void
496 MixerStrip::set_stuff_from_route ()
497 {
498         XMLProperty *prop;
499
500         ensure_xml_node ();
501
502         /* if width is not set, it will be set by the MixerUI or editor */
503
504         if ((prop = xml_node->property ("strip-width")) != 0) {
505                 set_width_enum (Width (string_2_enum (prop->value(), _width)), this);
506         }
507
508         if ((prop = xml_node->property ("shown-mixer")) != 0) {
509                 if (prop->value() == "no") {
510                         _marked_for_display = false;
511                 } else {
512                         _marked_for_display = true;
513                 }
514         } else {
515                 /* backwards compatibility */
516                 _marked_for_display = true;
517         }
518 }
519
520 void
521 MixerStrip::set_width_enum (Width w, void* owner)
522 {
523         /* always set the gpm width again, things may be hidden */
524
525         gpm.set_width (w);
526         panners.set_width (w);
527         processor_box.set_width (w);
528
529         boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
530
531         _width_owner = owner;
532
533         ensure_xml_node ();
534         
535         _width = w;
536
537         if (_width_owner == this) {
538                 xml_node->add_property ("strip-width", enum_2_string (_width));
539         }
540
541         set_button_names ();
542
543         switch (w) {
544         case Wide:
545                 if (show_sends_button)  {
546                         ((Gtk::Label*)show_sends_button->get_child())->set_text (_("Sends"));
547                 }
548
549                 if (_route->comment() == "") {
550                         comment_button.unset_bg (STATE_NORMAL);
551                         ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
552                 } else {
553                         comment_button.modify_bg (STATE_NORMAL, color());
554                         ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
555                 }
556
557                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
558                                 gpm.astyle_string(gain_automation->automation_style()));
559                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
560                                 gpm.astate_string(gain_automation->automation_state()));
561
562                 if (_route->panner()) {
563                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
564                                         panners.astyle_string(_route->panner()->automation_style()));
565                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
566                                         panners.astate_string(_route->panner()->automation_state()));
567                 }
568
569                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
570                 set_size_request (-1, -1);
571                 break;
572
573         case Narrow:
574                 if (show_sends_button) {
575                         ((Gtk::Label*)show_sends_button->get_child())->set_text (_("Snd"));
576                 }
577
578                 if (_route->comment() == "") {
579                        comment_button.unset_bg (STATE_NORMAL);
580                        ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
581                 } else {
582                        comment_button.modify_bg (STATE_NORMAL, color());
583                        ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
584                 }
585
586                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
587                                 gpm.short_astyle_string(gain_automation->automation_style()));
588                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
589                                 gpm.short_astate_string(gain_automation->automation_state()));
590                 
591                 if (_route->panner()) {
592                         ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
593                         panners.short_astyle_string(_route->panner()->automation_style()));
594                         ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
595                         panners.short_astate_string(_route->panner()->automation_state()));
596                 }
597
598                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
599                 set_size_request (max (50, gpm.get_gm_width()), -1);
600                 break;
601         }
602         update_input_display ();
603         update_output_display ();
604         route_group_changed (0);
605         name_changed ();
606         WidthChanged ();
607 }
608
609 void
610 MixerStrip::set_packed (bool yn)
611 {
612         _packed = yn;
613
614         ensure_xml_node ();
615
616         if (_packed) {
617                 xml_node->add_property ("shown-mixer", "yes");
618         } else {
619                 xml_node->add_property ("shown-mixer", "no");
620         }
621 }
622
623
624 gint
625 MixerStrip::output_press (GdkEventButton *ev)
626 {
627         using namespace Menu_Helpers;
628         if (!_session.engine().connected()) {
629                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
630                 msg.run ();
631                 return true;
632         }
633
634         MenuList& citems = output_menu.items();
635         switch (ev->button) {
636
637         case 1:
638                 edit_output_configuration ();
639                 break;
640                 
641         case 3:
642         {
643                 output_menu.set_name ("ArdourContextMenu");
644                 citems.clear();
645                 
646                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
647                 citems.push_back (SeparatorElem());
648
649                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
650
651                 boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
652                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
653                         maybe_add_bundle_to_output_menu (*i, current);
654                 }
655
656                 boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
657                 for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
658                         maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
659                 }
660
661                 if (citems.size() == 2) {
662                         /* no routes added; remove the separator */
663                         citems.pop_back ();
664                 }
665
666                 output_menu.popup (1, ev->time);
667                 break;
668         }
669
670         default:
671                 break;
672         }
673         return TRUE;
674 }
675
676 void
677 MixerStrip::edit_output_configuration ()
678 {
679         if (output_selector == 0) {
680                 output_selector = new IOSelectorWindow (_session, _route->output());
681         } 
682
683         if (output_selector->is_visible()) {
684                 output_selector->get_toplevel()->get_window()->raise();
685         } else {
686                 output_selector->present ();
687         }
688 }
689
690 void
691 MixerStrip::edit_input_configuration ()
692 {
693         if (input_selector == 0) {
694                 input_selector = new IOSelectorWindow (_session, _route->input());
695         } 
696
697         if (input_selector->is_visible()) {
698                 input_selector->get_toplevel()->get_window()->raise();
699         } else {
700                 input_selector->present ();
701         }
702 }
703
704 gint
705 MixerStrip::input_press (GdkEventButton *ev)
706 {
707         using namespace Menu_Helpers;
708
709         MenuList& citems = input_menu.items();
710         input_menu.set_name ("ArdourContextMenu");
711         citems.clear();
712         
713         if (!_session.engine().connected()) {
714                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
715                 msg.run ();
716                 return true;
717         }
718
719         switch (ev->button) {
720
721         case 1:
722                 edit_input_configuration ();
723                 break;
724
725         case 3:
726         {
727                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
728                 citems.push_back (SeparatorElem());
729
730                 ARDOUR::BundleList current = _route->input()->bundles_connected ();
731
732                 boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
733                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
734                         maybe_add_bundle_to_input_menu (*i, current);
735                 }
736
737                 boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
738                 for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
739                         maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
740                 }
741
742                 if (citems.size() == 2) {
743                         /* no routes added; remove the separator */
744                         citems.pop_back ();
745                 }
746
747                 input_menu.popup (1, ev->time);
748                 break;
749         }
750         default:
751                 break;
752         }
753         return TRUE;
754 }
755
756 void
757 MixerStrip::bundle_input_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
758 {
759         if (ignore_toggle) {
760                 return;
761         }
762
763         ARDOUR::BundleList current = _route->input()->bundles_connected ();
764
765         if (std::find (current.begin(), current.end(), c) == current.end()) {
766                 _route->input()->connect_ports_to_bundle (c, this);
767         } else {
768                 _route->input()->disconnect_ports_from_bundle (c, this);
769         }
770 }
771
772 void
773 MixerStrip::bundle_output_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
774 {
775         if (ignore_toggle) {
776                 return;
777         }
778
779         ARDOUR::BundleList current = _route->output()->bundles_connected ();
780
781         if (std::find (current.begin(), current.end(), c) == current.end()) {
782                 _route->output()->connect_ports_to_bundle (c, this);
783         } else {
784                 _route->output()->disconnect_ports_from_bundle (c, this);
785         }
786 }
787
788 void
789 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
790 {
791         using namespace Menu_Helpers;
792
793         if (b->ports_are_outputs() == false ||
794             route()->input()->default_type() != b->type() ||
795             b->nchannels() != _route->n_inputs().get (b->type ())) {
796                 
797                 return;
798         }
799
800         MenuList& citems = input_menu.items();
801         
802         std::string n = b->name ();
803         replace_all (n, "_", " ");
804         
805         citems.push_back (CheckMenuElem (n, bind (mem_fun(*this, &MixerStrip::bundle_input_toggled), b)));
806         
807         if (std::find (current.begin(), current.end(), b) != current.end()) {
808                 ignore_toggle = true;
809                 dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
810                 ignore_toggle = false;
811         }
812 }
813
814 void
815 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
816 {
817         using namespace Menu_Helpers;
818
819         if (b->ports_are_inputs() == false ||
820             route()->output()->default_type() != b->type() ||
821             b->nchannels() != _route->n_outputs().get (b->type ())) {
822                 
823                 return;
824         }
825
826         MenuList& citems = output_menu.items();
827         
828         std::string n = b->name ();
829         replace_all (n, "_", " ");
830         
831         citems.push_back (CheckMenuElem (n, bind (mem_fun(*this, &MixerStrip::bundle_output_toggled), b)));
832         
833         if (std::find (current.begin(), current.end(), b) != current.end()) {
834                 ignore_toggle = true;
835                 dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
836                 ignore_toggle = false;
837         }
838 }
839
840 void
841 MixerStrip::update_diskstream_display ()
842 {
843         if (is_track()) {
844
845                 if (input_selector) {
846                         input_selector->hide_all ();
847                 }
848
849                 show_route_color ();
850
851         } else {
852
853                 show_passthru_color ();
854         }
855 }
856
857 void
858 MixerStrip::connect_to_pan ()
859 {
860         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::connect_to_pan));
861
862         panstate_connection.disconnect ();
863         panstyle_connection.disconnect ();
864
865         if (!_route->panner()) {
866                 return;
867         }
868
869         boost::shared_ptr<ARDOUR::AutomationControl> pan_control
870                 = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
871                                 _route->panner()->data().control(Evoral::Parameter(PanAutomation)));
872
873         if (pan_control) {
874                 panstate_connection = pan_control->alist()->automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed));
875                 panstyle_connection = pan_control->alist()->automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed));
876         }
877
878         panners.pan_changed (this);
879 }
880
881
882 /*
883  * Output port labelling
884  * =====================
885  * 
886  * Case 1: Each output has one connection, all connections are to system:playback_%i
887  *   out 1 -> system:playback_1
888  *   out 2 -> system:playback_2
889  *   out 3 -> system:playback_3
890  *   Display as: 1/2/3
891  *
892  * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
893  *   out 1 -> ardour:track_x/in 1
894  *   out 2 -> ardour:track_x/in 2
895  *   Display as: track_x
896  * 
897  * Case 3: Each output has one connection, all connections are to Jack client "program x"
898  *   out 1 -> program x:foo
899  *   out 2 -> program x:foo
900  *   Display as: program x
901  *
902  * Case 4: No connections (Disconnected)
903  *   Display as: -
904  * 
905  * Default case (unusual routing):
906  *   Display as: *number of connections*
907  *
908  * Tooltips
909  * ========
910  * .-----------------------------------------------.
911  * | Mixdown                                       |
912  * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
913  * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
914  * '-----------------------------------------------'
915  * .-----------------------------------------------.
916  * | Guitar SM58                                   |
917  * | Disconnected                                  |
918  * '-----------------------------------------------'
919  */
920
921 void
922 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
923 {
924         uint32_t io_count;
925         uint32_t io_index;
926         Port *port;
927         vector<string> connections;
928         
929         uint32_t connection_index;
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 (connection_index == 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                                                 ardour_track_name = connection_name.substr(0, connection_name.find("/") + 1);
984                                         }
985                                         
986                                         if (connection_name.find(ardour_track_name) == 0) {
987                                                 ++ardour_connection_count;
988                                         }
989                                 } else if (connection_name.find("system:") == 0) {
990                                         if (for_input) {
991                                                 // "system:capture_123" -> "123"
992                                                 system_port = connection_name.substr(15);
993                                         } else {
994                                                 // "system:playback_123" -> "123"
995                                                 system_port = connection_name.substr(16);
996                                         }
997                                         
998                                         if (system_ports.empty()) {
999                                                 system_ports += system_port;
1000                                         } else {
1001                                                 system_ports += "/" + system_port;
1002                                         }
1003                                         
1004                                         ++system_connection_count;
1005                                 } else {
1006                                         if (other_connection_type.empty()) {
1007                                                 // "jamin:in 1" -> "jamin:"
1008                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1009                                         }
1010                                         
1011                                         if (connection_name.find(other_connection_type) == 0) {
1012                                                 ++other_connection_count;
1013                                         }
1014                                 }
1015                                 
1016                                 ++total_connection_count;
1017                                 ++io_connection_count;
1018                         }
1019                 } 
1020                 
1021                 if (io_connection_count != 1) {
1022                         each_io_has_one_connection = false;
1023                 }
1024         }
1025         
1026         if (total_connection_count == 0) {
1027                 tooltip << endl << _("Disconnected");
1028         }
1029         
1030         tooltip_cstr = new char[tooltip.str().size() + 1];
1031         strcpy(tooltip_cstr, tooltip.str().c_str());
1032         
1033         if (for_input) {
1034                 ARDOUR_UI::instance()->set_tip (&input_button, tooltip_cstr, "");
1035         } else {
1036                 ARDOUR_UI::instance()->set_tip (&output_button, tooltip_cstr, "");
1037         }  
1038         
1039         if (each_io_has_one_connection) {
1040                 if ((total_connection_count == ardour_connection_count)) {
1041                         // all connections are to the same track in ardour
1042                         // "ardour:Master/" -> "Master"
1043                         label << ardour_track_name.substr(7, ardour_track_name.find("/") - 7);
1044                         have_label = true;
1045                 }
1046                 else if (total_connection_count == system_connection_count) {
1047                         // all connections are to system ports
1048                         label << system_ports;
1049                         have_label = true;
1050                 }
1051                 else if (total_connection_count == other_connection_count) {
1052                         // all connections are to the same external program eg jamin
1053                         // "jamin:" -> "jamin"
1054                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1055                         have_label = true;
1056                 }
1057         }
1058         
1059         if (!have_label) {
1060                 if (total_connection_count == 0) {
1061                         // Disconnected
1062                         label << "-";
1063                 } else {
1064                         // Odd configuration
1065                         label << "*" << total_connection_count << "*";
1066                 }
1067         }
1068         
1069         switch (width) {
1070         case Wide:
1071                 label_string = label.str().substr(0, 6);
1072                 break;
1073         case Narrow:
1074                 label_string = label.str().substr(0, 3);
1075                 break;
1076         }
1077         
1078         label_cstr = new char[label_string.size() + 1];
1079         strcpy(label_cstr, label_string.c_str());
1080         
1081         if (for_input) {
1082                 input_label.set_text (label_cstr);
1083         } else {
1084                 output_label.set_text (label_cstr);
1085         }
1086 }
1087
1088 void
1089 MixerStrip::update_input_display ()
1090 {
1091         update_io_button (_route, _width, true);
1092         panners.setup_pan ();
1093 }
1094
1095 void
1096 MixerStrip::update_output_display ()
1097 {
1098         update_io_button (_route, _width, false);
1099         gpm.setup_meters ();
1100         panners.setup_pan ();
1101 }
1102
1103 void
1104 MixerStrip::fast_update ()
1105 {
1106         gpm.update_meters ();
1107 }
1108
1109 void
1110 MixerStrip::diskstream_changed ()
1111 {
1112         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display));
1113 }       
1114
1115 void
1116 MixerStrip::input_changed (IOChange /*change*/, void */*src*/)
1117 {
1118         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_input_display));
1119         set_width_enum (_width, this);
1120 }
1121
1122 void
1123 MixerStrip::output_changed (IOChange /*change*/, void */*src*/)
1124 {
1125         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_output_display));
1126         set_width_enum (_width, this);
1127 }
1128
1129
1130 void 
1131 MixerStrip::comment_editor_done_editing() 
1132 {
1133         string str =  comment_area->get_buffer()->get_text();
1134         if (_route->comment() != str) {
1135                 _route->set_comment (str, this);
1136
1137                 switch (_width) {
1138                    
1139                 case Wide:
1140                         if (! str.empty()) {
1141                                 comment_button.modify_bg (STATE_NORMAL, color());
1142                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
1143                         } else {
1144                                 comment_button.unset_bg (STATE_NORMAL);
1145                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
1146                         }
1147                         break;
1148                    
1149                 case Narrow:
1150                         if (! str.empty()) {
1151                                 comment_button.modify_bg (STATE_NORMAL, color());
1152                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
1153                         } else {
1154                                 comment_button.unset_bg (STATE_NORMAL);
1155                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
1156                         } 
1157                         break;
1158                 }
1159                  
1160                 ARDOUR_UI::instance()->tooltips().set_tip (comment_button, 
1161                                 str.empty() ? _("Click to Add/Edit Comments") : str);
1162         }
1163
1164 }
1165
1166 void
1167 MixerStrip::comment_button_clicked ()
1168 {
1169         if (comment_window == 0) {
1170                 setup_comment_editor ();
1171         }
1172
1173     int x, y, cw_width, cw_height;
1174
1175         if (comment_window->is_visible()) {
1176                 comment_window->hide ();
1177                 return;
1178         }
1179
1180         comment_window->get_size (cw_width, cw_height);
1181         comment_window->get_position(x, y);
1182         comment_window->move(x, y - (cw_height / 2) - 45);
1183         /* 
1184            half the dialog height minus the comments button height 
1185            with some window decoration fudge thrown in.
1186         */
1187
1188         comment_window->show();
1189         comment_window->present();
1190 }
1191
1192 void
1193 MixerStrip::setup_comment_editor ()
1194 {
1195         string title;
1196         title = _route->name();
1197         title += _(": comment editor");
1198
1199         comment_window = new ArdourDialog (title, false);
1200         comment_window->set_position (Gtk::WIN_POS_MOUSE);
1201         comment_window->set_skip_taskbar_hint (true);
1202         comment_window->signal_hide().connect (mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1203
1204         comment_area = manage (new TextView());
1205         comment_area->set_name ("MixerTrackCommentArea");
1206         comment_area->set_size_request (110, 178);
1207         comment_area->set_wrap_mode (WRAP_WORD);
1208         comment_area->set_editable (true);
1209         comment_area->get_buffer()->set_text (_route->comment());
1210         comment_area->show ();
1211
1212         comment_window->get_vbox()->pack_start (*comment_area);
1213         comment_window->get_action_area()->hide();
1214 }
1215
1216 void
1217 MixerStrip::comment_changed (void *src)
1218 {
1219         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::comment_changed), src));
1220         
1221         if (src != this) {
1222                 ignore_comment_edit = true;
1223                 if (comment_area) {
1224                         comment_area->get_buffer()->set_text (_route->comment());
1225                 }
1226                 ignore_comment_edit = false;
1227         }
1228 }
1229
1230 void
1231 MixerStrip::set_route_group (RouteGroup *rg)
1232 {
1233         _route->set_route_group (rg, this);
1234 }
1235
1236 bool
1237 MixerStrip::select_route_group (GdkEventButton *ev)
1238 {
1239         using namespace Menu_Helpers;
1240
1241         if (ev->button == 1) {
1242
1243                 if (group_menu == 0) {
1244                         
1245                         group_menu = new RouteGroupMenu (
1246                                 _session,
1247                                 (RouteGroup::Property) (RouteGroup::Gain | RouteGroup::Mute | RouteGroup::Solo)
1248                                 );
1249                         
1250                         group_menu->GroupSelected.connect (mem_fun (*this, &MixerStrip::set_route_group));
1251                 }
1252
1253                 group_menu->popup (1, ev->time);
1254         }
1255         
1256         return true;
1257 }       
1258
1259 void
1260 MixerStrip::route_group_changed (void *ignored)
1261 {
1262         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_group_changed), ignored));
1263         
1264         RouteGroup *rg = _route->route_group();
1265
1266         if (rg) {
1267                 /* XXX: this needs a better algorithm */
1268                 string truncated = rg->name ();
1269                 if (truncated.length () > 5) {
1270                         truncated = truncated.substr (0, 5);
1271                 }
1272                 group_label.set_text (truncated);
1273         } else {
1274                 switch (_width) {
1275                 case Wide:
1276                         group_label.set_text (_("Grp"));
1277                         break;
1278                 case Narrow:
1279                         group_label.set_text (_("~G"));
1280                         break;
1281                 }
1282         }
1283 }
1284
1285
1286 void 
1287 MixerStrip::route_gui_changed (string what_changed, void* ignored)
1288 {
1289         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_gui_changed), what_changed, ignored));
1290         
1291         if (what_changed == "color") {
1292                 if (set_color_from_route () == 0) {
1293                         show_route_color ();
1294                 }
1295         }
1296 }
1297
1298 void
1299 MixerStrip::show_route_color ()
1300 {
1301         name_button.modify_bg (STATE_NORMAL, color());
1302         top_event_box.modify_bg (STATE_NORMAL, color());
1303         route_active_changed ();
1304 }
1305
1306 void
1307 MixerStrip::show_passthru_color ()
1308 {
1309         route_active_changed ();
1310 }
1311
1312 void
1313 MixerStrip::build_route_ops_menu ()
1314 {
1315         using namespace Menu_Helpers;
1316         route_ops_menu = new Menu;
1317         route_ops_menu->set_name ("ArdourContextMenu");
1318
1319         MenuList& items = route_ops_menu->items();
1320
1321         items.push_back (MenuElem (_("Save As Template"), mem_fun(*this, &RouteUI::save_as_template)));
1322         items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteUI::route_rename)));
1323         rename_menu_item = &items.back();
1324         items.push_back (SeparatorElem());
1325         items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
1326         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1327         route_active_menu_item->set_active (_route->active());
1328
1329         items.push_back (SeparatorElem());
1330
1331         items.push_back (MenuElem (_("Adjust latency"), mem_fun (*this, &RouteUI::adjust_latency)));
1332
1333         items.push_back (SeparatorElem());
1334         items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
1335         polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1336         polarity_menu_item->set_active (_route->phase_invert());
1337         items.push_back (CheckMenuElem (_("Protect against denormals"), mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1338         denormal_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1339         denormal_menu_item->set_active (_route->denormal_protection());
1340
1341         if (!Profile->get_sae()) {
1342                 items.push_back (SeparatorElem());
1343                 items.push_back (MenuElem (_("Remote Control ID..."), mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
1344         }
1345
1346         items.push_back (SeparatorElem());
1347         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
1348 }
1349
1350 gint
1351 MixerStrip::name_button_button_press (GdkEventButton* ev)
1352 {
1353         if (ev->button == 1 || ev->button == 3) {
1354                 list_route_operations ();
1355
1356                 /* do not allow rename if the track is record-enabled */
1357                 rename_menu_item->set_sensitive (!_route->record_enabled());
1358                 route_ops_menu->popup (1, ev->time);
1359         }
1360         return FALSE;
1361 }
1362
1363 void
1364 MixerStrip::list_route_operations ()
1365 {
1366         if (route_ops_menu == 0) {
1367                 build_route_ops_menu ();
1368         }
1369 }
1370
1371 void
1372 MixerStrip::set_selected (bool yn)
1373 {
1374         AxisView::set_selected (yn);
1375         if (_selected) {
1376                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1377                 global_frame.set_name ("MixerStripSelectedFrame");
1378         } else {
1379                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1380                 global_frame.set_name ("MixerStripFrame");
1381         }
1382         global_frame.queue_draw ();
1383 }
1384
1385 void
1386 MixerStrip::name_changed ()
1387 {
1388         switch (_width) {
1389         case Wide:
1390                 RouteUI::name_changed ();
1391                 break;
1392         case Narrow:
1393                 name_label.set_text (PBD::short_version (_route->name(), 5));
1394                 break;
1395         }
1396         if (_route->phase_invert()) {
1397                 name_label.set_text (X_("Ø ") + name_label.get_text());
1398         }
1399 }
1400
1401 void
1402 MixerStrip::width_clicked ()
1403 {
1404         switch (_width) {
1405         case Wide:
1406                 set_width_enum (Narrow, this);
1407                 break;
1408         case Narrow:
1409                 set_width_enum (Wide, this);
1410                 break;
1411         }
1412 }
1413
1414 void
1415 MixerStrip::hide_clicked ()
1416 {
1417         // LAME fix to reset the button status for when it is redisplayed (part 1)
1418         hide_button.set_sensitive(false);
1419         
1420         if (_embedded) {
1421                 Hiding(); /* EMIT_SIGNAL */
1422         } else {
1423                 _mixer.hide_strip (this);
1424         }
1425         
1426         // (part 2)
1427         hide_button.set_sensitive(true);
1428 }
1429
1430 void
1431 MixerStrip::set_embedded (bool yn)
1432 {
1433         _embedded = yn;
1434 }
1435
1436 void
1437 MixerStrip::map_frozen ()
1438 {
1439         ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::map_frozen));
1440
1441         boost::shared_ptr<AudioTrack> at = audio_track();
1442
1443         if (at) {
1444                 switch (at->freeze_state()) {
1445                 case AudioTrack::Frozen:
1446                         processor_box.set_sensitive (false);
1447                         break;
1448                 default:
1449                         processor_box.set_sensitive (true);
1450                         // XXX need some way, maybe, to retoggle redirect editors
1451                         break;
1452                 }
1453         }
1454         
1455         hide_redirect_editors ();
1456 }
1457
1458 void
1459 MixerStrip::hide_redirect_editors ()
1460 {
1461         _route->foreach_processor (mem_fun (*this, &MixerStrip::hide_processor_editor));
1462 }
1463
1464 void
1465 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1466 {
1467         boost::shared_ptr<Processor> processor (p.lock ());
1468         if (!processor) {
1469                 return;
1470         }
1471         
1472         void* gui = processor->get_gui ();
1473         
1474         if (gui) {
1475                 static_cast<Gtk::Widget*>(gui)->hide ();
1476         }
1477 }
1478
1479 void
1480 MixerStrip::route_active_changed ()
1481 {
1482         RouteUI::route_active_changed ();
1483
1484         if (is_midi_track()) {
1485                 if (_route->active()) {
1486                         set_name ("MidiTrackStripBase");
1487                         gpm.set_meter_strip_name ("MidiTrackStripBase");
1488                 } else {
1489                         set_name ("MidiTrackStripBaseInactive");
1490                         gpm.set_meter_strip_name ("MidiTrackStripBaseInactive");
1491                 }
1492                 gpm.set_fader_name ("MidiTrackFader");
1493         } else if (is_audio_track()) {
1494                 if (_route->active()) {
1495                         set_name ("AudioTrackStripBase");
1496                         gpm.set_meter_strip_name ("AudioTrackMetrics");
1497                 } else {
1498                         set_name ("AudioTrackStripBaseInactive");
1499                         gpm.set_meter_strip_name ("AudioTrackMetricsInactive");
1500                 }
1501                 gpm.set_fader_name ("AudioTrackFader");
1502         } else {
1503                 if (_route->active()) {
1504                         set_name ("AudioBusStripBase");
1505                         gpm.set_meter_strip_name ("AudioBusMetrics");
1506                 } else {
1507                         set_name ("AudioBusStripBaseInactive");
1508                         gpm.set_meter_strip_name ("AudioBusMetricsInactive");
1509                 }
1510                 gpm.set_fader_name ("AudioBusFader");
1511                 
1512                 /* (no MIDI busses yet) */
1513         }
1514 }
1515
1516 RouteGroup*
1517 MixerStrip::route_group() const
1518 {
1519         return _route->route_group();
1520 }
1521
1522 void
1523 MixerStrip::engine_stopped ()
1524 {
1525 }
1526
1527 void
1528 MixerStrip::engine_running ()
1529 {
1530 }
1531
1532 void
1533 MixerStrip::meter_changed (void *src)
1534 {
1535         ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
1536
1537         switch (_route->meter_point()) {
1538         case MeterInput:
1539                 meter_point_label.set_text (_("input"));
1540                 break;
1541
1542         case MeterPreFader:
1543                 meter_point_label.set_text (_("pre"));
1544                 break;
1545                 
1546         case MeterPostFader:
1547                 meter_point_label.set_text (_("post"));
1548                 break;
1549         }
1550
1551         gpm.setup_meters ();
1552         // reset peak when meter point changes
1553         gpm.reset_peak_display();
1554         set_width_enum (_width, this);
1555 }
1556
1557 void
1558 MixerStrip::switch_io (boost::shared_ptr<Route> target)
1559 {
1560         if (_route == target || _route->is_master()) {
1561                 /* don't change the display for the target or the master bus */
1562                 return;
1563         } else if (!is_track() && show_sends_button) {
1564                 /* make sure our show sends button is inactive, and we no longer blink,
1565                    since we're not the target.
1566                 */
1567                 send_blink_connection.disconnect ();
1568                 show_sends_button->set_active (false);
1569                 show_sends_button->set_state (STATE_NORMAL);
1570         }
1571
1572         if (!target) {
1573                 /* switch back to default */
1574                 revert_to_default_display ();
1575                 return;
1576         }
1577         
1578         boost::shared_ptr<Send> send;
1579
1580         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
1581                 send->set_metering (false);
1582         }
1583         
1584         _current_delivery = _route->internal_send_for (target);
1585
1586         cerr << "internal send from " << _route->name() << " to " << target->name() << " = " 
1587              << _current_delivery << endl;
1588
1589         if (_current_delivery) {
1590                 send = boost::dynamic_pointer_cast<Send>(_current_delivery);
1591                 send->set_metering (true);
1592                 _current_delivery->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display));
1593                 gain_meter().set_controls (_route, send->meter(), send->amp());
1594                 panner_ui().set_panner (_current_delivery->panner());
1595
1596         } else {
1597                 _current_delivery = _route->main_outs ();
1598                 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp());
1599                 panner_ui().set_panner (_route->main_outs()->panner());
1600         }
1601         
1602         gain_meter().setup_meters ();
1603         panner_ui().setup_pan ();
1604 }
1605
1606
1607 void
1608 MixerStrip::revert_to_default_display ()
1609 {
1610         show_sends_button->set_active (false);
1611         
1612         boost::shared_ptr<Send> send;
1613
1614         if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
1615                 send->set_metering (false);
1616         }
1617         
1618         _current_delivery = _route->main_outs();
1619
1620         gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp());
1621         gain_meter().setup_meters ();
1622         panner_ui().set_panner (_route->main_outs()->panner());
1623         panner_ui().setup_pan ();
1624 }
1625
1626 void
1627 MixerStrip::set_button_names ()
1628 {
1629         switch (_width) {
1630         case Wide:
1631                 rec_enable_button_label.set_text (_("Rec"));
1632                 mute_button_label.set_text (_("Mute"));
1633                 if (!Config->get_solo_control_is_listen_control()) {
1634                         solo_button_label.set_text (_("Solo"));
1635                 } else {
1636                         switch (Config->get_listen_position()) {
1637                         case AfterFaderListen:
1638                                 solo_button_label.set_text (_("AFL"));
1639                                 break;
1640                         case PreFaderListen:
1641                                 solo_button_label.set_text (_("PFL"));
1642                                 break;
1643                         }
1644                 }
1645                 break;
1646
1647         default:
1648                 rec_enable_button_label.set_text (_("R"));
1649                 mute_button_label.set_text (_("M"));
1650                 if (!Config->get_solo_control_is_listen_control()) {
1651                         solo_button_label.set_text (_("S"));
1652                 } else {
1653                         switch (Config->get_listen_position()) {
1654                         case AfterFaderListen:
1655                                 solo_button_label.set_text (_("A"));
1656                                 break;
1657                         case PreFaderListen:
1658                                 solo_button_label.set_text (_("P"));
1659                                 break;
1660                         }
1661                 }
1662                 break;
1663                 
1664         }
1665 }
1666
1667 bool
1668 MixerStrip::on_key_press_event (GdkEventKey* ev)
1669 {
1670         GdkEventButton fake;
1671         fake.type = GDK_BUTTON_PRESS;
1672         fake.button = 1;
1673         fake.state = ev->state;
1674
1675         switch (ev->keyval) {
1676         case GDK_m:
1677                 mute_press (&fake);
1678                 return true;
1679                 break;
1680                 
1681         case GDK_s:
1682                 solo_press (&fake);
1683                 return true;
1684                 break;
1685                 
1686         case GDK_r:
1687                 rec_enable_press (&fake);
1688                 return true;
1689                 break;
1690                 
1691         case GDK_e:
1692                 show_sends_press (&fake);
1693                 return true;
1694                 break;                  
1695                 
1696         case GDK_g:
1697                 if (ev->state & Keyboard::PrimaryModifier) {
1698                         step_gain_down ();
1699                 } else {
1700                         step_gain_up ();
1701                 }
1702                 return true;
1703                 break;
1704
1705         case GDK_0:
1706                 if (_route) {
1707                         _route->set_gain (1.0, this);
1708                 }
1709                 return true;
1710                 
1711         default:
1712                 break;
1713         }
1714
1715         return false;
1716 }
1717
1718
1719 bool
1720 MixerStrip::on_key_release_event (GdkEventKey* ev)
1721 {
1722         GdkEventButton fake;
1723         fake.type = GDK_BUTTON_RELEASE;
1724         fake.button = 1;
1725         fake.state = ev->state;
1726
1727         switch (ev->keyval) {
1728         case GDK_m:
1729                 mute_release (&fake);
1730                 return true;
1731                 break;
1732                 
1733         case GDK_s:
1734                 solo_release (&fake);
1735                 return true;
1736                 break;
1737                 
1738         case GDK_r:
1739                 rec_enable_release (&fake);
1740                 return true;
1741                 break;
1742                 
1743         case GDK_e:
1744                 show_sends_release (&fake);
1745                 return true;
1746                 break;                  
1747                 
1748         case GDK_g:
1749                 return true;
1750                 break;
1751                 
1752         default:
1753                 break;
1754         }
1755
1756         return false;
1757 }
1758
1759 bool
1760 MixerStrip::on_enter_notify_event (GdkEventCrossing*)
1761 {
1762         Keyboard::magic_widget_grab_focus ();
1763         grab_focus ();
1764         return false;
1765 }
1766
1767 bool
1768 MixerStrip::on_leave_notify_event (GdkEventCrossing* ev)
1769 {
1770         switch (ev->detail) {
1771         case GDK_NOTIFY_INFERIOR:
1772                 break;
1773         default:
1774                 Keyboard::magic_widget_drop_focus ();
1775         }
1776
1777         return false;
1778 }