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