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