19b81ec4f94ecc28180e74dbe996d19ba450b462
[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
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
29 #include <gtkmm2ext/choice.h>
30 #include <gtkmm2ext/stop_signal.h>
31 #include <gtkmm2ext/doi.h>
32 #include <gtkmm2ext/slider_controller.h>
33 #include <gtkmm2ext/bindable_button.h>
34
35 #include <ardour/ardour.h>
36 #include <ardour/session.h>
37 #include <ardour/audioengine.h>
38 #include <ardour/route.h>
39 #include <ardour/audio_track.h>
40 #include <ardour/audio_diskstream.h>
41 #include <ardour/panner.h>
42 #include <ardour/send.h>
43 #include <ardour/processor.h>
44 #include <ardour/profile.h>
45 #include <ardour/ladspa_plugin.h>
46 #include <ardour/auto_bundle.h>
47 #include <ardour/user_bundle.h>
48
49 #include "ardour_ui.h"
50 #include "ardour_dialog.h"
51 #include "mixer_strip.h"
52 #include "mixer_ui.h"
53 #include "keyboard.h"
54 #include "public_editor.h"
55 #include "send_ui.h"
56 #include "io_selector.h"
57 #include "utils.h"
58 #include "gui_thread.h"
59
60 #include "i18n.h"
61
62 using namespace sigc;
63 using namespace ARDOUR;
64 using namespace PBD;
65 using namespace Gtk;
66 using namespace Gtkmm2ext;
67 using namespace std;
68
69 int MixerStrip::scrollbar_height = 0;
70
71 #ifdef VARISPEED_IN_MIXER_STRIP
72 static void 
73 speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
74 {
75         float val = adj.get_value ();
76
77         if (val == 1.0) {
78                 strcpy (buf, "1");
79         } else {
80                 snprintf (buf, 32, "%.3f", val);
81         }
82 }
83 #endif 
84
85 MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
86         : AxisView(sess),
87           RouteUI (rt, sess, _("Mute"), _("Solo"), _("Record")),
88           _mixer(mx),
89           pre_processor_box (PreFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
90           post_processor_box (PostFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
91           gpm (_route, sess),
92           panners (_route, sess),
93           button_table (3, 2),
94           middle_button_table (1, 2),
95           bottom_button_table (1, 2),
96           meter_point_label (_("pre")),
97           comment_button (_("Comments")),
98           speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1),
99           speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
100
101 {
102         if (set_color_from_route()) {
103                 set_color (unique_random_color());
104         }
105
106         input_selector = 0;
107         output_selector = 0;
108         group_menu = 0;
109         _marked_for_display = false;
110         route_ops_menu = 0;
111         ignore_comment_edit = false;
112         ignore_toggle = false;
113         ignore_speed_adjustment = false;
114         comment_window = 0;
115         comment_area = 0;
116         _width_owner = 0;
117
118         Gtk::Image *width_icon = manage (new Gtk::Image (::get_icon("strip_width")));
119         Gtk::Image *hide_icon = manage (new Gtk::Image (::get_icon("hide")));
120         width_button.add (*width_icon);
121         hide_button.add (*hide_icon);
122
123         input_label.set_text (_("Input"));
124         input_button.add (input_label);
125         input_button.set_name ("MixerIOButton");
126         input_label.set_name ("MixerIOButtonLabel");
127
128         output_label.set_text (_("Output"));
129         output_button.add (output_label);
130         output_button.set_name ("MixerIOButton");
131         output_label.set_name ("MixerIOButtonLabel");
132
133         _route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed));
134         meter_point_button.add (meter_point_label);
135         meter_point_button.set_name ("MixerStripMeterPreButton");
136         meter_point_label.set_name ("MixerStripMeterPreButton");
137         
138         switch (_route->meter_point()) {
139         case MeterInput:
140                 meter_point_label.set_text (_("input"));
141                 break;
142                 
143         case MeterPreFader:
144                 meter_point_label.set_text (_("pre"));
145                 break;
146                 
147         case MeterPostFader:
148                 meter_point_label.set_text (_("post"));
149                 break;
150         }
151         
152         /* TRANSLATORS: this string should be longest of the strings
153            used to describe meter points. In english, it's "input".
154         */
155         set_size_request_to_display_given_text (meter_point_button, _("tupni"), 5, 5);
156     
157         bottom_button_table.attach (meter_point_button, 1, 2, 0, 1);
158     
159         meter_point_button.signal_button_press_event().connect (mem_fun (gpm, &GainMeter::meter_press), false);
160         /* XXX what is this meant to do? */
161         //meter_point_button.signal_button_release_event().connect (mem_fun (gpm, &GainMeter::meter_release), false);
162
163         hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
164
165         mute_button->set_name ("MixerMuteButton");
166         solo_button->set_name ("MixerSoloButton");
167
168         button_table.set_homogeneous (true);
169         button_table.set_spacings (0);
170
171         button_table.attach (name_button, 0, 2, 0, 1);
172         button_table.attach (input_button, 0, 2, 1, 2);
173
174         middle_button_table.set_homogeneous (true);
175         middle_button_table.set_spacings (0);
176         middle_button_table.attach (*mute_button, 0, 1, 0, 1);
177         middle_button_table.attach (*solo_button, 1, 2, 0, 1);
178
179         bottom_button_table.set_col_spacings (0);
180         bottom_button_table.set_homogeneous (true);
181         bottom_button_table.attach (group_button, 0, 1, 0, 1);
182         
183         if (is_audio_track()) {
184                 
185                 rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
186                 rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
187
188                 rec_enable_button->set_name ("MixerRecordEnableButton");
189
190                 boost::shared_ptr<AudioTrack> at = audio_track();
191
192                 at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen));
193
194 #ifdef VARISPEED_IN_MIXER_STRIP
195                 speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
196                 
197                 speed_frame.set_name ("BaseFrame");
198                 speed_frame.set_shadow_type (Gtk::SHADOW_IN);
199                 speed_frame.add (speed_spinner);
200                 
201                 speed_spinner.set_print_func (speed_printer, 0);
202
203                 ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
204
205                 button_table.attach (speed_frame, 0, 2, 5, 6);
206 #endif /* VARISPEED_IN_MIXER_STRIP */
207
208                 button_table.attach (*rec_enable_button, 0, 2, 2, 3);
209         }
210
211         name_button.add (name_label);
212         name_button.set_name ("MixerNameButton");
213         Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
214
215         name_label.set_name ("MixerNameButtonLabel");
216         if (_route->phase_invert()) {
217                 name_label.set_text (X_("Ø ") + name_label.get_text());
218         } else {
219                 name_label.set_text (_route->name());
220         }
221
222         group_button.add (group_label);
223         group_button.set_name ("MixerGroupButton");
224         group_label.set_name ("MixerGroupButtonLabel");
225
226         comment_button.set_name ("MixerCommentButton");
227
228         ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment()==""        ?
229                                                         _("Click to Add/Edit Comments"):
230                                                         _route->comment());
231
232         comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked));
233         
234         global_vpacker.set_border_width (0);
235         global_vpacker.set_spacing (0);
236
237         VBox *whvbox = manage (new VBox);
238
239         width_button.set_name ("MixerWidthButton");
240         hide_button.set_name ("MixerHideButton");
241         top_event_box.set_name ("MixerTopEventBox");
242
243         width_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::width_clicked));
244         hide_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::hide_clicked));
245
246         width_hide_box.pack_start (width_button, false, true);
247         width_hide_box.pack_start (top_event_box, true, true);
248         width_hide_box.pack_end (hide_button, false, true);
249         Gtk::Alignment *gain_meter_alignment = Gtk::manage(new Gtk::Alignment());
250         gain_meter_alignment->set_padding(0, 4, 0, 0);
251         gain_meter_alignment->add(gpm);
252
253         whvbox->pack_start (width_hide_box, true, true);
254
255         global_vpacker.pack_start (*whvbox, Gtk::PACK_SHRINK);
256         global_vpacker.pack_start (button_table,Gtk::PACK_SHRINK);
257         global_vpacker.pack_start (pre_processor_box, true, true);
258         global_vpacker.pack_start (middle_button_table,Gtk::PACK_SHRINK);
259         global_vpacker.pack_start (*gain_meter_alignment,Gtk::PACK_SHRINK);
260         global_vpacker.pack_start (bottom_button_table,Gtk::PACK_SHRINK);
261         global_vpacker.pack_start (post_processor_box, true, true);
262         if (!is_midi_track())
263                 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
264         global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
265         global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
266
267         if (route()->is_master() || route()->is_control()) {
268                 
269                 if (scrollbar_height == 0) {
270                         HScrollbar scrollbar;
271                         Gtk::Requisition requisition(scrollbar.size_request ());
272                         scrollbar_height = requisition.height;
273                 }
274
275                 EventBox* spacer = manage (new EventBox);
276                 spacer->set_size_request (-1, scrollbar_height);
277                 global_vpacker.pack_start (*spacer, false, false);
278         }
279
280         global_frame.add (global_vpacker);
281         global_frame.set_shadow_type (Gtk::SHADOW_IN);
282         global_frame.set_name ("BaseFrame");
283
284         add (global_frame);
285
286         /* force setting of visible selected status */
287
288         _selected = true;
289         set_selected (false);
290
291         _packed = false;
292         _embedded = false;
293
294         _session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped));
295         _session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running));
296         _route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed));
297         _route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed));
298         _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
299         _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
300         _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
301         _route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed));
302         _route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan));
303
304         if (is_audio_track()) {
305                 audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed));
306                 get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed));
307         }
308
309         _route->NameChanged.connect (mem_fun(*this, &RouteUI::name_changed));
310         _route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed));
311         _route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed));
312
313         input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false);
314         output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false);
315
316         solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false);
317         solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false);
318         mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
319         mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
320
321         name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false);
322         group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false);
323
324         _width = (Width) -1;
325         set_stuff_from_route ();
326
327         /* start off as a passthru strip. we'll correct this, if necessary,
328            in update_diskstream_display().
329         */
330
331         if (is_midi_track())
332                 set_name ("MidiTrackStripBase");
333         else
334                 set_name ("AudioTrackStripBase");
335
336         /* now force an update of all the various elements */
337
338         pre_processor_box.update();
339         post_processor_box.update();
340         mute_changed (0);
341         solo_changed (0);
342         name_changed ();
343         comment_changed (0);
344         mix_group_changed (0);
345
346         connect_to_pan ();
347
348         panners.setup_pan ();
349
350         if (is_audio_track()) {
351                 speed_changed ();
352         }
353
354         update_diskstream_display ();
355         update_input_display ();
356         update_output_display ();
357
358         add_events (Gdk::BUTTON_RELEASE_MASK);
359
360         whvbox->show();
361         hide_icon->show();
362         width_icon->show();
363         gain_meter_alignment->show();
364
365         pre_processor_box.show();
366
367         if (!route()->is_master() && !route()->is_control()) {
368                 /* we don't allow master or control routes to be hidden */
369                 hide_button.show();
370         }
371         width_button.show();
372         width_hide_box.show();
373         global_frame.show();
374         global_vpacker.show();
375         button_table.show();
376         middle_button_table.show();
377         bottom_button_table.show();
378         gain_unit_button.show();
379         gain_unit_label.show();
380         meter_point_button.show();
381         meter_point_label.show();
382         diskstream_button.show();
383         diskstream_label.show();
384         input_button.show();
385         input_label.show();
386         output_button.show();
387         output_label.show();
388         name_label.show();
389         name_button.show();
390         comment_button.show();
391         group_button.show();
392         group_label.show();
393         speed_spinner.show();
394         speed_label.show();
395         speed_frame.show();
396
397         show();
398 }
399
400 MixerStrip::~MixerStrip ()
401 {
402         GoingAway(); /* EMIT_SIGNAL */
403
404         if (input_selector) {
405                 delete input_selector;
406         }
407
408         if (output_selector) {
409                 delete output_selector;
410         }
411 }
412
413 void
414 MixerStrip::set_stuff_from_route ()
415 {
416         XMLProperty *prop;
417
418         ensure_xml_node ();
419
420         /* if width is not set, it will be set by the MixerUI or editor */
421
422         if ((prop = xml_node->property ("strip_width")) != 0) {
423                 set_width (Width (string_2_enum (prop->value(), _width)), this);
424         }
425
426         if ((prop = xml_node->property ("shown_mixer")) != 0) {
427                 if (prop->value() == "no") {
428                         _marked_for_display = false;
429                 } else {
430                         _marked_for_display = true;
431                 }
432         } else {
433                 /* backwards compatibility */
434                 _marked_for_display = true;
435         }
436 }
437
438 void
439 MixerStrip::set_width (Width w, void* owner)
440 {
441         /* always set the gpm width again, things may be hidden */
442
443         gpm.set_width (w);
444         panners.set_width (w);
445         pre_processor_box.set_width (w);
446         post_processor_box.set_width (w);
447
448         boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->list();
449
450         _width_owner = owner;
451
452         ensure_xml_node ();
453         
454         _width = w;
455
456         if (_width_owner == this) {
457                 xml_node->add_property ("strip_width", enum_2_string (_width));
458         }
459
460         switch (w) {
461         case Wide:
462                 set_size_request (-1, -1);
463                 
464                 if (rec_enable_button)  {
465                         ((Gtk::Label*)rec_enable_button->get_child())->set_text (_("record"));
466                 }
467                 ((Gtk::Label*)mute_button->get_child())->set_text  (_("Mute"));
468                 ((Gtk::Label*)solo_button->get_child())->set_text (_("Solo"));
469
470                 if (_route->comment() == "") {
471                        comment_button.unset_bg (STATE_NORMAL);
472                        ((Gtk::Label*)comment_button.get_child())->set_text (_("comments"));
473                 } else {
474                        comment_button.modify_bg (STATE_NORMAL, color());
475                        ((Gtk::Label*)comment_button.get_child())->set_text (_("*comments*"));
476                 }
477
478                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.astyle_string(gain_automation->automation_style()));
479                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.astate_string(gain_automation->automation_state()));
480                 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (panners.astyle_string(_route->panner().automation_style()));
481                 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (panners.astate_string(_route->panner().automation_state()));
482                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
483                 break;
484
485         case Narrow:
486                 if (rec_enable_button) {
487                         ((Gtk::Label*)rec_enable_button->get_child())->set_text (_("Rec"));
488                 }
489                 ((Gtk::Label*)mute_button->get_child())->set_text (_("M"));
490                 ((Gtk::Label*)solo_button->get_child())->set_text (_("S"));
491
492                 if (_route->comment() == "") {
493                        comment_button.unset_bg (STATE_NORMAL);
494                        ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
495                 } else {
496                        comment_button.modify_bg (STATE_NORMAL, color());
497                        ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
498                 }
499
500                 ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.short_astyle_string(gain_automation->automation_style()));
501                 ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.short_astate_string(gain_automation->automation_state()));
502                 ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (panners.short_astyle_string(_route->panner().automation_style()));
503                 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (panners.short_astate_string(_route->panner().automation_state()));
504                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
505                 set_size_request (max (50, gpm.get_gm_width()), -1);
506                 break;
507         }
508
509         update_input_display ();
510         update_output_display ();
511         mix_group_changed (0);
512         name_changed ();
513
514 }
515
516 void
517 MixerStrip::set_packed (bool yn)
518 {
519         _packed = yn;
520
521         ensure_xml_node ();
522
523         if (_packed) {
524                 xml_node->add_property ("shown_mixer", "yes");
525         } else {
526                 xml_node->add_property ("shown_mixer", "no");
527         }
528 }
529
530
531 gint
532 MixerStrip::output_press (GdkEventButton *ev)
533 {
534         using namespace Menu_Helpers;
535         if (!_session.engine().connected()) {
536                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
537                 msg.run ();
538                 return true;
539         }
540
541         MenuList& citems = output_menu.items();
542         switch (ev->button) {
543
544         case 1:
545         {
546                 output_menu.set_name ("ArdourContextMenu");
547                 citems.clear();
548                 
549                 citems.push_back (MenuElem (_("Edit"), mem_fun(*this, &MixerStrip::edit_output_configuration)));
550                 citems.push_back (SeparatorElem());
551                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
552                 citems.push_back (SeparatorElem());
553
554                 std::vector<boost::shared_ptr<Bundle> > current = _route->bundles_connected_to_outputs ();
555
556                 _session.foreach_bundle (
557                         bind (mem_fun (*this, &MixerStrip::add_bundle_to_output_menu), current)
558                         );
559
560                 output_menu.popup (1, ev->time);
561                 break;
562         }
563                 
564         default:
565                 break;
566         }
567         return TRUE;
568 }
569
570 void
571 MixerStrip::edit_output_configuration ()
572 {
573         if (output_selector == 0) {
574                 output_selector = new IOSelectorWindow (_session, _route, false);
575         } 
576
577         if (output_selector->is_visible()) {
578                 output_selector->get_toplevel()->get_window()->raise();
579         } else {
580                 output_selector->present ();
581         }
582 }
583
584 void
585 MixerStrip::edit_input_configuration ()
586 {
587         if (input_selector == 0) {
588                 input_selector = new IOSelectorWindow (_session, _route, true);
589         } 
590
591         if (input_selector->is_visible()) {
592                 input_selector->get_toplevel()->get_window()->raise();
593         } else {
594                 input_selector->present ();
595         }
596 }
597
598 gint
599 MixerStrip::input_press (GdkEventButton *ev)
600 {
601         using namespace Menu_Helpers;
602
603         MenuList& citems = input_menu.items();
604         input_menu.set_name ("ArdourContextMenu");
605         citems.clear();
606         
607         if (!_session.engine().connected()) {
608                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
609                 msg.run ();
610                 return true;
611         }
612
613         switch (ev->button) {
614
615         case 1:
616         {
617                 citems.push_back (MenuElem (_("Edit"), mem_fun(*this, &MixerStrip::edit_input_configuration)));
618                 citems.push_back (SeparatorElem());
619                 citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
620                 citems.push_back (SeparatorElem());
621
622                 std::vector<boost::shared_ptr<Bundle> > current = _route->bundles_connected_to_inputs ();
623
624                 _session.foreach_bundle (
625                         bind (mem_fun (*this, &MixerStrip::add_bundle_to_input_menu), current)
626                         );
627
628                 input_menu.popup (1, ev->time);
629                 break;
630         }
631         default:
632                 break;
633         }
634         return TRUE;
635 }
636
637 void
638 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
639 {
640         if (!ignore_toggle) {
641
642                 try { 
643                         _route->connect_input_ports_to_bundle (c, this);
644                 }
645
646                 catch (AudioEngine::PortRegistrationFailure& err) {
647                         error << _("could not register new ports required for that bundle")
648                               << endmsg;
649                 }
650         }
651 }
652
653 void
654 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
655 {
656         if (!ignore_toggle) {
657
658                 try { 
659                         _route->connect_output_ports_to_bundle (c, this);
660                 }
661
662                 catch (AudioEngine::PortRegistrationFailure& err) {
663                         error << _("could not register new ports required for that bundle")
664                               << endmsg;
665                 }
666         }
667 }
668
669 void
670 MixerStrip::add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, std::vector<boost::shared_ptr<Bundle> > const & current)
671 {
672         using namespace Menu_Helpers;
673
674         /* the input menu needs to contain only output bundles (that we
675            can connect inputs to */
676         if (b->ports_are_outputs() == false) {
677                 return;
678         }
679
680         MenuList& citems = input_menu.items();
681         
682         if (b->nchannels() == _route->n_inputs().n_total()) {
683
684                 citems.push_back (CheckMenuElem (b->name(), bind (mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
685
686                 if (std::find (current.begin(), current.end(), b) != current.end()) {
687                         ignore_toggle = true;
688                         dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
689                         ignore_toggle = false;
690                 }
691         }
692 }
693
694 void
695 MixerStrip::add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, std::vector<boost::shared_ptr<Bundle> > const & current)
696 {
697         using namespace Menu_Helpers;
698
699         /* the output menu needs to contain only input bundles (that we
700            can connect outputs to */
701         if (b->ports_are_inputs() == false) {
702                 return;
703         }
704
705         if (b->nchannels() == _route->n_outputs().n_total()) {
706
707                 MenuList& citems = output_menu.items();
708                 citems.push_back (CheckMenuElem (b->name(), bind (mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
709                 
710                 if (std::find (current.begin(), current.end(), b) != current.end()) {
711                         ignore_toggle = true;
712                         dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
713                         ignore_toggle = false;
714                 }
715         }
716 }
717
718 void
719 MixerStrip::update_diskstream_display ()
720 {
721         if (is_track()) {
722
723                 map_frozen ();
724
725                 update_input_display ();
726
727                 if (input_selector) {
728                         input_selector->hide_all ();
729                 }
730
731                 show_route_color ();
732
733         } else {
734
735                 map_frozen ();
736
737                 update_input_display ();
738                 show_passthru_color ();
739         }
740 }
741
742 void
743 MixerStrip::connect_to_pan ()
744 {
745         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::connect_to_pan));
746
747         panstate_connection.disconnect ();
748         panstyle_connection.disconnect ();
749
750         if (!_route->panner().empty()) {
751                 StreamPanner* sp = _route->panner().front();
752
753                 panstate_connection = sp->pan_control()->list()->automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed));
754                 panstyle_connection = sp->pan_control()->list()->automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed));
755         }
756
757         panners.pan_changed (this);
758 }
759
760 void
761 MixerStrip::update_input_display ()
762 {
763         std::vector<boost::shared_ptr<ARDOUR::Bundle> > c = _route->bundles_connected_to_inputs ();
764
765         /* XXX: how do we represent >1 connected bundle? */
766         if (c.empty() == false) {
767                 input_label.set_text (c[0]->name());
768         } else {
769                 switch (_width) {
770                 case Wide:
771                         input_label.set_text (_(" Input"));
772                         break;
773                 case Narrow:
774                         input_label.set_text (_("I"));
775                         break;
776                 }
777         }
778         panners.setup_pan ();
779 }
780
781 void
782 MixerStrip::update_output_display ()
783 {
784         std::vector<boost::shared_ptr<ARDOUR::Bundle> > c = _route->bundles_connected_to_outputs ();
785
786         /* XXX: how do we represent >1 connected bundle? */
787         if (c.empty() == false) {
788                 output_label.set_text (c[0]->name());
789         } else {
790                 switch (_width) {
791                 case Wide:
792                         output_label.set_text (_("Output"));
793                         break;
794                 case Narrow:
795                         output_label.set_text (_("O"));
796                         break;
797                 }
798         }
799         gpm.setup_meters ();
800         panners.setup_pan ();
801 }
802
803 void
804 MixerStrip::fast_update ()
805 {
806         gpm.update_meters ();
807 }
808
809 void
810 MixerStrip::diskstream_changed ()
811 {
812         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display));
813 }       
814
815 void
816 MixerStrip::input_changed (IOChange change, void *src)
817 {
818         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_input_display));
819         set_width(_width, this);
820 }
821
822 void
823 MixerStrip::output_changed (IOChange change, void *src)
824 {
825         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_output_display));
826         set_width(_width, this);
827 }
828
829
830 void 
831 MixerStrip::comment_editor_done_editing() 
832 {
833         string str =  comment_area->get_buffer()->get_text();
834         if (_route->comment() != str) {
835                 _route->set_comment (str, this);
836
837                 switch (_width) {
838                    
839                 case Wide:
840                         if (! str.empty()) {
841                                 comment_button.modify_bg (STATE_NORMAL, color());
842                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
843                         } else {
844                                 comment_button.unset_bg (STATE_NORMAL);
845                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
846                         }
847                         break;
848                    
849                 case Narrow:
850                         if (! str.empty()) {
851                                 comment_button.modify_bg (STATE_NORMAL, color());
852                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
853                         } else {
854                                 comment_button.unset_bg (STATE_NORMAL);
855                                 ((Gtk::Label*)comment_button.get_child())->set_text (_("Cmt"));
856                         } 
857                         break;
858                 }
859                  
860                 ARDOUR_UI::instance()->tooltips().set_tip (comment_button, 
861                                 str.empty() ? _("Click to Add/Edit Comments") : str);
862         }
863
864 }
865
866 void
867 MixerStrip::comment_button_clicked ()
868 {
869         if (comment_window == 0) {
870                 setup_comment_editor ();
871         }
872
873     int x, y, cw_width, cw_height;
874
875         if (comment_window->is_visible()) {
876                 comment_window->hide ();
877                 return;
878         }
879
880         comment_window->get_size (cw_width, cw_height);
881         comment_window->get_position(x, y);
882         comment_window->move(x, y - (cw_height / 2) - 45);
883         /* 
884            half the dialog height minus the comments button height 
885            with some window decoration fudge thrown in.
886         */
887
888         comment_window->show();
889         comment_window->present();
890 }
891
892 void
893 MixerStrip::setup_comment_editor ()
894 {
895         string title;
896         title = _route->name();
897         title += _(": comment editor");
898
899         comment_window = new ArdourDialog (title, false);
900         comment_window->set_position (Gtk::WIN_POS_MOUSE);
901         comment_window->set_skip_taskbar_hint (true);
902         comment_window->signal_hide().connect (mem_fun(*this, &MixerStrip::comment_editor_done_editing));
903
904         comment_area = manage (new TextView());
905         comment_area->set_name ("MixerTrackCommentArea");
906         comment_area->set_size_request (110, 178);
907         comment_area->set_wrap_mode (WRAP_WORD);
908         comment_area->set_editable (true);
909         comment_area->get_buffer()->set_text (_route->comment());
910         comment_area->show ();
911
912         comment_window->get_vbox()->pack_start (*comment_area);
913         comment_window->get_action_area()->hide();
914 }
915
916 void
917 MixerStrip::comment_changed (void *src)
918 {
919         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::comment_changed), src));
920         
921         if (src != this) {
922                 ignore_comment_edit = true;
923                 if (comment_area) {
924                         comment_area->get_buffer()->set_text (_route->comment());
925                 }
926                 ignore_comment_edit = false;
927         }
928 }
929
930 void
931 MixerStrip::set_mix_group (RouteGroup *rg)
932 {
933         _route->set_mix_group (rg, this);
934 }
935
936 void
937 MixerStrip::add_mix_group_to_menu (RouteGroup *rg, RadioMenuItem::Group* group)
938 {
939         using namespace Menu_Helpers;
940
941         MenuList& items = group_menu->items();
942
943         items.push_back (RadioMenuElem (*group, rg->name(), bind (mem_fun(*this, &MixerStrip::set_mix_group), rg)));
944
945         if (_route->mix_group() == rg) {
946                 static_cast<RadioMenuItem*>(&items.back())->set_active ();
947         }
948 }
949
950 bool
951 MixerStrip::select_mix_group (GdkEventButton *ev)
952 {
953         using namespace Menu_Helpers;
954
955         if (group_menu == 0) {
956                 group_menu = new Menu;
957         } 
958         group_menu->set_name ("ArdourContextMenu");
959         MenuList& items = group_menu->items();
960         RadioMenuItem::Group group;
961
962         switch (ev->button) {
963         case 1:
964
965                 items.clear ();
966                 items.push_back (RadioMenuElem (group, _("No group"), bind (mem_fun(*this, &MixerStrip::set_mix_group), (RouteGroup *) 0)));
967
968                 _session.foreach_mix_group (bind (mem_fun (*this, &MixerStrip::add_mix_group_to_menu), &group));
969
970                 group_menu->popup (1, ev->time);
971                 break;
972
973         default:
974                 break;
975         }
976         
977         return true;
978 }       
979
980 void
981 MixerStrip::mix_group_changed (void *ignored)
982 {
983         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::mix_group_changed), ignored));
984         
985         RouteGroup *rg = _route->mix_group();
986         
987         if (rg) {
988                 group_label.set_text (rg->name());
989         } else {
990                 switch (_width) {
991                 case Wide:
992                         group_label.set_text (_("Grp"));
993                         break;
994                 case Narrow:
995                         group_label.set_text (_("~G"));
996                         break;
997                 }
998         }
999 }
1000
1001
1002 void 
1003 MixerStrip::route_gui_changed (string what_changed, void* ignored)
1004 {
1005         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_gui_changed), what_changed, ignored));
1006         
1007         if (what_changed == "color") {
1008                 if (set_color_from_route () == 0) {
1009                         show_route_color ();
1010                 }
1011         }
1012 }
1013
1014 void
1015 MixerStrip::show_route_color ()
1016 {
1017         name_button.modify_bg (STATE_NORMAL, color());
1018         top_event_box.modify_bg (STATE_NORMAL, color());
1019         route_active_changed ();
1020 }
1021
1022 void
1023 MixerStrip::show_passthru_color ()
1024 {
1025         route_active_changed ();
1026 }
1027
1028 void
1029 MixerStrip::build_route_ops_menu ()
1030 {
1031         using namespace Menu_Helpers;
1032         route_ops_menu = manage (new Menu);
1033         route_ops_menu->set_name ("ArdourContextMenu");
1034
1035         MenuList& items = route_ops_menu->items();
1036
1037         items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteUI::route_rename)));
1038         items.push_back (SeparatorElem());
1039         items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
1040         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1041         route_active_menu_item->set_active (_route->active());
1042
1043         items.push_back (SeparatorElem());
1044
1045         items.push_back (MenuElem (_("Adjust latency"), mem_fun (*this, &RouteUI::adjust_latency)));
1046
1047         items.push_back (SeparatorElem());
1048         items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
1049         polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1050         polarity_menu_item->set_active (_route->phase_invert());
1051         items.push_back (CheckMenuElem (_("Protect against denormals"), mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1052         denormal_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1053         denormal_menu_item->set_active (_route->denormal_protection());
1054
1055         build_remote_control_menu ();
1056         
1057         items.push_back (SeparatorElem());
1058         if (!Profile->get_sae()) {
1059               items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu));
1060         }
1061
1062         items.push_back (SeparatorElem());
1063         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
1064 }
1065
1066 gint
1067 MixerStrip::name_button_button_press (GdkEventButton* ev)
1068 {
1069         if (ev->button == 1) {
1070                 list_route_operations ();
1071
1072                 Menu_Helpers::MenuList& items = route_ops_menu->items();
1073                 /* do not allow rename if the track is record-enabled */
1074                 static_cast<MenuItem*> (&items.front())->set_sensitive (!_route->record_enabled());
1075
1076                 route_ops_menu->popup (1, ev->time);
1077         }
1078         return FALSE;
1079 }
1080
1081 void
1082 MixerStrip::list_route_operations ()
1083 {
1084         if (route_ops_menu == 0) {
1085                 build_route_ops_menu ();
1086         }
1087         
1088         refresh_remote_control_menu();
1089 }
1090
1091
1092 void
1093 MixerStrip::speed_adjustment_changed ()
1094 {
1095         /* since there is a usable speed adjustment, there has to be a diskstream */
1096         if (!ignore_speed_adjustment) {
1097                 get_diskstream()->set_speed (speed_adjustment.get_value());
1098         }
1099 }
1100
1101 void
1102 MixerStrip::speed_changed ()
1103 {
1104         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_speed_display));
1105 }
1106
1107 void
1108 MixerStrip::update_speed_display ()
1109 {
1110         float val;
1111         
1112         val = get_diskstream()->speed();
1113
1114         if (val != 1.0) {
1115                 speed_spinner.set_name ("MixerStripSpeedBaseNotOne");
1116         } else {
1117                 speed_spinner.set_name ("MixerStripSpeedBase");
1118         }
1119
1120         if (speed_adjustment.get_value() != val) {
1121                 ignore_speed_adjustment = true;
1122                 speed_adjustment.set_value (val);
1123                 ignore_speed_adjustment = false;
1124         }
1125 }                       
1126
1127
1128 void
1129 MixerStrip::set_selected (bool yn)
1130 {
1131         AxisView::set_selected (yn);
1132         if (_selected) {
1133                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1134                 global_frame.set_name ("MixerStripSelectedFrame");
1135         } else {
1136                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1137                 global_frame.set_name ("MixerStripFrame");
1138         }
1139         global_frame.queue_draw ();
1140 }
1141
1142 void
1143 MixerStrip::name_changed ()
1144 {
1145         switch (_width) {
1146         case Wide:
1147                 RouteUI::name_changed ();
1148                 break;
1149         case Narrow:
1150                 name_label.set_text (PBD::short_version (_route->name(), 5));
1151                 break;
1152         }
1153         if (_route->phase_invert()) {
1154                 name_label.set_text (X_("Ø ") + name_label.get_text());
1155         }
1156 }
1157
1158 void
1159 MixerStrip::width_clicked ()
1160 {
1161         switch (_width) {
1162         case Wide:
1163                 set_width (Narrow, this);
1164                 break;
1165         case Narrow:
1166                 set_width (Wide, this);
1167                 break;
1168         }
1169 }
1170
1171 void
1172 MixerStrip::hide_clicked ()
1173 {
1174     // LAME fix to reset the button status for when it is redisplayed (part 1)
1175     hide_button.set_sensitive(false);
1176     
1177         if (_embedded) {
1178                  Hiding(); /* EMIT_SIGNAL */
1179         } else {
1180                 _mixer.hide_strip (this);
1181         }
1182         
1183     // (part 2)
1184         hide_button.set_sensitive(true);
1185 }
1186
1187 void
1188 MixerStrip::set_embedded (bool yn)
1189 {
1190         _embedded = yn;
1191 }
1192
1193 void
1194 MixerStrip::map_frozen ()
1195 {
1196         ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::map_frozen));
1197
1198         boost::shared_ptr<AudioTrack> at = audio_track();
1199
1200         if (at) {
1201                 switch (at->freeze_state()) {
1202                 case AudioTrack::Frozen:
1203                         pre_processor_box.set_sensitive (false);
1204                         post_processor_box.set_sensitive (false);
1205                         speed_spinner.set_sensitive (false);
1206                         break;
1207                 default:
1208                         pre_processor_box.set_sensitive (true);
1209                         post_processor_box.set_sensitive (true);
1210                         speed_spinner.set_sensitive (true);
1211                         break;
1212                 }
1213         }
1214         _route->foreach_processor (this, &MixerStrip::hide_processor_editor);
1215 }
1216
1217 void
1218 MixerStrip::hide_processor_editor (boost::shared_ptr<Processor> processor)
1219 {
1220         void* gui = processor->get_gui ();
1221         
1222         if (gui) {
1223                 static_cast<Gtk::Widget*>(gui)->hide ();
1224         }
1225 }
1226
1227 void
1228 MixerStrip::route_active_changed ()
1229 {
1230         RouteUI::route_active_changed ();
1231
1232         if (is_midi_track()) {
1233                 if (_route->active()) {
1234                         set_name ("MidiTrackStripBase");
1235                         gpm.set_meter_strip_name ("MidiTrackStripBase");
1236                 } else {
1237                         set_name ("MidiTrackStripBaseInactive");
1238                         gpm.set_meter_strip_name ("MidiTrackStripBaseInactive");
1239                 }
1240                 gpm.set_fader_name ("MidiTrackFader");
1241         } else if (is_audio_track()) {
1242                 if (_route->active()) {
1243                         set_name ("AudioTrackStripBase");
1244                         gpm.set_meter_strip_name ("AudioTrackMetrics");
1245                 } else {
1246                         set_name ("AudioTrackStripBaseInactive");
1247                         gpm.set_meter_strip_name ("AudioTrackMetricsInactive");
1248                 }
1249                 gpm.set_fader_name ("AudioTrackFader");
1250         } else {
1251                 if (_route->active()) {
1252                         set_name ("AudioBusStripBase");
1253                         gpm.set_meter_strip_name ("AudioBusMetrics");
1254                 } else {
1255                         set_name ("AudioBusStripBaseInactive");
1256                         gpm.set_meter_strip_name ("AudioBusMetricsInactive");
1257                 }
1258                 gpm.set_fader_name ("AudioBusFader");
1259                 
1260                 /* (no MIDI busses yet) */
1261         }
1262 }
1263
1264 RouteGroup*
1265 MixerStrip::mix_group() const
1266 {
1267         return _route->mix_group();
1268 }
1269
1270 void
1271 MixerStrip::engine_stopped ()
1272 {
1273 }
1274
1275 void
1276 MixerStrip::engine_running ()
1277 {
1278 }
1279
1280 void
1281 MixerStrip::meter_changed (void *src)
1282 {
1283
1284         ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
1285
1286         switch (_route->meter_point()) {
1287                 case MeterInput:
1288                         meter_point_label.set_text (_("input"));
1289                         break;
1290
1291                 case MeterPreFader:
1292                         meter_point_label.set_text (_("pre"));
1293                         break;
1294
1295                 case MeterPostFader:
1296                         meter_point_label.set_text (_("post"));
1297                         break;
1298         }
1299
1300         gpm.setup_meters ();
1301                 set_width(_width, this);
1302 }
1303