Audio/AudioControl: Lots of fixes
[audiocontrol.git] / Bindings.py
1 """The Bindings module manages an infrastructure for key bindings."""
2
3 # Event = (context, sequence ...) wobei alle elsts strings sind
4
5 # gebuynbden wird ein Action object. Jede Action hat einen namen unter
6 # der sie registriert wird.  die funktionen zum definieren eines
7 # keymnap und zum binden von keys nehmen diesen namen als argument =>
8 # alle Aktionen m"ussen vorher registriert werden
9
10 # KeyStack => KeyMap => Binding => Action
11
12 # Das Binding Objekt enthaelt das Event unter welchem die Action
13 # gebunden ist. Jedes Binding aht auch einen label zum anzeigen des
14 # bindings
15
16 import Node, Actions, Events, Logger
17
18 class Binding(Node.Node):
19
20     action = Node.NodeReference()
21
22     def __init__(self, event, label, action):
23         Node.Node.__init__(self)
24         self.event = event
25         self.label = label
26         self.action = action
27
28     def keymap(self):
29         return self.owner
30
31     def execute(self):
32         Logger.log('binding', 'execute: %s' % self.action.name)
33         self.action(self)
34
35
36 class KeyMap(Node.Node):
37
38     _map = Node.NodeMap()
39
40     def __init__(self, name=None):
41         Node.Node.__init__(self)
42         self._name = name
43
44     def add(self, binding):
45         if self.owner : raise RuntimeError, 'changing an active KeyMap not supported'
46         self._map[binding.event] = binding
47
48     def unbind(self, event):
49         if self.owner : raise RuntimeError, 'changing an active KeyMap not supported'
50         del self._map[event]
51
52     def name(self):
53         return self._name
54
55     def index(self):
56         if self.owner : return self.owner.indexOf(self)
57         else          : return None
58
59     def keylist(self):
60         return self.owner
61
62     def lookup(self, event):
63         return self._map.get(event,None)
64
65     def bindings(self):
66         return self._map
67
68
69 class KeyList(Node.Node):
70
71     _list = Node.NodeList()
72     
73     def __init__(self):
74         Node.Node.__init__(self)
75         self._callbacks = []
76
77     def indexOf(self, map):
78         return self._list.index(map)
79
80     def append(self, map):
81         self._list.append(map)
82         self._callCallbacks()
83
84     def prepend(self, map):
85         self._list[:0] = [map]
86         self._callCallbacks()
87
88     def removeMap(self, map):
89         for i in (range(len(self._list))):
90             if self._list[i] is map:
91                 self._list[i:i+1] = []
92                 return
93
94     def replaceFromIndex(self, index, maps):
95         self._list[index:] = maps
96         self._callCallbacks()
97
98     def lookup(self, event):
99         for i in range(len(self._list)-1,-1,-1):
100             binding = self._list[i].lookup(event)
101             if binding is not None : return binding
102         return None
103
104     def bindings(self):
105         bindings = {}
106         for map in self._list:
107             bindings.update(map.bindings())
108         return bindings
109
110     def bindingsByContext(self):
111         bindings = {}
112         for map in self._list:
113             for binding in map.bindings().itervalues():
114                 bindings.setdefault(binding.event.context,{})
115                 bindings[binding.event.context][binding.event] = binding
116         return bindings
117
118     def registerCallback(self, cb):
119         self._callbacks.append(cb)
120
121     def unregisterCallback(self, cb):
122         self._callbacks.remove(cb)
123
124     def _callCallbacks(self):
125         for cb in self._callbacks : cb(self)
126
127     def path(self):
128         return ' / '.join([ map.name() for map in self._list if map.name() ])