Audio/AudioControl: Lots of fixes
[audiocontrol.git] / Views.py
1 """Manage binding views.
2
3 The Views module manages the on-screen keymap representations. A View
4 is registered for a specific context. The view will be called with a
5 list of all active bindings whenever the bindings change."""
6
7 import Events, Node, curses
8
9 class View(Node.Node):
10     def __init__(self, context, label, x, y, dx, dy):
11         Node.Node.__init__(self)
12         self._context = context
13         self._label = label
14         self._win = None
15         self.x, self.y, self.dx, self.dy = x, y, dx, dy
16     
17     def init(self):
18         self._win = self.owner.win().derwin(self.dy, self.dx, self.y, self.x)
19         self.drawFrame()
20
21     def drawFrame(self, subtitle=None):
22         label = ' %s ' % self._label
23         if subtitle:
24             label = '%s- %s ' % (label, subtitle)
25         self._win.border()
26         self._win.addstr(0,2,label)
27         self._win.nooutrefresh()
28         
29     def win(self):
30         return self._win
31
32     def updateView(self, bindings):
33         raise NotImplementedError
34         
35
36 class WidgetView(View):
37
38     _widgets = Node.NodeMap()
39
40     def __init__(self, context, label, x, y, dx, dy):
41         View.__init__(self, context, label, x, y, dx, dy)
42
43     def init(self):
44         View.init(self)
45         for widget in self._widgets.itervalues():
46             widget.init()
47         
48     def add(self,widget):
49         if self.win() : raise RuntimeError, 'Cannot change active view'
50         self._widgets[widget.code] = widget
51
52     def updateView(self, bindings):
53         if bindings:
54             self.drawFrame(bindings.itervalues().next().keymap().keylist().path())
55         for code, widget in self._widgets.iteritems():
56             event = Events.Event(self._context,code)
57             if bindings.has_key(event):
58                 widget.updateView(bindings[event])
59             else:
60                 widget.updateView(None)
61
62
63 class EventWidget(Node.Node):
64
65     def __init__(self, code, label, x, y, size=9):
66         Node.Node.__init__(self)
67         self.x, self.y, self.size = x, y, size
68         self._win = None
69         self.code = code
70         self.label = label
71
72     def init(self):
73         self._win = self.owner.win().derwin(2, self.size, self.y, self.x)
74         self._win.hline(0,0,curses.ACS_HLINE,self.size-1)
75         self._win.addstr(0,(self.size-1-min(self.size-3,len(self.label)))/2, self.label[:self.size-3])
76         self._win.nooutrefresh()
77
78     def updateView(self, binding):
79         if binding:
80             self._win.addstr(1,0, binding.label[:self.size-1].center(self.size-1), curses.A_BOLD)
81         else:
82             self._win.addstr(1, 0, ' '*(self.size-1))
83         self._win.nooutrefresh()
84
85
86 class ViewManager(object):
87
88     _views = Node.NodeMap()
89
90     def __init__(self, keylist, dispatcher, win):
91         self._win = win
92         keylist.registerCallback(self.updateViews)
93         dispatcher.registerCallback(self.beforeIdle)
94
95     def win(self):
96         return self._win
97
98     def registerView(self, view):
99         self._views[view._context] = view
100         view.init()
101
102     def updateViews(self, keylist):
103         bindings = keylist.bindingsByContext()
104         for context, keys in bindings.iteritems():
105             if self._views.has_key(context):
106                 self._views[context].updateView(keys)
107
108     def beforeIdle(self):
109         self._win.refresh()