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