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