37b8af29f9effa3e43096e05586133529f722f41
[ardour.git] / gtk2_ardour / mixer_strip.cc
1 /*
2     Copyright (C) 2000-2002 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     $Id$
19 */
20
21 #include <cmath>
22
23 #include <sigc++/bind.h>
24
25 #include <pbd/convert.h>
26
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
29 #include <gtkmm2ext/choice.h>
30 #include <gtkmm2ext/slider_controller.h>
31 #include <gtkmm2ext/stop_signal.h>
32 #include <gtkmm2ext/bindable_button.h>
33 #include <gtkmm2ext/doi.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/diskstream.h>
41 #include <ardour/panner.h>
42 #include <ardour/send.h>
43 #include <ardour/insert.h>
44 #include <ardour/ladspa_plugin.h>
45 #include <ardour/connection.h>
46 #include <ardour/session_connection.h>
47
48 #include "ardour_ui.h"
49 #include "ardour_dialog.h"
50 #include "mixer_strip.h"
51 #include "mixer_ui.h"
52 #include "keyboard.h"
53 #include "plugin_selector.h"
54 #include "public_editor.h"
55
56 #include "plugin_ui.h"
57 #include "send_ui.h"
58 #include "io_selector.h"
59 #include "utils.h"
60 #include "gui_thread.h"
61
62 #include "i18n.h"
63
64 using namespace sigc;
65 using namespace ARDOUR;
66 using namespace Gtk;
67 using namespace Gtkmm2ext;
68
69 #ifdef VARISPEED_IN_MIXER_STRIP
70 static void 
71 speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
72 {
73         float val = adj.get_value ();
74
75         if (val == 1.0) {
76                 strcpy (buf, "1");
77         } else {
78                 snprintf (buf, 32, "%.3f", val);
79         }
80 }
81 #endif 
82
83 MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, Route& rt, bool in_mixer)
84         : AxisView(sess),
85           RouteUI (rt, sess, _("mute"), _("solo"), _("RECORD")),
86           _mixer(mx),
87           pre_redirect_box (PreFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
88           post_redirect_box (PostFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
89           gpm (_route, sess),
90           panners (_route, sess),
91           button_table (6, 2),
92           gain_automation_style_button (""),
93           gain_automation_state_button (""),
94           pan_automation_style_button (""),
95           pan_automation_state_button (""),
96           comment_button (_("Comments")),
97           speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1),
98           speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
99
100 {
101         if (set_color_from_route()) {
102                 set_color (unique_random_color());
103         }
104
105         input_selector = 0;
106         output_selector = 0;
107         group_menu = 0;
108         _marked_for_display = false;
109         route_ops_menu = 0;
110         ignore_comment_edit = false;
111         ignore_toggle = false;
112         ignore_speed_adjustment = false;
113         comment_window = 0;
114         comment_area = 0;
115
116         width_button.add (*(manage (new Gtk::Image (get_xpm("lr.xpm")))));
117         hide_button.add (*(manage (new Gtk::Image (get_xpm("small_x.xpm")))));
118
119
120         input_label.set_text (_("INPUT"));
121         input_button.add (input_label);
122         input_button.set_name ("MixerIOButton");
123         input_label.set_name ("MixerIOButtonLabel");
124
125         output_label.set_text (_("OUTPUT"));
126         output_button.add (output_label);
127         output_button.set_name ("MixerIOButton");
128         output_label.set_name ("MixerIOButtonLabel");
129
130         rec_enable_button->set_name ("MixerRecordEnableButton");
131         rec_enable_button->unset_flags (Gtk::CAN_FOCUS);
132
133         solo_button->set_name ("MixerSoloButton");
134         mute_button->set_name ("MixerMuteButton");
135         gain_automation_style_button.set_name ("MixerAutomationModeButton");
136         gain_automation_state_button.set_name ("MixerAutomationPlaybackButton");
137         pan_automation_style_button.set_name ("MixerAutomationModeButton");
138         pan_automation_state_button.set_name ("MixerAutomationPlaybackButton");
139
140         ARDOUR_UI::instance()->tooltips().set_tip (pan_automation_state_button, _("Pan automation mode"));
141         ARDOUR_UI::instance()->tooltips().set_tip (gain_automation_state_button, _("Gain automation mode"));
142
143         ARDOUR_UI::instance()->tooltips().set_tip (pan_automation_style_button, _("Pan automation type"));
144         ARDOUR_UI::instance()->tooltips().set_tip (gain_automation_style_button, _("Gain automation type"));
145
146         hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
147
148         width_button.unset_flags (Gtk::CAN_FOCUS);
149         hide_button.unset_flags (Gtk::CAN_FOCUS);
150         input_button.unset_flags (Gtk::CAN_FOCUS);
151         output_button.unset_flags (Gtk::CAN_FOCUS);
152         solo_button->unset_flags (Gtk::CAN_FOCUS);
153         mute_button->unset_flags (Gtk::CAN_FOCUS);
154         gain_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
155         gain_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
156         pan_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
157         pan_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
158
159         button_table.set_homogeneous (true);
160         button_table.set_spacings (0);
161
162         button_table.attach (name_button, 0, 2, 0, 1);
163         button_table.attach (group_button, 0, 2, 1, 2);
164         button_table.attach (input_button, 0, 2, 2, 3);
165
166         button_table.attach (*solo_button, 0, 1, 3, 4);
167         button_table.attach (*mute_button, 1, 2, 3, 4);
168
169         button_table.attach (gain_automation_state_button, 0, 1, 4, 5);
170         button_table.attach (pan_automation_state_button, 1, 2, 4, 5);
171
172         using namespace Menu_Helpers;
173         
174         gain_astate_menu.items().push_back (MenuElem (_("off"), 
175                                                       bind (mem_fun (_route, &IO::set_gain_automation_state), (AutoState) Off)));
176         gain_astate_menu.items().push_back (MenuElem (_("play"),
177                                                       bind (mem_fun (_route, &IO::set_gain_automation_state), (AutoState) Play)));
178         gain_astate_menu.items().push_back (MenuElem (_("write"),
179                                                       bind (mem_fun (_route, &IO::set_gain_automation_state), (AutoState) Write)));
180         gain_astate_menu.items().push_back (MenuElem (_("touch"),
181                                                       bind (mem_fun (_route, &IO::set_gain_automation_state), (AutoState) Touch)));
182         
183         gain_astyle_menu.items().push_back (MenuElem (_("trim")));
184         gain_astyle_menu.items().push_back (MenuElem (_("abs")));
185
186         pan_astate_menu.items().push_back (MenuElem (_("off"), 
187                                                      bind (mem_fun (_route.panner(), &Panner::set_automation_state), (AutoState) Off)));
188         pan_astate_menu.items().push_back (MenuElem (_("play"),
189                                                      bind (mem_fun (_route.panner(), &Panner::set_automation_state), (AutoState) Play)));
190         pan_astate_menu.items().push_back (MenuElem (_("write"),
191                                                      bind (mem_fun (_route.panner(), &Panner::set_automation_state), (AutoState) Write)));
192         pan_astate_menu.items().push_back (MenuElem (_("touch"),
193                                                      bind (mem_fun (_route.panner(), &Panner::set_automation_state), (AutoState) Touch)));
194
195         pan_astyle_menu.items().push_back (MenuElem (_("trim")));
196         pan_astyle_menu.items().push_back (MenuElem (_("abs")));
197         
198         gain_astate_menu.set_name ("ArdourContextMenu");
199         gain_astyle_menu.set_name ("ArdourContextMenu");
200         pan_astate_menu.set_name ("ArdourContextMenu");
201         pan_astyle_menu.set_name ("ArdourContextMenu");
202
203         ARDOUR_UI::instance()->tooltips().set_tip (gain_automation_style_button, _("gain automation mode"));
204         ARDOUR_UI::instance()->tooltips().set_tip (pan_automation_style_button, _("pan automation mode"));
205         ARDOUR_UI::instance()->tooltips().set_tip (gain_automation_state_button, _("gain automation state"));
206         ARDOUR_UI::instance()->tooltips().set_tip (pan_automation_state_button, _("pan automation state"));
207
208         if (is_audio_track()) {
209                 
210                 AudioTrack* at = dynamic_cast<AudioTrack*>(&_route);
211
212                 at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen));
213
214 #ifdef VARISPEED_IN_MIXER_STRIP
215                 speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
216                 
217                 speed_frame.set_name ("BaseFrame");
218                 speed_frame.set_shadow_type (Gtk::SHADOW_IN);
219                 speed_frame.add (speed_spinner);
220                 
221                 speed_spinner.set_print_func (speed_printer, 0);
222
223                 ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("varispeed"));
224
225                 button_table.attach (speed_frame, 0, 2, 5, 6);
226 #endif /* VARISPEED_IN_MIXER_STRIP */
227
228                 button_table.attach (*rec_enable_button, 0, 2, 5, 6);
229         }
230
231         name_button.add (name_label);
232         name_button.set_name ("MixerNameButton");
233         Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
234
235         name_label.set_name ("MixerNameButtonLabel");
236         name_label.set_text (_route.name());
237
238         group_button.add (group_label);
239         group_button.set_name ("MixerGroupButton");
240         group_label.set_name ("MixerGroupButtonLabel");
241
242         comment_button.set_name ("MixerCommentButton");
243
244         ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route.comment()=="" ?
245                                                         _("Click to Add/Edit Comments"):
246                                                         _route.comment());
247
248         comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked));
249         
250         global_vpacker.set_border_width (0);
251         global_vpacker.set_spacing (0);
252
253         Gtk::VBox *whvbox = manage (new Gtk::VBox);
254
255         width_button.set_name ("MixerWidthButton");
256         hide_button.set_name ("MixerHideButton");
257
258         width_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::width_clicked));
259         hide_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::hide_clicked));
260
261         width_hide_box.pack_start (width_button, false, true);
262         width_hide_box.pack_end (hide_button, false, true);
263
264         whvbox->pack_start (width_hide_box, true, true);
265
266         global_vpacker.pack_start (*whvbox, Gtk::PACK_SHRINK);
267         global_vpacker.pack_start (button_table,Gtk::PACK_SHRINK);
268         global_vpacker.pack_start (pre_redirect_box, true, true);
269         global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK, 4);
270         global_vpacker.pack_start (post_redirect_box, true, true);
271         global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
272         global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
273         global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
274
275         global_frame.add (global_vpacker);
276         global_frame.set_shadow_type (Gtk::SHADOW_IN);
277         global_frame.set_name ("BaseFrame");
278
279         add (global_frame);
280
281         /* force setting of visible selected status */
282
283         _selected = true;
284         set_selected (false);
285
286         _packed = false;
287         _embedded = false;
288
289         _route.input_changed.connect (mem_fun(*this, &MixerStrip::input_changed));
290         _route.output_changed.connect (mem_fun(*this, &MixerStrip::output_changed));
291         _route.mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
292         _route.solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
293         _route.solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
294         _route.mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed));
295         _route.gain_automation_curve().automation_state_changed.connect (mem_fun(*this, &MixerStrip::gain_automation_state_changed));
296         _route.gain_automation_curve().automation_style_changed.connect (mem_fun(*this, &MixerStrip::gain_automation_style_changed));
297         _route.panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan));
298
299         if (is_audio_track()) {
300                 audio_track()->diskstream_changed.connect (mem_fun(*this, &MixerStrip::diskstream_changed));
301                 get_diskstream()->speed_changed.connect (mem_fun(*this, &MixerStrip::speed_changed));
302         }
303
304         _route.name_changed.connect (mem_fun(*this, &RouteUI::name_changed));
305         _route.comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed));
306         _route.gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed));
307
308         input_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::input_press), false);
309         output_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::output_press), false);
310
311         rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press));
312         solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false);
313         solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false);
314         mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
315         mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
316
317         gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::gain_automation_style_button_event), false);
318         gain_automation_style_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::gain_automation_style_button_event), false);
319         pan_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::pan_automation_style_button_event), false);
320         pan_automation_style_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::pan_automation_style_button_event), false);
321
322         gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::gain_automation_state_button_event), false);
323         gain_automation_state_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::gain_automation_state_button_event), false);
324         pan_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::pan_automation_state_button_event), false);
325         pan_automation_state_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::pan_automation_state_button_event), false);
326
327         name_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::name_button_button_release), false);
328
329         group_button.signal_button_release_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false);
330
331         _width = (Width) -1;
332         set_stuff_from_route ();
333
334         /* start off as a passthru strip. we'll correct this, if necessary,
335            in update_diskstream_display().
336         */
337
338         set_name ("AudioTrackStripBase");
339
340         /* now force an update of all the various elements */
341
342         pre_redirect_box.update();
343         post_redirect_box.update();
344         mute_changed (0);
345         solo_changed (0);
346         name_changed (0);
347         comment_changed (0);
348         mix_group_changed (0);
349         gain_automation_state_changed ();
350         pan_automation_state_changed ();
351         connect_to_pan ();
352
353         panners.setup_pan ();
354
355         if (is_audio_track()) {
356                 speed_changed ();
357         }
358
359         update_diskstream_display ();
360         update_input_display ();
361         update_output_display ();
362
363         add_events (Gdk::BUTTON_RELEASE_MASK);
364 }
365
366 MixerStrip::~MixerStrip ()
367 {
368         GoingAway(); /* EMIT_SIGNAL */
369
370         if (input_selector) {
371                 delete input_selector;
372         }
373
374         if (output_selector) {
375                 delete output_selector;
376         }
377 }
378
379 void
380 MixerStrip::set_stuff_from_route ()
381 {
382         XMLProperty *prop;
383         
384         ensure_xml_node ();
385
386         if ((prop = xml_node->property ("strip_width")) != 0) {
387                 if (prop->value() == "wide") {
388                         set_width (Wide);
389                 } else if (prop->value() == "narrow") {
390                         set_width (Narrow);
391                 }
392                 else {
393                         error << string_compose(_("unknown strip width \"%1\" in XML GUI information"), prop->value()) << endmsg;
394                         set_width (Wide);
395                 }
396         }
397         else {
398                 set_width (Wide);
399         }
400
401         if ((prop = xml_node->property ("shown_mixer")) != 0) {
402                 if (prop->value() == "no") {
403                         _marked_for_display = false;
404                 } else {
405                         _marked_for_display = true;
406                 }
407         }
408         else {
409                 /* backwards compatibility */
410                 _marked_for_display = true;
411         }
412 }
413
414 void
415 MixerStrip::set_width (Width w)
416 {
417         /* always set the gpm width again, things may be hidden */
418         gpm.set_width (w);
419         panners.set_width (w);
420         pre_redirect_box.set_width (w);
421         post_redirect_box.set_width (w);
422         
423         if (_width == w) {
424                 return;
425         }
426
427         ensure_xml_node ();
428         
429         _width = w;
430
431         switch (w) {
432         case Wide:
433                 set_size_request (-1, -1);
434                 xml_node->add_property ("strip_width", "wide");
435
436                 rec_enable_button->set_label (_("RECORD"));
437                 mute_button->set_label  (_("mute"));
438                 solo_button->set_label (_("solo"));
439
440                 if (_route.comment() == "") {
441                        comment_button.set_label (_("Comments"));
442                 } else {
443                        comment_button.set_label (_("*Comments*"));
444                 }
445
446                 gain_automation_style_button.set_label (astyle_string(_route.gain_automation_curve().automation_style()));
447                 gain_automation_state_button.set_label (astate_string(_route.gain_automation_curve().automation_state()));
448                 pan_automation_style_button.set_label (astyle_string(_route.panner().automation_style()));
449                 pan_automation_state_button.set_label (astate_string(_route.panner().automation_state()));
450                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
451                 break;
452
453         case Narrow:
454                 set_size_request (50, -1);
455                 xml_node->add_property ("strip_width", "narrow");
456
457                 rec_enable_button->set_label (_("REC"));
458                 mute_button->set_label (_("m"));
459                 solo_button->set_label (_("s"));
460
461                 if (_route.comment() == "") {
462                        comment_button.set_label (_("Cmt"));
463                 } else {
464                        comment_button.set_label (_("*Cmt*"));
465                 }
466
467                 gain_automation_style_button.set_label (short_astyle_string(_route.gain_automation_curve().automation_style()));
468                 gain_automation_state_button.set_label (short_astate_string(_route.gain_automation_curve().automation_state()));
469                 pan_automation_style_button.set_label (short_astyle_string(_route.panner().automation_style()));
470                 pan_automation_state_button.set_label (short_astate_string(_route.panner().automation_state()));
471                 Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
472                 break;
473         }
474
475         update_input_display ();
476         update_output_display ();
477         mix_group_changed (0);
478         name_changed (0);
479
480 }
481
482 void
483 MixerStrip::set_packed (bool yn)
484 {
485         _packed = yn;
486
487         ensure_xml_node ();
488
489         if (_packed) {
490                 xml_node->add_property ("shown_mixer", "yes");
491         } else {
492                 xml_node->add_property ("shown_mixer", "no");
493         }
494 }
495
496
497 gint
498 MixerStrip::output_press (GdkEventButton *ev)
499 {
500         using namespace Menu_Helpers;
501
502         if (!_session.engine().connected()) {
503                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
504                 msg.run ();
505                 return true;
506         }
507
508         MenuList& citems = output_menu.items();
509         output_menu.set_name ("ArdourContextMenu");
510         citems.clear();
511
512         citems.push_back (MenuElem (_("Edit"), mem_fun(*this, &MixerStrip::edit_output_configuration)));
513         citems.push_back (SeparatorElem());
514         citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
515         citems.push_back (SeparatorElem());
516
517         _session.foreach_connection (this, &MixerStrip::add_connection_to_output_menu);
518
519         output_menu.popup (1, ev->time);
520
521         return TRUE;
522 }
523
524 void
525 MixerStrip::edit_output_configuration ()
526 {
527         if (output_selector == 0) {
528                 output_selector = new IOSelectorWindow (_session, _route, false);
529         } 
530
531         if (output_selector->is_visible()) {
532                 output_selector->get_toplevel()->get_window()->raise();
533         } else {
534                 output_selector->show_all ();
535         }
536 }
537
538 void
539 MixerStrip::edit_input_configuration ()
540 {
541         if (input_selector == 0) {
542                 input_selector = new IOSelectorWindow (_session, _route, true);
543         } 
544
545         if (input_selector->is_visible()) {
546                 input_selector->get_toplevel()->get_window()->raise();
547         } else {
548                 input_selector->show_all ();
549         }
550 }
551
552 gint
553 MixerStrip::input_press (GdkEventButton *ev)
554 {
555         using namespace Menu_Helpers;
556
557         MenuList& citems = input_menu.items();
558         input_menu.set_name ("ArdourContextMenu");
559         citems.clear();
560
561         if (!_session.engine().connected()) {
562                 MessageDialog msg (_("Not connected to JACK - no I/O changes are possible"));
563                 msg.run ();
564                 return true;
565         }
566
567 #if ADVANCED_ROUTE_DISKSTREAM_CONNECTIVITY
568         if (is_audio_track()) {
569                 citems.push_back (MenuElem (_("Track"), mem_fun(*this, &MixerStrip::select_stream_input)));
570         }
571 #endif
572         citems.push_back (MenuElem (_("Edit"), mem_fun(*this, &MixerStrip::edit_input_configuration)));
573         citems.push_back (SeparatorElem());
574         citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
575         citems.push_back (SeparatorElem());
576
577         _session.foreach_connection (this, &MixerStrip::add_connection_to_input_menu);
578         input_menu.popup (1, ev->time);
579
580         return TRUE;
581 }
582
583 void
584 MixerStrip::connection_input_chosen (ARDOUR::Connection *c)
585 {
586         if (!ignore_toggle) {
587
588                 try { 
589                         _route.use_input_connection (*c, this);
590                 }
591
592                 catch (AudioEngine::PortRegistrationFailure& err) {
593                         error << _("could not register new ports required for that connection")
594                               << endmsg;
595                 }
596         }
597 }
598
599 void
600 MixerStrip::connection_output_chosen (ARDOUR::Connection *c)
601 {
602         if (!ignore_toggle) {
603
604                 try { 
605                         _route.use_output_connection (*c, this);
606                 }
607
608                 catch (AudioEngine::PortRegistrationFailure& err) {
609                         error << _("could not register new ports required for that connection")
610                               << endmsg;
611                 }
612         }
613 }
614
615 void
616 MixerStrip::add_connection_to_input_menu (ARDOUR::Connection* c)
617 {
618         using namespace Menu_Helpers;
619
620         if (dynamic_cast<InputConnection *> (c) == 0) {
621                 return;
622         }
623
624         MenuList& citems = input_menu.items();
625         
626         if (c->nports() == _route.n_inputs()) {
627
628                 citems.push_back (CheckMenuElem (c->name(), bind (mem_fun(*this, &MixerStrip::connection_input_chosen), c)));
629                 
630                 ARDOUR::Connection *current = _route.input_connection();
631                 
632                 if (current == c) {
633                         ignore_toggle = true;
634                         dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
635                         ignore_toggle = false;
636                 }
637         }
638 }
639
640 void
641 MixerStrip::add_connection_to_output_menu (ARDOUR::Connection* c)
642 {
643         using namespace Menu_Helpers;
644
645         if (dynamic_cast<OutputConnection *> (c) == 0) {
646                 return;
647         }
648
649         if (c->nports() == _route.n_outputs()) {
650
651                 MenuList& citems = output_menu.items();
652                 citems.push_back (CheckMenuElem (c->name(), bind (mem_fun(*this, &MixerStrip::connection_output_chosen), c)));
653                 
654                 ARDOUR::Connection *current = _route.output_connection();
655                 
656                 if (current == c) {
657                         ignore_toggle = true;
658                         dynamic_cast<CheckMenuItem *> (&citems.back())->set_active (true);
659                         ignore_toggle = false;
660                 }
661         }
662 }
663
664 void
665 MixerStrip::select_stream_input ()
666 {
667         using namespace Menu_Helpers;
668
669         Menu *stream_menu = manage (new Menu);
670         MenuList& items = stream_menu->items();
671         stream_menu->set_name ("ArdourContextMenu");
672         
673         Session::DiskStreamList streams = _session.disk_streams();
674
675         for (Session::DiskStreamList::iterator i = streams.begin(); i != streams.end(); ++i) {
676
677                 if (!(*i)->hidden()) {
678
679                         items.push_back (CheckMenuElem ((*i)->name(), bind (mem_fun(*this, &MixerStrip::stream_input_chosen), *i)));
680                         
681                         if (get_diskstream() == *i) {
682                                 ignore_toggle = true;
683                                 static_cast<CheckMenuItem *> (&items.back())->set_active (true);
684                                 ignore_toggle = false;
685                         } 
686                 }
687         }
688         
689         stream_menu->popup (1, 0);
690 }
691
692 void
693 MixerStrip::stream_input_chosen (DiskStream *stream)
694 {
695         if (is_audio_track()) {
696                 audio_track()->set_diskstream (*stream, this);
697         }
698 }
699
700 void
701 MixerStrip::update_diskstream_display ()
702 {
703         if (is_audio_track()) {
704
705                 map_frozen ();
706
707                 update_input_display ();
708
709                 if (input_selector) {
710                         input_selector->hide_all ();
711                 }
712
713                 show_route_color ();
714
715         } else {
716
717                 map_frozen ();
718
719                 update_input_display ();
720                 show_passthru_color ();
721         }
722 }
723
724 void
725 MixerStrip::connect_to_pan ()
726 {
727         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::connect_to_pan));
728         
729         panstate_connection.disconnect ();
730         panstyle_connection.disconnect ();
731
732         if (!_route.panner().empty()) {
733                 StreamPanner* sp = _route.panner().front();
734
735                 panstate_connection = sp->automation().automation_state_changed.connect (mem_fun(*this, &MixerStrip::pan_automation_state_changed));
736                 panstyle_connection = sp->automation().automation_style_changed.connect (mem_fun(*this, &MixerStrip::pan_automation_style_changed));
737         }
738
739         panners.pan_changed (this);
740 }
741
742 void
743 MixerStrip::update_input_display ()
744 {
745         ARDOUR::Connection *c;
746
747         if ((c = _route.input_connection()) != 0) {
748                 input_label.set_text (c->name());
749         } else {
750                 switch (_width) {
751                 case Wide:
752                         input_label.set_text (_("INPUT"));
753                         break;
754                 case Narrow:
755                         input_label.set_text (_("IN"));
756                         break;
757                 }
758         }
759
760         panners.setup_pan ();
761 }
762
763 void
764 MixerStrip::update_output_display ()
765 {
766         ARDOUR::Connection *c;
767
768         if ((c = _route.output_connection()) != 0) {
769                 output_label.set_text (c->name());
770         } else {
771                 switch (_width) {
772                 case Wide:
773                         output_label.set_text (_("OUTPUT"));
774                         break;
775                 case Narrow:
776                         output_label.set_text (_("OUT"));
777                         break;
778                 }
779         }
780
781         gpm.setup_meters ();
782         panners.setup_pan ();
783 }
784
785 void
786 MixerStrip::fast_update ()
787 {
788         gpm.update_meters ();
789 }
790
791 gint
792 MixerStrip::gain_automation_state_button_event (GdkEventButton *ev)
793 {
794         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
795                 return TRUE;
796         }
797         
798         switch (ev->button) {
799         case 1:
800                 switch (ev->button) {
801                 case 1:
802                         gain_astate_menu.popup (1, ev->time);
803                         break;
804                 default:
805                         break;
806                 }
807         }
808
809         return TRUE;
810 }
811
812 gint
813 MixerStrip::gain_automation_style_button_event (GdkEventButton *ev)
814 {
815         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
816                 return TRUE;
817         }
818
819         switch (ev->button) {
820         case 1:
821                 gain_astyle_menu.popup (1, ev->time);
822                 break;
823         default:
824                 break;
825         }
826         return TRUE;
827 }
828
829 gint
830 MixerStrip::pan_automation_state_button_event (GdkEventButton *ev)
831 {
832         using namespace Menu_Helpers;
833
834         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
835                 return TRUE;
836         }
837
838         switch (ev->button) {
839         case 1:
840                 pan_astate_menu.popup (1, ev->time);
841                 break;
842         default:
843                 break;
844         }
845
846         return TRUE;
847 }
848
849 gint
850 MixerStrip::pan_automation_style_button_event (GdkEventButton *ev)
851 {
852         switch (ev->button) {
853         case 1:
854                 pan_astyle_menu.popup (1, ev->time);
855                 break;
856         default:
857                 break;
858         }
859         return TRUE;
860 }
861
862 string
863 MixerStrip::astate_string (AutoState state)
864 {
865         return _astate_string (state, false);
866 }
867
868 string
869 MixerStrip::short_astate_string (AutoState state)
870 {
871         return _astate_string (state, true);
872 }
873
874 string
875 MixerStrip::_astate_string (AutoState state, bool shrt)
876 {
877         string sstr;
878
879         switch (state) {
880         case Off:
881                 sstr = (shrt ? "--" : _("off"));
882                 break;
883         case Play:
884                 sstr = (shrt ? "P" : _("aplay"));
885                 break;
886         case Touch:
887                 sstr = (shrt ? "T" : _("touch"));
888                 break;
889         case Write:
890                 sstr = (shrt ? "W" : _("awrite"));
891                 break;
892         }
893
894         return sstr;
895 }
896
897 string
898 MixerStrip::astyle_string (AutoStyle style)
899 {
900         return _astyle_string (style, false);
901 }
902
903 string
904 MixerStrip::short_astyle_string (AutoStyle style)
905 {
906         return _astyle_string (style, true);
907 }
908
909 string
910 MixerStrip::_astyle_string (AutoStyle style, bool shrt)
911 {
912         if (style & Trim) {
913                 return _("trim");
914         } else {
915                 /* XXX it might different in different languages */
916
917                 return (shrt ? _("abs") : _("abs"));
918         }
919 }
920
921 void
922 MixerStrip::diskstream_changed (void *src)
923 {
924         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display));
925 }       
926
927 void
928 MixerStrip::gain_automation_style_changed ()
929 {
930         switch (_width) {
931         case Wide:
932                 gain_automation_style_button.set_label (astyle_string(_route.gain_automation_curve().automation_style()));
933                 break;
934         case Narrow:
935                 gain_automation_style_button.set_label  (short_astyle_string(_route.gain_automation_curve().automation_style()));
936                 break;
937         }
938 }
939
940 void
941 MixerStrip::gain_automation_state_changed ()
942 {
943         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::gain_automation_state_changed));
944         
945         bool x;
946
947         switch (_width) {
948         case Wide:
949                 gain_automation_state_button.set_label (astate_string(_route.gain_automation_curve().automation_state()));
950                 break;
951         case Narrow:
952                 gain_automation_state_button.set_label (short_astate_string(_route.gain_automation_curve().automation_state()));
953                 break;
954         }
955
956         x = (_route.gain_automation_state() != Off);
957         
958         if (gain_automation_state_button.get_active() != x) {
959                 ignore_toggle = true;
960                 gain_automation_state_button.set_active (x);
961                 ignore_toggle = false;
962         }
963
964         gpm.update_gain_sensitive ();
965         
966         /* start watching automation so that things move */
967         
968         gain_watching.disconnect();
969
970         if (x) {
971                 gain_watching = ARDOUR_UI::RapidScreenUpdate.connect (mem_fun (gpm, &GainMeter::effective_gain_display));
972         }
973 }
974
975 void
976 MixerStrip::pan_automation_style_changed ()
977 {
978         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::pan_automation_style_changed));
979         
980         switch (_width) {
981         case Wide:
982                 pan_automation_style_button.set_label (astyle_string(_route.panner().automation_style()));
983                 break;
984         case Narrow:
985                 pan_automation_style_button.set_label (short_astyle_string(_route.panner().automation_style()));
986                 break;
987         }
988 }
989
990 void
991 MixerStrip::pan_automation_state_changed ()
992 {
993         ENSURE_GUI_THREAD(mem_fun(*this, &MixerStrip::pan_automation_state_changed));
994         
995         bool x;
996
997         switch (_width) {
998         case Wide:
999                 pan_automation_state_button.set_label (astate_string(_route.panner().automation_state()));
1000                 break;
1001         case Narrow:
1002                 pan_automation_state_button.set_label (short_astate_string(_route.panner().automation_state()));
1003                 break;
1004         }
1005
1006         /* when creating a new session, we get to create busses (and
1007            sometimes tracks) with no outputs by the time they get
1008            here.
1009         */
1010
1011         if (_route.panner().empty()) {
1012                 return;
1013         }
1014
1015         x = (_route.panner().front()->automation().automation_state() != Off);
1016
1017         if (pan_automation_state_button.get_active() != x) {
1018                 ignore_toggle = true;
1019                 pan_automation_state_button.set_active (x);
1020                 ignore_toggle = false;
1021         }
1022
1023         panners.update_pan_sensitive ();
1024         
1025         /* start watching automation so that things move */
1026         
1027         pan_watching.disconnect();
1028
1029         if (x) {
1030                 pan_watching = ARDOUR_UI::RapidScreenUpdate.connect (mem_fun (panners, &PannerUI::effective_pan_display));
1031         }
1032 }
1033
1034 void
1035 MixerStrip::input_changed (IOChange change, void *src)
1036 {
1037         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_input_display));
1038 }
1039
1040 void
1041 MixerStrip::output_changed (IOChange change, void *src)
1042 {
1043         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_output_display));
1044 }
1045
1046 void
1047 MixerStrip::comment_button_clicked ()
1048 {
1049         if (comment_window == 0) {
1050                 setup_comment_editor ();
1051         }
1052
1053         if (comment_window->is_visible()) {
1054                string str =  comment_area->get_buffer()->get_text();
1055                if (_route.comment() != str) {
1056                  _route.set_comment (str, this);
1057
1058                  switch (_width) {
1059                    
1060                  case Wide:
1061                    if (! str.empty()) {
1062                      comment_button.set_label (_("*Comments*"));
1063                    } else {
1064                      comment_button.set_label (_("Comments"));
1065                       }
1066                    break;
1067                    
1068                  case Narrow:
1069                    if (! str.empty()) {
1070                      comment_button.set_label (_("*Cmt*"));
1071                    } else {
1072                      comment_button.set_label (_("Cmt"));
1073                    } 
1074                    break;
1075                  }
1076                  
1077                  ARDOUR_UI::instance()->tooltips().set_tip (comment_button, 
1078                                                             str.empty() ? _("Click to Add/Edit Comments") : str);
1079                }
1080                comment_window->hide ();
1081                return;
1082         } 
1083         
1084         comment_window->set_position (Gtk::WIN_POS_MOUSE);
1085         comment_window->show();
1086         comment_window->present();
1087
1088 }
1089
1090 void
1091 MixerStrip::setup_comment_editor ()
1092 {
1093         string title;
1094         title = _route.name();
1095         title += _(": comment editor");
1096
1097         comment_window = new ArdourDialog (title, false);
1098         comment_area = manage (new TextView());
1099
1100         comment_area->set_name ("MixerTrackCommentArea");
1101         comment_area->set_editable (true);
1102         comment_area->get_buffer()->set_text (_route.comment());
1103         comment_area->set_size_request (200,124);
1104         comment_area->show ();
1105
1106         comment_window->get_vbox()->pack_start (*comment_area);
1107         comment_window->get_action_area()->hide();
1108 }
1109
1110 void
1111 MixerStrip::comment_changed (void *src)
1112 {
1113         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::comment_changed), src));
1114         
1115         if (src != this) {
1116                 ignore_comment_edit = true;
1117                 if (comment_area) {
1118                         comment_area->get_buffer()->set_text (_route.comment());
1119                 }
1120                 ignore_comment_edit = false;
1121         }
1122 }
1123
1124 void
1125 MixerStrip::set_mix_group (RouteGroup *rg)
1126 {
1127         _route.set_mix_group (rg, this);
1128 }
1129
1130 void
1131 MixerStrip::add_mix_group_to_menu (RouteGroup *rg, RadioMenuItem::Group* group)
1132 {
1133         using namespace Menu_Helpers;
1134
1135         MenuList& items = group_menu->items();
1136
1137         items.push_back (RadioMenuElem (*group, rg->name(), bind (mem_fun(*this, &MixerStrip::set_mix_group), rg)));
1138
1139         if (_route.mix_group() == rg) {
1140                 static_cast<RadioMenuItem*>(&items.back())->set_active ();
1141         }
1142 }
1143
1144 bool
1145 MixerStrip::select_mix_group (GdkEventButton *ev)
1146 {
1147         using namespace Menu_Helpers;
1148
1149         if (group_menu == 0) {
1150                 group_menu = new Menu;
1151         } 
1152         group_menu->set_name ("ArdourContextMenu");
1153         MenuList& items = group_menu->items();
1154         RadioMenuItem::Group group;
1155
1156         items.clear ();
1157         items.push_back (RadioMenuElem (group, _("no group"), bind (mem_fun(*this, &MixerStrip::set_mix_group), (RouteGroup *) 0)));
1158
1159         _session.foreach_mix_group (bind (mem_fun (*this, &MixerStrip::add_mix_group_to_menu), &group));
1160         
1161         group_menu->popup (1, 0);
1162
1163         return true;
1164 }       
1165
1166 void
1167 MixerStrip::mix_group_changed (void *ignored)
1168 {
1169         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::mix_group_changed), ignored));
1170         
1171         RouteGroup *rg = _route.mix_group();
1172         
1173         if (rg) {
1174                 group_label.set_text (rg->name());
1175         } else {
1176                 switch (_width) {
1177                 case Wide:
1178                         group_label.set_text (_("no group"));
1179                         break;
1180                 case Narrow:
1181                         group_label.set_text (_("~G"));
1182                         break;
1183                 }
1184         }
1185 }
1186
1187
1188 void 
1189 MixerStrip::route_gui_changed (string what_changed, void* ignored)
1190 {
1191         ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_gui_changed), what_changed, ignored));
1192         
1193         if (what_changed == "color") {
1194                 if (set_color_from_route () == 0) {
1195                         show_route_color ();
1196                 }
1197         }
1198 }
1199
1200 void
1201 MixerStrip::show_route_color ()
1202 {
1203         name_button.modify_bg (STATE_NORMAL, color());
1204         route_active_changed ();
1205 }
1206
1207 void
1208 MixerStrip::show_passthru_color ()
1209 {
1210         route_active_changed ();
1211 }
1212
1213 void
1214 MixerStrip::build_route_ops_menu ()
1215 {
1216         using namespace Menu_Helpers;
1217
1218         route_ops_menu = manage (new Menu);
1219         route_ops_menu->set_name ("ArdourContextMenu");
1220
1221         MenuList& items = route_ops_menu->items();
1222         
1223         items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteUI::route_rename)));
1224         items.push_back (SeparatorElem());
1225         items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
1226         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1227         route_active_menu_item->set_active (_route.active());
1228         items.push_back (SeparatorElem());
1229         items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
1230         polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
1231         polarity_menu_item->set_active (_route.phase_invert());
1232
1233         build_remote_control_menu ();
1234         
1235         items.push_back (SeparatorElem());
1236         items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu));
1237
1238         items.push_back (SeparatorElem());
1239         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
1240 }
1241
1242 gint
1243 MixerStrip::name_button_button_release (GdkEventButton* ev)
1244 {
1245         if (ev->button == 3) {
1246                 list_route_operations ();
1247         }
1248         return FALSE;
1249 }
1250
1251 void
1252 MixerStrip::list_route_operations ()
1253 {
1254         if (route_ops_menu == 0) {
1255                 build_route_ops_menu ();
1256         }
1257         
1258         refresh_remote_control_menu();
1259
1260         route_ops_menu->popup (1, 0);
1261 }
1262
1263
1264 void
1265 MixerStrip::speed_adjustment_changed ()
1266 {
1267         /* since there is a usable speed adjustment, there has to be a diskstream */
1268         if (!ignore_speed_adjustment) {
1269                 get_diskstream()->set_speed (speed_adjustment.get_value());
1270         }
1271 }
1272
1273 void
1274 MixerStrip::speed_changed ()
1275 {
1276         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_speed_display));
1277 }
1278
1279 void
1280 MixerStrip::update_speed_display ()
1281 {
1282         float val;
1283         
1284         val = get_diskstream()->speed();
1285
1286         if (val != 1.0) {
1287                 speed_spinner.set_name ("MixerStripSpeedBaseNotOne");
1288         } else {
1289                 speed_spinner.set_name ("MixerStripSpeedBase");
1290         }
1291
1292         if (speed_adjustment.get_value() != val) {
1293                 ignore_speed_adjustment = true;
1294                 speed_adjustment.set_value (val);
1295                 ignore_speed_adjustment = false;
1296         }
1297 }                       
1298
1299
1300 void
1301 MixerStrip::set_selected (bool yn)
1302 {
1303         AxisView::set_selected (yn);
1304         if (_selected) {
1305                 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1306                 global_frame.set_name ("MixerStripSelectedFrame");
1307         } else {
1308                 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1309                 global_frame.set_name ("MixerStripFrame");
1310         }
1311         global_frame.queue_draw ();
1312 }
1313
1314 void
1315 MixerStrip::name_changed (void *src)
1316 {
1317         switch (_width) {
1318         case Wide:
1319                 RouteUI::name_changed (src);
1320                 break;
1321         case Narrow:
1322                 name_label.set_text (PBD::short_version (_route.name(), 5));
1323                 break;
1324         }
1325 }
1326
1327 void
1328 MixerStrip::width_clicked ()
1329 {
1330         switch (_width) {
1331         case Wide:
1332                 set_width (Narrow);
1333                 break;
1334         case Narrow:
1335                 set_width (Wide);
1336                 break;
1337         }
1338 }
1339
1340 void
1341 MixerStrip::hide_clicked ()
1342 {
1343         if (_embedded) {
1344                  Hiding(); /* EMIT_SIGNAL */
1345         } else {
1346                 _mixer.hide_strip (this);
1347         }
1348 }
1349
1350 void
1351 MixerStrip::set_embedded (bool yn)
1352 {
1353         _embedded = yn;
1354 }
1355
1356 void
1357 MixerStrip::map_frozen ()
1358 {
1359         ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::map_frozen));
1360
1361         AudioTrack* at = dynamic_cast<AudioTrack*>(&_route);
1362
1363         if (at) {
1364                 switch (at->freeze_state()) {
1365                 case AudioTrack::Frozen:
1366                         pre_redirect_box.set_sensitive (false);
1367                         post_redirect_box.set_sensitive (false);
1368                         speed_spinner.set_sensitive (false);
1369                         break;
1370                 default:
1371                         pre_redirect_box.set_sensitive (true);
1372                         post_redirect_box.set_sensitive (true);
1373                         speed_spinner.set_sensitive (true);
1374                         break;
1375                 }
1376         }
1377         _route.foreach_redirect (this, &MixerStrip::hide_redirect_editor);
1378 }
1379
1380 void
1381 MixerStrip::hide_redirect_editor (Redirect* redirect)
1382 {
1383         void* gui = redirect->get_gui ();
1384         
1385         if (gui) {
1386                 static_cast<Gtk::Widget*>(gui)->hide ();
1387         }
1388 }
1389
1390 void
1391 MixerStrip::route_active_changed ()
1392 {
1393         RouteUI::route_active_changed ();
1394
1395         if (is_audio_track()) {
1396                 if (_route.active()) {
1397                         set_name ("AudioTrackStripBase");
1398                         gpm.set_meter_strip_name ("AudioTrackStripBase");
1399                 } else {
1400                         set_name ("AudioTrackStripBaseInactive");
1401                         gpm.set_meter_strip_name ("AudioTrackStripBaseInactive");
1402                 }
1403                 gpm.set_fader_name ("AudioTrackFader");
1404         } else {
1405                 if (_route.active()) {
1406                         set_name ("AudioBusStripBase");
1407                         gpm.set_meter_strip_name ("AudioBusStripBase");
1408                 } else {
1409                         set_name ("AudioBusStripBaseInactive");
1410                         gpm.set_meter_strip_name ("AudioBusStripBaseInactive");
1411                 }
1412                 gpm.set_fader_name ("AudioBusFader");
1413         }
1414 }
1415
1416 RouteGroup*
1417 MixerStrip::mix_group() const
1418 {
1419         return _route.mix_group();
1420 }