add gesture control for position+width controls of a 2in/2out panner - not used,...
[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         assert (!pan_bars.empty());
224         return pan_bars[0]->get_controllable();
225 }
226
227 bool
228 PannerUI::panning_link_button_press (GdkEventButton*)
229 {
230         return true;
231 }
232
233 bool
234 PannerUI::panning_link_button_release (GdkEventButton*)
235 {
236         if (!ignore_toggle) {
237                 _panner->set_linked (!_panner->linked());
238         }
239         return true;
240 }
241
242 void
243 PannerUI::panning_link_direction_clicked()
244 {
245         switch (_panner->link_direction()) {
246         case Panner::SameDirection:
247                 _panner->set_link_direction (Panner::OppositeDirection);
248                 break;
249         default:
250                 _panner->set_link_direction (Panner::SameDirection);
251                 break;
252         }
253 }
254
255 void
256 PannerUI::update_pan_linkage ()
257 {
258         ENSURE_GUI_THREAD (*this, &PannerUI::update_pan_linkage)
259
260         bool const x = _panner->linked();
261         bool const bx = panning_link_button.get_active();
262
263         if (x != bx) {
264
265                 ignore_toggle = true;
266                 panning_link_button.set_active (x);
267                 ignore_toggle = false;
268         }
269
270         panning_link_direction_button.set_sensitive (x);
271
272         switch (_panner->link_direction()) {
273         case Panner::SameDirection:
274                 panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm")))));
275                 break;
276         default:
277                 panning_link_direction_button.set_image (*(manage (new Image (get_xpm("revdblarrow.xpm")))));
278                 break;
279         }
280 }
281
282 void
283 PannerUI::on_size_allocate (Allocation& a)
284 {
285         HBox::on_size_allocate (a);
286 }
287
288 void
289 PannerUI::set_width (Width w)
290 {
291         switch (w) {
292         case Wide:
293                 panning_link_button.set_label (_("link"));
294                 break;
295         case Narrow:
296                 panning_link_button.set_label (_("L"));
297                 break;
298         }
299
300         _width = w;
301 }
302
303
304 PannerUI::~PannerUI ()
305 {
306         for (vector<MonoPanner*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) {
307                 delete (*i);
308         }
309
310         delete twod_panner;
311         delete big_window;
312         delete pan_menu;
313         delete pan_astyle_menu;
314         delete pan_astate_menu;
315         delete _stereo_panner;
316 }
317
318
319 void
320 PannerUI::panner_changed (void* src)
321 {
322         ENSURE_GUI_THREAD (*this, &PannerUI::panner_changed)
323
324         setup_pan ();
325
326         if (src == this) {
327                 return;
328         }
329
330         switch (_panner->npanners()) {
331         case 0:
332                 panning_link_direction_button.set_sensitive (false);
333                 panning_link_button.set_sensitive (false);
334                 return;
335         case 1:
336                 panning_link_direction_button.set_sensitive (false);
337                 panning_link_button.set_sensitive (false);
338                 break;
339         default:
340                 panning_link_direction_button.set_sensitive (_panner->linked ());
341                 panning_link_button.set_sensitive (true);
342         }
343
344         uint32_t const nouts = _panner->nouts();
345
346         switch (nouts) {
347         case 0:
348         case 1:
349                 /* relax */
350                 break;
351
352         case 2:
353                 break;
354
355         default:
356                 // panner->move_puck (pan_value (pans[0], pans[1]), 0.5);
357                 break;
358         }
359 }
360
361 void
362 PannerUI::update_pan_state ()
363 {
364         /* currently nothing to do */
365         // ENSURE_GUI_THREAD (*this, &PannerUI::update_panner_state)
366 }
367
368 void
369 PannerUI::setup_pan ()
370 {
371         if (!_panner) {
372                 return;
373         }
374
375         uint32_t const nouts = _panner->nouts();
376         uint32_t const npans = _panner->npanners();
377
378         if (int32_t (nouts) == _current_nouts && int32_t (npans) == _current_npans) {
379                 return;
380         }
381
382         _current_nouts = nouts;
383         _current_npans = npans;
384
385         panning_viewport.remove ();
386
387         delete twod_panner;
388         twod_panner = 0;
389         delete _stereo_panner;
390         _stereo_panner = 0;
391
392         if (nouts == 0 || nouts == 1) {
393
394                 while (!pan_bars.empty()) {
395                         delete pan_bars.back();
396                         pan_bars.pop_back ();
397                 }
398
399                 /* stick something into the panning viewport so that it redraws */
400
401                 EventBox* eb = manage (new EventBox());
402                 panning_viewport.add (*eb);
403
404         } else if (nouts == 2) {
405
406                 vector<Adjustment*>::size_type p;
407
408                 while (!pan_bars.empty()) {
409                         delete pan_bars.back();
410                         pan_bars.pop_back ();
411                 }
412
413                 if (npans == 2) {
414
415                         /* add integrated 2in/2out panner GUI */
416
417                         _stereo_panner = new StereoPanner (_panner->direction_control(), 
418                                                            _panner->width_control());
419                         _stereo_panner->set_size_request (-1, pan_bar_height);
420                         panning_viewport.add (*_stereo_panner);
421
422                         boost::shared_ptr<AutomationControl> ac;
423
424                         ac = _panner->direction_control();
425                         _stereo_panner->StartPositionGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch), 
426                                                               boost::weak_ptr<AutomationControl> (ac)));
427                         _stereo_panner->StopPositionGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch), 
428                                                              boost::weak_ptr<AutomationControl>(ac)));
429
430                         ac = _panner->width_control();
431                         _stereo_panner->StartWidthGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch), 
432                                                               boost::weak_ptr<AutomationControl> (ac)));
433                         _stereo_panner->StopWidthGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch), 
434                                                              boost::weak_ptr<AutomationControl>(ac)));
435
436                 } else {
437                         
438                         /* N-in/2out - just use a set of single-channel panners */
439
440                         while ((p = pan_bars.size()) < npans) {
441                                 
442                                 MonoPanner* mp;
443                                 boost::shared_ptr<AutomationControl> ac = _panner->pan_control (p);
444
445                                 mp = new MonoPanner (_panner->pan_control (p));
446                                 
447                                 mp->StartGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch), 
448                                                                       boost::weak_ptr<AutomationControl> (ac)));
449                                 mp->StopGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch), 
450                                                                      boost::weak_ptr<AutomationControl>(ac)));
451
452                                 mp->signal_button_release_event().connect
453                                         (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_button_event), (uint32_t) p));
454                                 
455                                 mp->set_size_request (-1, pan_bar_height);
456                                 
457                                 pan_bars.push_back (mp);
458                                 pan_bar_packer.pack_start (*mp, false, false);
459                         }
460                         
461                         /* now that we actually have the pan bars,
462                            set their sensitivity based on current
463                            automation state.
464                         */
465                         
466                         update_pan_sensitive ();
467                         panning_viewport.add (pan_bar_packer);
468                 }
469
470
471         } else {
472
473                 if (!twod_panner) {
474                         twod_panner = new Panner2d (_panner, 61);
475                         twod_panner->set_name ("MixerPanZone");
476                         twod_panner->show ();
477
478                         twod_panner->signal_button_press_event().connect
479                                 (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_button_event), (uint32_t) 0), false);
480                 }
481
482                 update_pan_sensitive ();
483                 twod_panner->reset (npans);
484                 if (big_window) {
485                         big_window->reset (npans);
486                 }
487                 twod_panner->set_size_request (-1, 61);
488
489                 /* and finally, add it to the panner frame */
490
491                 panning_viewport.add (*twod_panner);
492         }
493
494         panning_viewport.show_all ();
495 }
496
497 void
498 PannerUI::start_touch (boost::weak_ptr<AutomationControl> wac)
499 {
500         boost::shared_ptr<AutomationControl> ac = wac.lock();
501         if (!ac) {
502                 return;
503         }
504         ac->start_touch (ac->session().transport_frame());
505 }
506
507 void
508 PannerUI::stop_touch (boost::weak_ptr<AutomationControl> wac)
509 {
510         boost::shared_ptr<AutomationControl> ac = wac.lock();
511         if (!ac) {
512                 return;
513         }
514         ac->stop_touch (false, ac->session().transport_frame());
515 }
516
517 bool
518 PannerUI::pan_button_event (GdkEventButton* ev, uint32_t which)
519 {
520         switch (ev->button) {
521         case 1:
522                 if (twod_panner && ev->type == GDK_2BUTTON_PRESS) {
523                         if (!big_window) {
524                                 big_window = new Panner2dWindow (_panner, 400, _panner->npanners());
525                         }
526                         big_window->show ();
527                         return true;
528                 }
529                 break;
530
531         case 3:
532                 if (pan_menu == 0) {
533                         pan_menu = manage (new Menu);
534                         pan_menu->set_name ("ArdourContextMenu");
535                 }
536                 build_pan_menu (which);
537                 pan_menu->popup (1, ev->time);
538                 return true;
539                 break;
540         default:
541                 return false;
542         }
543
544         return false; // what's wrong with gcc?
545 }
546
547 void
548 PannerUI::build_pan_menu (uint32_t which)
549 {
550         using namespace Menu_Helpers;
551         MenuList& items (pan_menu->items());
552
553         items.clear ();
554
555         items.push_back (CheckMenuElem (_("Mute")));
556
557         /* set state first, connect second */
558
559         (dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_panner->streampanner(which).muted());
560         (dynamic_cast<CheckMenuItem*> (&items.back()))->signal_toggled().connect
561                 (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_mute), which));
562
563         items.push_back (CheckMenuElem (_("Bypass"), sigc::mem_fun(*this, &PannerUI::pan_bypass_toggle)));
564         bypass_menu_item = static_cast<CheckMenuItem*> (&items.back());
565
566         /* set state first, connect second */
567
568         bypass_menu_item->set_active (_panner->bypassed());
569         bypass_menu_item->signal_toggled().connect (sigc::mem_fun(*this, &PannerUI::pan_bypass_toggle));
570
571         items.push_back (MenuElem (_("Reset"), sigc::bind (sigc::mem_fun (*this, &PannerUI::pan_reset), which)));
572         items.push_back (SeparatorElem());
573         items.push_back (MenuElem (_("Reset all"), sigc::mem_fun (*this, &PannerUI::pan_reset_all)));
574 }
575
576 void
577 PannerUI::pan_mute (uint32_t which)
578 {
579         StreamPanner& sp = _panner->streampanner(which);
580         sp.set_muted (!sp.muted());
581 }
582
583 void
584 PannerUI::pan_bypass_toggle ()
585 {
586         if (bypass_menu_item && (_panner->bypassed() != bypass_menu_item->get_active())) {
587                 _panner->set_bypassed (!_panner->bypassed());
588         }
589 }
590
591 void
592 PannerUI::pan_reset (uint32_t which)
593 {
594         _panner->reset_streampanner (which);
595 }
596
597 void
598 PannerUI::pan_reset_all ()
599 {
600         _panner->reset_to_default ();
601 }
602
603 void
604 PannerUI::effective_pan_display ()
605 {
606         if (_stereo_panner) {
607                 _stereo_panner->queue_draw ();
608         } else if (twod_panner) {
609                 twod_panner->queue_draw ();
610         } else {
611                 for (vector<MonoPanner*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) {
612                         (*i)->queue_draw ();
613                 }
614         }
615 }
616
617 void
618 PannerUI::update_pan_sensitive ()
619 {
620         bool const sensitive = !(_panner->mono()) && !(_panner->automation_state() & Play);
621
622         switch (_panner->nouts()) {
623         case 0:
624         case 1:
625                 break;
626         case 2:
627                 for (vector<MonoPanner*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) {
628                         (*i)->set_sensitive (sensitive);
629                 }
630                 break;
631         default:
632                 if (twod_panner) {
633                         twod_panner->set_sensitive (sensitive);
634                 }
635                 if (big_window) {
636                         big_window->set_sensitive (sensitive);
637                 }
638                 break;
639         }
640 }
641
642 gint
643 PannerUI::pan_automation_state_button_event (GdkEventButton *ev)
644 {
645         using namespace Menu_Helpers;
646
647         if (ev->type == GDK_BUTTON_RELEASE) {
648                 return TRUE;
649         }
650
651         switch (ev->button) {
652         case 1:
653                 if (pan_astate_menu == 0) {
654                         build_astate_menu ();
655                 }
656                 pan_astate_menu->popup (1, ev->time);
657                 break;
658         default:
659                 break;
660         }
661
662         return TRUE;
663 }
664
665 gint
666 PannerUI::pan_automation_style_button_event (GdkEventButton *ev)
667 {
668         if (ev->type == GDK_BUTTON_RELEASE) {
669                 return TRUE;
670         }
671
672         switch (ev->button) {
673         case 1:
674                 if (pan_astyle_menu == 0) {
675                         build_astyle_menu ();
676                 }
677                 pan_astyle_menu->popup (1, ev->time);
678                 break;
679         default:
680                 break;
681         }
682         return TRUE;
683 }
684
685 void
686 PannerUI::pan_automation_style_changed ()
687 {
688         ENSURE_GUI_THREAD (*this, &PannerUI::pan_automation_style_changed)
689
690         switch (_width) {
691         case Wide:
692                 pan_automation_style_button.set_label (astyle_string(_panner->automation_style()));
693                 break;
694         case Narrow:
695                 pan_automation_style_button.set_label (short_astyle_string(_panner->automation_style()));
696                 break;
697         }
698 }
699
700 void
701 PannerUI::pan_automation_state_changed ()
702 {
703         ENSURE_GUI_THREAD (*this, &PannerUI::pan_automation_state_changed)
704
705         bool x;
706
707         switch (_width) {
708         case Wide:
709           pan_automation_state_button.set_label (astate_string(_panner->automation_state()));
710                 break;
711         case Narrow:
712           pan_automation_state_button.set_label (short_astate_string(_panner->automation_state()));
713                 break;
714         }
715
716         /* when creating a new session, we get to create busses (and
717            sometimes tracks) with no outputs by the time they get
718            here.
719         */
720
721         if (_panner->empty()) {
722                 return;
723         }
724
725         x = (_panner->streampanner(0).pan_control()->alist()->automation_state() != Off);
726
727         if (pan_automation_state_button.get_active() != x) {
728         ignore_toggle = true;
729                 pan_automation_state_button.set_active (x);
730                 ignore_toggle = false;
731         }
732
733         update_pan_sensitive ();
734
735         /* start watching automation so that things move */
736
737         pan_watching.disconnect();
738
739         if (x) {
740                 pan_watching = ARDOUR_UI::RapidScreenUpdate.connect (sigc::mem_fun (*this, &PannerUI::effective_pan_display));
741         }
742 }
743
744 string
745 PannerUI::astate_string (AutoState state)
746 {
747         return _astate_string (state, false);
748 }
749
750 string
751 PannerUI::short_astate_string (AutoState state)
752 {
753         return _astate_string (state, true);
754 }
755
756 string
757 PannerUI::_astate_string (AutoState state, bool shrt)
758 {
759         string sstr;
760
761         switch (state) {
762         case Off:
763                 sstr = (shrt ? "M" : _("M"));
764                 break;
765         case Play:
766                 sstr = (shrt ? "P" : _("P"));
767                 break;
768         case Touch:
769                 sstr = (shrt ? "T" : _("T"));
770                 break;
771         case Write:
772                 sstr = (shrt ? "W" : _("W"));
773                 break;
774         }
775
776         return sstr;
777 }
778
779 string
780 PannerUI::astyle_string (AutoStyle style)
781 {
782         return _astyle_string (style, false);
783 }
784
785 string
786 PannerUI::short_astyle_string (AutoStyle style)
787 {
788         return _astyle_string (style, true);
789 }
790
791 string
792 PannerUI::_astyle_string (AutoStyle style, bool shrt)
793 {
794         if (style & Trim) {
795                 return _("Trim");
796         } else {
797                 /* XXX it might different in different languages */
798
799                 return (shrt ? _("Abs") : _("Abs"));
800         }
801 }
802
803 void
804 PannerUI::set_mono (bool yn)
805 {
806         _panner->set_mono (yn);
807         update_pan_sensitive ();
808 }
809
810 void
811 PannerUI::show_width ()
812 {
813 }
814
815 void
816 PannerUI::width_adjusted ()
817 {
818 }
819
820 void
821 PannerUI::show_position ()
822 {
823 }
824
825 void
826 PannerUI::position_adjusted ()
827 {
828 }