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