remove almost-unusued stop_signal.h and clean up the one (unused) place where it...
[ardour.git] / gtk2_ardour / panner_ui.cc
1 /*
2   Copyright (C) 2004 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 <limits.h>
20
21 #include "ardour/io.h"
22 #include "ardour/dB.h"
23 #include <gtkmm2ext/utils.h>
24 #include <gtkmm2ext/barcontroller.h>
25 #include "midi++/manager.h"
26 #include "pbd/fastlog.h"
27
28 #include "ardour_ui.h"
29 #include "panner_ui.h"
30 #include "panner2d.h"
31 #include "utils.h"
32 #include "panner.h"
33 #include "gui_thread.h"
34
35 #include "ardour/delivery.h"
36 #include "ardour/session.h"
37 #include "ardour/panner.h"
38 #include "ardour/route.h"
39
40 #include "i18n.h"
41
42 using namespace std;
43 using namespace ARDOUR;
44 using namespace PBD;
45 using namespace Gtkmm2ext;
46 using namespace Gtk;
47
48 const int PannerUI::pan_bar_height = 30;
49
50 PannerUI::PannerUI (Session* s)
51         : _current_nouts (-1)
52         , _current_npans (-1)
53         , hAdjustment(0.0, 0.0, 0.0)
54         , vAdjustment(0.0, 0.0, 0.0)
55         , panning_viewport(hAdjustment, vAdjustment)
56         , panning_up_arrow (Gtk::ARROW_UP, Gtk::SHADOW_OUT)
57         , panning_down_arrow (Gtk::ARROW_DOWN, Gtk::SHADOW_OUT)
58         , panning_link_button (_("link"))
59         , pan_automation_style_button ("")
60         , pan_automation_state_button ("")
61 {
62         set_session (s);
63
64         ignore_toggle = false;
65         pan_menu = 0;
66         pan_astate_menu = 0;
67         pan_astyle_menu = 0;
68         in_pan_update = false;
69
70         pan_automation_style_button.set_name ("MixerAutomationModeButton");
71         pan_automation_state_button.set_name ("MixerAutomationPlaybackButton");
72
73         ARDOUR_UI::instance()->set_tip (pan_automation_state_button, _("Pan automation mode"));
74         ARDOUR_UI::instance()->set_tip (pan_automation_style_button, _("Pan automation type"));
75
76         //set_size_request_to_display_given_text (pan_automation_state_button, X_("O"), 2, 2);
77         //set_size_request_to_display_given_text (pan_automation_style_button, X_("0"), 2, 2);
78
79         panning_viewport.set_name (X_("BaseFrame"));
80
81         ARDOUR_UI::instance()->set_tip (panning_link_button,
82                                                    _("panning link control"));
83         ARDOUR_UI::instance()->set_tip (panning_link_direction_button,
84                                                    _("panning link direction"));
85
86         pan_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
87         pan_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
88
89         pan_automation_style_button.signal_button_press_event().connect (sigc::mem_fun(*this, &PannerUI::pan_automation_style_button_event), false);
90         pan_automation_state_button.signal_button_press_event().connect (sigc::mem_fun(*this, &PannerUI::pan_automation_state_button_event), false);
91
92         panning_link_button.set_name (X_("PanningLinkButton"));
93         panning_link_direction_button.set_name (X_("PanningLinkDirectionButton"));
94
95         panning_link_box.pack_start (panning_link_button, true, true);
96         panning_link_box.pack_start (panning_link_direction_button, true, true);
97         panning_link_box.pack_start (pan_automation_state_button, true, true);
98
99         /* the pixmap will be reset at some point, but the key thing is that
100            we need a pixmap in the button just to get started.
101         */
102         panning_link_direction_button.add (*(manage (new Image (get_xpm("forwardblarrow.xpm")))));
103
104         panning_link_direction_button.signal_clicked().connect
105                 (sigc::mem_fun(*this, &PannerUI::panning_link_direction_clicked));
106
107         panning_link_button.signal_button_press_event().connect
108                 (sigc::mem_fun(*this, &PannerUI::panning_link_button_press), false);
109         panning_link_button.signal_button_release_event().connect
110                 (sigc::mem_fun(*this, &PannerUI::panning_link_button_release), false);
111
112         panning_up.set_border_width (3);
113         panning_down.set_border_width (3);
114         panning_up.add (panning_up_arrow);
115         panning_down.add (panning_down_arrow);
116         panning_up.set_name (X_("PanScrollerBase"));
117         panning_down.set_name (X_("PanScrollerBase"));
118         panning_up_arrow.set_name (X_("PanScrollerArrow"));
119         panning_down_arrow.set_name (X_("PanScrollerArrow"));
120
121         pan_vbox.set_spacing (2);
122         pan_vbox.pack_start (panning_viewport, Gtk::PACK_SHRINK);
123         pan_vbox.pack_start (panning_link_box, Gtk::PACK_SHRINK);
124
125         pack_start (pan_vbox, true, true);
126
127         twod_panner = 0;
128         big_window = 0;
129
130         set_width(Narrow);
131 }
132
133 void
134 PannerUI::set_panner (boost::shared_ptr<Panner> p)
135 {
136         connections.drop_connections ();
137
138         delete pan_astyle_menu;
139         pan_astyle_menu = 0;
140
141         delete pan_astate_menu;
142         pan_astate_menu = 0;
143
144         _panner = p;
145
146         delete twod_panner;
147         twod_panner = 0;
148
149         if (!_panner) {
150                 return;
151         }
152
153         _panner->Changed.connect (connections, invalidator (*this), boost::bind (&PannerUI::panner_changed, this), gui_context());
154         _panner->LinkStateChanged.connect (connections, invalidator (*this), boost::bind (&PannerUI::update_pan_linkage, this), gui_context());
155         _panner->StateChanged.connect (connections, invalidator (*this), boost::bind (&PannerUI::update_pan_state, this), gui_context());
156
157         setup_pan ();
158
159         pan_changed (0);
160         update_pan_sensitive ();
161         update_pan_linkage ();
162         pan_automation_state_changed ();
163 }
164
165 void
166 PannerUI::build_astate_menu ()
167 {
168         using namespace Menu_Helpers;
169
170         if (pan_astate_menu == 0) {
171                 pan_astate_menu = new Menu;
172                 pan_astate_menu->set_name ("ArdourContextMenu");
173         } else {
174                 pan_astate_menu->items().clear ();
175         }
176
177         pan_astate_menu->items().push_back (MenuElem (_("Manual"), sigc::bind (
178                         sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
179                         (AutoState) Off)));
180         pan_astate_menu->items().push_back (MenuElem (_("Play"), sigc::bind (
181                         sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
182                         (AutoState) Play)));
183         pan_astate_menu->items().push_back (MenuElem (_("Write"), sigc::bind (
184                         sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
185                         (AutoState) Write)));
186         pan_astate_menu->items().push_back (MenuElem (_("Touch"), sigc::bind (
187                         sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
188                         (AutoState) Touch)));
189
190 }
191
192 void
193 PannerUI::build_astyle_menu ()
194 {
195         using namespace Menu_Helpers;
196
197         if (pan_astyle_menu == 0) {
198                 pan_astyle_menu = new Menu;
199                 pan_astyle_menu->set_name ("ArdourContextMenu");
200         } else {
201                 pan_astyle_menu->items().clear();
202         }
203
204         pan_astyle_menu->items().push_back (MenuElem (_("Trim")));
205         pan_astyle_menu->items().push_back (MenuElem (_("Abs")));
206 }
207
208 boost::shared_ptr<PBD::Controllable>
209 PannerUI::get_controllable()
210 {
211         return pan_bars[0]->get_controllable();
212 }
213
214 bool
215 PannerUI::panning_link_button_press (GdkEventButton*)
216 {
217         return true;
218 }
219
220 bool
221 PannerUI::panning_link_button_release (GdkEventButton*)
222 {
223         if (!ignore_toggle) {
224                 _panner->set_linked (!_panner->linked());
225         }
226         return true;
227 }
228
229 void
230 PannerUI::panning_link_direction_clicked()
231 {
232         switch (_panner->link_direction()) {
233         case Panner::SameDirection:
234                 _panner->set_link_direction (Panner::OppositeDirection);
235                 break;
236         default:
237                 _panner->set_link_direction (Panner::SameDirection);
238                 break;
239         }
240 }
241
242 void
243 PannerUI::update_pan_linkage ()
244 {
245         ENSURE_GUI_THREAD (*this, &PannerUI::update_pan_linkage)
246
247         bool const x = _panner->linked();
248         bool const bx = panning_link_button.get_active();
249
250         if (x != bx) {
251
252                 ignore_toggle = true;
253                 panning_link_button.set_active (x);
254                 ignore_toggle = false;
255         }
256
257         panning_link_direction_button.set_sensitive (x);
258
259         switch (_panner->link_direction()) {
260         case Panner::SameDirection:
261                 panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm")))));
262                 break;
263         default:
264                 panning_link_direction_button.set_image (*(manage (new Image (get_xpm("revdblarrow.xpm")))));
265                 break;
266         }
267 }
268
269 void
270 PannerUI::set_width (Width w)
271 {
272         switch (w) {
273         case Wide:
274                 panning_link_button.set_label (_("link"));
275                 break;
276         case Narrow:
277                 panning_link_button.set_label (_("L"));
278                 break;
279         }
280
281         _width = w;
282 }
283
284
285 PannerUI::~PannerUI ()
286 {
287         for (vector<Adjustment*>::iterator i = pan_adjustments.begin(); i != pan_adjustments.end(); ++i) {
288                 delete (*i);
289         }
290
291         for (vector<PannerBar*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) {
292                 delete (*i);
293         }
294
295         delete twod_panner;
296         delete big_window;
297         delete pan_menu;
298         delete pan_astyle_menu;
299         delete pan_astate_menu;
300 }
301
302
303 void
304 PannerUI::panner_changed ()
305 {
306         ENSURE_GUI_THREAD (*this, &PannerUI::panner_changed)
307         setup_pan ();
308         pan_changed (0);
309 }
310
311 void
312 PannerUI::update_pan_state ()
313 {
314         /* currently nothing to do */
315         // ENSURE_GUI_THREAD (*this, &PannerUI::update_panner_state)
316 }
317
318 void
319 PannerUI::setup_pan ()
320 {
321         if (!_panner) {
322                 return;
323         }
324
325         uint32_t const nouts = _panner->nouts();
326         uint32_t const npans = _panner->npanners();
327
328         if (int32_t (nouts) == _current_nouts && int32_t (npans) == _current_npans) {
329                 return;
330         }
331
332         _pan_control_connections.drop_connections ();
333         for (uint32_t i = 0; i < _panner->npanners(); ++i) {
334                 connect_to_pan_control (i);
335         }
336
337         _current_nouts = nouts;
338         _current_npans = npans;
339
340         if (nouts == 0 || nouts == 1) {
341
342                 while (!pan_adjustments.empty()) {
343                         delete pan_bars.back();
344                         pan_bars.pop_back ();
345                         delete pan_adjustments.back();
346                         pan_adjustments.pop_back ();
347                 }
348
349                 delete twod_panner;
350                 twod_panner = 0;
351
352                 /* stick something into the panning viewport so that it redraws */
353
354                 EventBox* eb = manage (new EventBox());
355                 panning_viewport.remove ();
356                 panning_viewport.add (*eb);
357                 panning_viewport.show_all ();
358
359         } else if (nouts == 2) {
360
361                 vector<Adjustment*>::size_type asz;
362
363                 while (!pan_adjustments.empty()) {
364                         delete pan_bars.back();
365                         pan_bars.pop_back ();
366                         delete pan_adjustments.back();
367                         pan_adjustments.pop_back ();
368                 }
369
370                 delete twod_panner;
371                 twod_panner = 0;
372
373                 while ((asz = pan_adjustments.size()) < npans) {
374
375                         float x, rx;
376                         PannerBar* bc;
377
378                         /* initialize adjustment with 0.0 (L) or 1.0 (R) for the first and second panners,
379                            which serves as a default, otherwise use current value */
380
381                         rx = _panner->pan_control( asz)->get_value();
382
383                         if (npans == 1) {
384                                 x = 0.5;
385                         } else if (asz == 0) {
386                                 x = 0.0;
387                         } else if (asz == 1) {
388                                 x = 1.0;
389                         } else {
390                                 x = rx;
391                         }
392
393                         pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.005, 0.05));
394                         bc = new PannerBar (*pan_adjustments[asz],
395                                 boost::static_pointer_cast<PBD::Controllable>( _panner->pan_control( asz )) );
396
397                         /* now set adjustment with current value of panner, then connect the signals */
398                         pan_adjustments.back()->set_value(rx);
399                         pan_adjustments.back()->signal_value_changed().connect (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_adjustment_changed), (uint32_t) asz));
400                         connect_to_pan_control (asz);
401
402                         bc->set_name ("PanSlider");
403                         bc->set_shadow_type (Gtk::SHADOW_NONE);
404
405                         boost::shared_ptr<AutomationControl> ac = _panner->pan_control (asz);
406
407                         if (asz) {
408                                 bc->StartGesture.connect (sigc::mem_fun (*ac, &AutomationControl::start_touch));
409                                 bc->StopGesture.connect (sigc::mem_fun (*ac, &AutomationControl::stop_touch));
410                         }
411
412                         char buf[64];
413                         snprintf (buf, sizeof (buf), _("panner for channel %zu"), asz + 1);
414                         ARDOUR_UI::instance()->set_tip (bc->event_widget(), buf);
415
416                         bc->event_widget().signal_button_release_event().connect
417                                 (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_button_event), (uint32_t) asz));
418
419                         bc->set_size_request (-1, pan_bar_height);
420
421                         pan_bars.push_back (bc);
422                         pan_bar_packer.pack_start (*bc, false, false);
423                 }
424
425                 /* now that we actually have the pan bars,
426                    set their sensitivity based on current
427                    automation state.
428                 */
429
430                 update_pan_sensitive ();
431
432                 panning_viewport.remove ();
433                 panning_viewport.add (pan_bar_packer);
434                 panning_viewport.show_all ();
435
436         } else {
437
438                 if (!twod_panner) {
439                         twod_panner = new Panner2d (_panner, 61);
440                         twod_panner->set_name ("MixerPanZone");
441                         twod_panner->show ();
442
443                         twod_panner->signal_button_press_event().connect
444                                 (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_button_event), (uint32_t) 0), false);
445                 }
446
447                 update_pan_sensitive ();
448                 twod_panner->reset (npans);
449                 if (big_window) {
450                         big_window->reset (npans);
451                 }
452                 twod_panner->set_size_request (-1, 61);
453
454                 /* and finally, add it to the panner frame */
455
456                 panning_viewport.remove ();
457                 panning_viewport.add (*twod_panner);
458                 panning_viewport.show_all ();
459         }
460 }
461
462 bool
463 PannerUI::pan_button_event (GdkEventButton* ev, uint32_t which)
464 {
465         switch (ev->button) {
466         case 1:
467                 if (twod_panner && ev->type == GDK_2BUTTON_PRESS) {
468                         if (!big_window) {
469                                 big_window = new Panner2dWindow (_panner, 400, _panner->npanners());
470                         }
471                         big_window->show ();
472                         return true;
473                 }
474                 break;
475
476         case 3:
477                 if (pan_menu == 0) {
478                         pan_menu = manage (new Menu);
479                         pan_menu->set_name ("ArdourContextMenu");
480                 }
481                 build_pan_menu (which);
482                 pan_menu->popup (1, ev->time);
483                 return true;
484                 break;
485         default:
486                 return false;
487         }
488
489         return false; // what's wrong with gcc?
490 }
491
492 void
493 PannerUI::build_pan_menu (uint32_t which)
494 {
495         using namespace Menu_Helpers;
496         MenuList& items (pan_menu->items());
497
498         items.clear ();
499
500         items.push_back (CheckMenuElem (_("Mute")));
501
502         /* set state first, connect second */
503
504         (dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_panner->streampanner(which).muted());
505         (dynamic_cast<CheckMenuItem*> (&items.back()))->signal_toggled().connect
506                 (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_mute), which));
507
508         items.push_back (CheckMenuElem (_("Bypass"), sigc::mem_fun(*this, &PannerUI::pan_bypass_toggle)));
509         bypass_menu_item = static_cast<CheckMenuItem*> (&items.back());
510
511         /* set state first, connect second */
512
513         bypass_menu_item->set_active (_panner->bypassed());
514         bypass_menu_item->signal_toggled().connect (sigc::mem_fun(*this, &PannerUI::pan_bypass_toggle));
515
516         items.push_back (MenuElem (_("Reset"), sigc::bind (sigc::mem_fun (*this, &PannerUI::pan_reset), which)));
517         items.push_back (SeparatorElem());
518         items.push_back (MenuElem (_("Reset all"), sigc::mem_fun (*this, &PannerUI::pan_reset_all)));
519 }
520
521 void
522 PannerUI::pan_mute (uint32_t which)
523 {
524         StreamPanner& sp = _panner->streampanner(which);
525         sp.set_muted (!sp.muted());
526 }
527
528 void
529 PannerUI::pan_bypass_toggle ()
530 {
531         if (bypass_menu_item && (_panner->bypassed() != bypass_menu_item->get_active())) {
532                 _panner->set_bypassed (!_panner->bypassed());
533         }
534 }
535
536 void
537 PannerUI::pan_reset (uint32_t which)
538 {
539         _panner->reset_streampanner (which);
540 }
541
542 void
543 PannerUI::pan_reset_all ()
544 {
545         _panner->reset_to_default ();
546 }
547
548 void
549 PannerUI::effective_pan_display ()
550 {
551         if (_panner->empty()) {
552                 return;
553         }
554
555         switch (_panner->nouts()) {
556         case 0:
557         case 1:
558                 /* relax */
559                 break;
560
561         case 2:
562                 update_pan_bars (true);
563                 break;
564
565         default:
566                 //panner->move_puck (pan_value (v, right), 0.5);
567                 break;
568         }
569 }
570
571 void
572 PannerUI::pan_changed (void *src)
573 {
574         if (src == this) {
575                 return;
576         }
577
578         switch (_panner->npanners()) {
579         case 0:
580                 panning_link_direction_button.set_sensitive (false);
581                 panning_link_button.set_sensitive (false);
582                 return;
583         case 1:
584                 panning_link_direction_button.set_sensitive (false);
585                 panning_link_button.set_sensitive (false);
586                 break;
587         default:
588                 panning_link_direction_button.set_sensitive (_panner->linked ());
589                 panning_link_button.set_sensitive (true);
590         }
591
592         uint32_t const nouts = _panner->nouts();
593
594         switch (nouts) {
595         case 0:
596         case 1:
597                 /* relax */
598                 break;
599
600         case 2:
601                 /* bring pan bar state up to date */
602                 update_pan_bars (false);
603                 break;
604
605         default:
606                 // panner->move_puck (pan_value (pans[0], pans[1]), 0.5);
607                 break;
608         }
609 }
610
611 void
612 PannerUI::pan_adjustment_changed (uint32_t which)
613 {
614         if (!in_pan_update && which < _panner->npanners()) {
615
616                 float val = pan_adjustments[which]->get_value ();
617                 float const xpos = _panner->pan_control(which)->get_value();
618
619                 /* add a kinda-sorta detent for the middle */
620
621                 if (val != 0.5 && Panner::equivalent (val, 0.5)) {
622                         /* this is going to be reentrant, so just
623                            return after it.
624                         */
625
626                         in_pan_update = true;
627                         pan_adjustments[which]->set_value (0.5);
628                         in_pan_update = false;
629                         return;
630                 }
631
632                 if (!Panner::equivalent (val, xpos)) {
633
634                         _panner->pan_control(which)->set_value (val);
635                         /* XXX
636                            the panner objects have no access to the session,
637                            so do this here. ick.
638                         */
639                         _session->set_dirty();
640                 }
641         }
642 }
643
644 void
645 PannerUI::pan_value_changed (uint32_t which)
646 {
647         ENSURE_GUI_THREAD (*this, &PannerUI::pan_value_changed, which)
648
649         if (twod_panner) {
650
651                 float x;
652                 float y;
653                 _panner->streampanner(which).get_position (x, y);
654
655                 in_pan_update = true;
656                 twod_panner->move_puck (which, x, y);
657                 in_pan_update = false;
658
659         } else if (_panner->npanners() > 0 && which < _panner->npanners()) {
660                 float xpos;
661                 float val = pan_adjustments[which]->get_value ();
662
663                 _panner->streampanner(which).get_position (xpos);
664
665                 if (!Panner::equivalent (val, xpos)) {
666                         in_pan_update = true;
667                         pan_adjustments[which]->set_value (xpos);
668                         in_pan_update = false;
669                 }
670         }
671 }
672
673 void
674 PannerUI::update_pan_bars (bool only_if_aplay)
675 {
676         uint32_t n;
677         vector<Adjustment*>::iterator i;
678
679         in_pan_update = true;
680
681         /* this runs during automation playback, and moves the bar controllers
682            and/or pucks around.
683         */
684
685         for (i = pan_adjustments.begin(), n = 0; i != pan_adjustments.end(); ++i, ++n) {
686                 float xpos, val;
687
688                 if (only_if_aplay) {
689                         boost::shared_ptr<AutomationList> alist (_panner->streampanner(n).pan_control()->alist());
690
691                         if (!alist->automation_playback()) {
692                                 continue;
693                         }
694                 }
695
696                 _panner->streampanner(n).get_effective_position (xpos);
697                 val = (*i)->get_value ();
698
699                 if (!Panner::equivalent (val, xpos)) {
700                         (*i)->set_value (xpos);
701                 }
702         }
703
704         in_pan_update = false;
705 }
706
707 void
708 PannerUI::update_pan_sensitive ()
709 {
710         bool const sensitive = !(_panner->mono()) && !(_panner->automation_state() & Play);
711
712         switch (_panner->nouts()) {
713         case 0:
714         case 1:
715                 break;
716         case 2:
717                 for (vector<PannerBar*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) {
718                         (*i)->set_sensitive (sensitive);
719                 }
720                 break;
721         default:
722                 if (twod_panner) {
723                         twod_panner->set_sensitive (sensitive);
724                 }
725                 if (big_window) {
726                         big_window->set_sensitive (sensitive);
727                 }
728                 break;
729         }
730 }
731
732 gint
733 PannerUI::pan_automation_state_button_event (GdkEventButton *ev)
734 {
735         using namespace Menu_Helpers;
736
737         if (ev->type == GDK_BUTTON_RELEASE) {
738                 return TRUE;
739         }
740
741         switch (ev->button) {
742         case 1:
743                 if (pan_astate_menu == 0) {
744                         build_astate_menu ();
745                 }
746                 pan_astate_menu->popup (1, ev->time);
747                 break;
748         default:
749                 break;
750         }
751
752         return TRUE;
753 }
754
755 gint
756 PannerUI::pan_automation_style_button_event (GdkEventButton *ev)
757 {
758         if (ev->type == GDK_BUTTON_RELEASE) {
759                 return TRUE;
760         }
761
762         switch (ev->button) {
763         case 1:
764                 if (pan_astyle_menu == 0) {
765                         build_astyle_menu ();
766                 }
767                 pan_astyle_menu->popup (1, ev->time);
768                 break;
769         default:
770                 break;
771         }
772         return TRUE;
773 }
774
775 void
776 PannerUI::pan_automation_style_changed ()
777 {
778         ENSURE_GUI_THREAD (*this, &PannerUI::pan_automation_style_changed)
779
780         switch (_width) {
781         case Wide:
782                 pan_automation_style_button.set_label (astyle_string(_panner->automation_style()));
783                 break;
784         case Narrow:
785                 pan_automation_style_button.set_label (short_astyle_string(_panner->automation_style()));
786                 break;
787         }
788 }
789
790 void
791 PannerUI::pan_automation_state_changed ()
792 {
793         ENSURE_GUI_THREAD (*this, &PannerUI::pan_automation_state_changed)
794
795         bool x;
796
797         switch (_width) {
798         case Wide:
799           pan_automation_state_button.set_label (astate_string(_panner->automation_state()));
800                 break;
801         case Narrow:
802           pan_automation_state_button.set_label (short_astate_string(_panner->automation_state()));
803                 break;
804         }
805
806         /* when creating a new session, we get to create busses (and
807            sometimes tracks) with no outputs by the time they get
808            here.
809         */
810
811         if (_panner->empty()) {
812                 return;
813         }
814
815         x = (_panner->streampanner(0).pan_control()->alist()->automation_state() != Off);
816
817         if (pan_automation_state_button.get_active() != x) {
818         ignore_toggle = true;
819                 pan_automation_state_button.set_active (x);
820                 ignore_toggle = false;
821         }
822
823         update_pan_sensitive ();
824
825         /* start watching automation so that things move */
826
827         pan_watching.disconnect();
828
829         if (x) {
830                 pan_watching = ARDOUR_UI::RapidScreenUpdate.connect (sigc::mem_fun (*this, &PannerUI::effective_pan_display));
831         }
832 }
833
834 string
835 PannerUI::astate_string (AutoState state)
836 {
837         return _astate_string (state, false);
838 }
839
840 string
841 PannerUI::short_astate_string (AutoState state)
842 {
843         return _astate_string (state, true);
844 }
845
846 string
847 PannerUI::_astate_string (AutoState state, bool shrt)
848 {
849         string sstr;
850
851         switch (state) {
852         case Off:
853                 sstr = (shrt ? "M" : _("M"));
854                 break;
855         case Play:
856                 sstr = (shrt ? "P" : _("P"));
857                 break;
858         case Touch:
859                 sstr = (shrt ? "T" : _("T"));
860                 break;
861         case Write:
862                 sstr = (shrt ? "W" : _("W"));
863                 break;
864         }
865
866         return sstr;
867 }
868
869 string
870 PannerUI::astyle_string (AutoStyle style)
871 {
872         return _astyle_string (style, false);
873 }
874
875 string
876 PannerUI::short_astyle_string (AutoStyle style)
877 {
878         return _astyle_string (style, true);
879 }
880
881 string
882 PannerUI::_astyle_string (AutoStyle style, bool shrt)
883 {
884         if (style & Trim) {
885                 return _("Trim");
886         } else {
887                 /* XXX it might different in different languages */
888
889                 return (shrt ? _("Abs") : _("Abs"));
890         }
891 }
892
893 void
894 PannerUI::set_mono (bool yn)
895 {
896         _panner->set_mono (yn);
897         update_pan_sensitive ();
898 }
899
900
901 void
902 PannerUI::connect_to_pan_control (uint32_t i)
903 {
904         _panner->pan_control(i)->Changed.connect (
905                 _pan_control_connections, invalidator (*this), boost::bind (&PannerUI::pan_value_changed, this, i), gui_context ()
906                 );
907 }