1 import Views, Events, Logger, Bindings, Actions
2 from Views import EventWidget
3 import time, os, struct, curses
5 class View(Views.WidgetView):
7 def __init__(self, context, label, numeric_switches, alpha_switches, x, y, dx=0, size=11):
9 dx = max(dx,size*numeric_switches+3)
10 delta = dx - size*numeric_switches - 3
12 delta = dx - size*numeric_switches - 2*shift
13 Views.WidgetView.__init__(self, context, label, x, y, dx, 7)
15 split = numeric_switches // 2
16 for i in range(split):
17 self.add( EventWidget(i,str(i+1)[-1:],size*i+1+shift,4,size) )
18 for i in range(split,numeric_switches):
19 self.add( EventWidget(i,str(i+1)[-1:],size*i+shift+delta,4,size) )
20 split = max(0,alpha_switches-(numeric_switches-split))
21 offset = size//2+(numeric_switches-alpha_switches-1)*size
22 for i in range(split):
23 self.add( EventWidget(i+numeric_switches, chr(ord('A')+i), size*i+1+offset+shift,1,size) )
24 for i in range(split, alpha_switches):
25 self.add( EventWidget(i+numeric_switches, chr(ord('A')+i), size*i+delta+offset+shift,1,size) )
31 STRUCT_len = struct.calcsize(STRUCT)
37 def __init__(self, data):
38 self.time, self.value, self.type, self.number = struct.unpack(self.STRUCT,data)
41 return "%s(time=%d, value=%d,type=%d (%s)), number=%d)" % (
42 str(self.__class__),self.time, self.value, self.type, self.decode_type(), self.number)
44 def decode_type(self):
45 return ('','INIT|')[(self.type & self.TYPE_INIT) and 1 or 0] \
46 + ('','BUTTON','AXIS')[self.type & ~self.TYPE_INIT]
48 def readFrom(klass,f):
49 return klass(os.read(f.fileno(),klass.STRUCT_len))
50 readFrom=classmethod(readFrom)
52 def readMultipleFrom(klass,f,maxevents=256):
53 data = os.read(f.fileno(),maxevents*klass.STRUCT_len)
56 rv.append(klass(data[:klass.STRUCT_len]))
57 data = data[klass.STRUCT_len:]
59 readMultipleFrom=classmethod(readMultipleFrom)
62 class Source(Events.EventSource):
64 def __init__(self, joydev, context, bits=None, mindelay=100):
65 Events.EventSource.__init__(self, file(joydev), context)
68 self._mindelay = mindelay
69 self._controllers = {}
76 jsevents = JSEvent.readMultipleFrom(self.fd())
77 for event in jsevents:
78 if event.type == JSEvent.TYPE_AXIS:
79 return self._controller(event.number, event.value)
80 if event.type == JSEvent.TYPE_BUTTON and event.value == 1:
81 self._lastevent = event.time
82 if event.time - lev < self._mindelay : return []
83 n = n | self._bits[event.number]
87 event = JSEvent.readFrom(self.fd())
88 if event.type == JSEvent.TYPE_AXIS:
89 return self._controller(event.number, event.value)
90 if event.type == JSEvent.TYPE_BUTTON and event.value == 1:
91 self._lastevent = event.time
92 if event.time - lev < self._mindelay : return []
96 return [Events.Event(self.context(), n)]
98 def registerController(self, controller, low, high):
99 self._controllers[controller] = { 'low': low, 'high': high }
101 def _controller(self, number, value):
102 controller = self._controllers.get(number)
104 value = (value - controller['low']) * 1000 / (controller['high']-controller['low'])
105 value = max(min(value,1000),0)
106 return [Events.ControlEvent(self.context(), 'p%d' % number, value)]
109 # New Controller state machine:
111 # First, we work in two steps: The controller gets an internal
112 # controller value which is an integer between 0 and 100. All
113 # operations change this value which is then converted to the output
116 # The controller position is managed as a signed integer between -2
119 # The current state is managed in a state variable. There are the
122 # INIT In this state, the controller is waiting for the initial
125 # RUNNING The value is currently being changed. The speed and
126 # direction are given by the controller position. If the
127 # current controller position changes to 0 or to the
128 # opposite sign, the state is switched to WAIT.
130 # WAIT The state machine waits for the controller to enter the
131 # center position. Only when the controller has been in the
132 # center position for some time, it will enter the IDLE
133 # state. It may however go to RUNNING, if the controller
134 # position is again changed to have the same sign t had
135 # before entering WAIT. On entering this state, the
136 # controller position is checked. If the position is 0 now
137 # or if it is changed to become 0, a timeout is started. If
138 # the controller is not changed within this timeout, we
139 # enter IDLE. Any change of the controlle value terminates
142 # SWAIT Wait at a stop. The controller will stay in this state
143 # until the controller position is changed to 0 or the opposite
144 # sign. It then enters the WAIT state.
146 # IDLE In this state, nothing happens, however, if the controller
147 # position changes from 0, the state machine enters the
152 # ev_controllerChanged The controller position changes
154 # ev_timeout The timeout handle got called
156 # The stop positions are handled by converting them to appropriate
157 # integer values. When such a value is reached or crossed, the value
158 # is set to the stop value and the state machine enters the SWAIT
161 # When converting the integer value to the return float value, we
162 # first check, wether the integer value is one of the stop values. In
163 # this case, the associated float value is returned otherweise ahe
164 # integer is scaled to the correct float range.
166 class Controller(Views.View):
168 ########################################
171 def __init__(self, context, name, x, y, dx, dy, keylist, dispatcher,
172 controller, source, low, high):
173 Views.View.__init__(self, context, name, x, y, dx, dy)
175 # External value interface
176 self._valueEvent = None
177 self._setCommand = None
178 self._valueCommand = None
180 # Parameter information
181 self._parameter = None
185 self._rawStops = None
188 # Controller keymap stuff
189 self._keylist = keylist
190 self._keymap = Bindings.KeyMap()
192 self._keymap.add( Bindings.Binding(Events.Event(source.context(), 'p%d' % controller), '',
193 Actions.Command('controllerChanged',
194 self._controllerChanged)) )
195 self._keylist.prepend(self._keymap)
197 source.registerController(controller, low, high)
200 self._dispatcher = dispatcher
202 self._rawValue = None
203 self._controlValue = None
204 self._controlSign = None
207 def assign(self, parameter, setCommand, valueCommand, valueEvent, min, max, stops=[]):
208 self._keylist.removeMap(self._keymap)
209 if self._valueEvent is not None:
210 self._keymap.unbind(self._valueEvent)
211 self._parameter = parameter
212 self._valueEvent = valueEvent
213 self._setCommand = setCommand
214 self._valueCommand = valueCommand
218 self._rawStops = [ self._rawFromCooked(x) for x in self._stops ]
220 self._keymap.add( Bindings.Binding( self._valueEvent, '',
221 Actions.Command('updateValue',
222 self._updateValue)) )
223 self._keylist.prepend(self._keymap)
226 self._controlValue = None
227 self._controlSign = None
228 self._state = self.S_INIT
232 def stepValue(self, direction):
233 Logger.log('ctl','direction = %d' % direction)
234 self._rawValue += max(-1,min(1,direction))
235 if self._rawValue > self._steps:
236 self._rawValue = self._steps
237 elif self._rawValue < 0:
240 Logger.log('ctl','rawValue = %d' % self._rawValue)
241 self._setValue(self._cookedFromRaw(self._rawValue))
243 return self._rawValue in self._rawStops
245 ########################################
246 # Base class interface implementation
248 def updateView(self, bindings):
252 Views.View.init(self)
255 ########################################
256 # External event callbacks
258 def _updateValue(self, binding):
259 # Called to return the value after executing the valueCommand
260 # (when valueCommand initiates an async value get like via
262 event = self._dispatcher.currentEvent()
263 self.__updateValue(event.value)
266 def __updateValue(self, value):
268 if self._state == self.S_INIT:
269 self._rawValue = self._rawFromCooked(self._value)
270 self._setState(self.S_SWAIT)
275 def _controllerChanged(self, binding):
276 # Called, whenever the controller position changes
277 event = self._dispatcher.currentEvent()
278 if event.value >= 999:
280 elif event.value >= 700:
282 elif event.value >= 200:
284 elif event.value >= 1:
288 Logger.log('ctl',"controlValue = %d" % newControlValue)
289 if self._controlValue is None or self._controlValue != newControlValue:
290 self._controlValue = newControlValue
291 self._ev_controllerChanged()
293 ########################################
296 def _setValue(self, value):
297 self._setCommand(value)
304 self.__updateValue(self._valueCommand())
306 def _rawFromCooked(self, value):
307 return min(self._steps,max(0,int(float(self._steps)*(value-self._min)/(self._max-self._min)+.5)))
309 def _cookedFromRaw(self, value):
311 return self._stops[ self._rawStops.index(value) ]
313 return (self._min*(self._steps-value) + self._max*value)/self._steps
315 ########################################
324 def _setState(self, state):
328 def _ev_controllerChanged(self):
329 self._redrawController()
331 if self._state in (self.S_IDLE, self.S_RUNNING):
332 if abs(self._controlValue)==1:
333 self._dispatcher.setIdleCallback(self._ev_timeout,200)
334 self._setState(self.S_RUNNING)
335 elif self._controlValue != 0:
336 self._dispatcher.setIdleCallback(self._ev_timeout,75)
337 self._setState(self.S_RUNNING)
339 self._dispatcher.unsetIdleCallback()
340 if self._state == self.S_RUNNING:
341 self._setState(self.S_WAIT)
342 self._ev_controllerChanged()
344 self._setState(self.S_IDLE)
346 elif self._state == self.S_SWAIT:
347 if self._controlValue == 0 or self._controlSign and self._controlSign*self._controlValue < 0:
348 self._setState(self.S_WAIT)
349 self._ev_controllerChanged()
351 elif self._state == self.S_WAIT:
352 if self._controlValue == 0:
353 self._dispatcher.setIdleCallback(self._ev_timeout,300)
355 self._dispatcher.unsetIdleCallback()
356 if self._controlSign and self._controlSign*self._controlValue > 0:
357 self._setState(self.S_RUNNING)
358 self._ev_controllerChanged()
362 def _ev_timeout(self):
363 if self._state == self.S_RUNNING:
364 self._controlSign = max(-1, min(1, self._controlValue))
365 if self._controlSign == 0:
366 # Cannot happen but ...
367 self._setState(self.S_IDLE)
369 if self.stepValue(self._controlSign):
370 self._setState(self.S_SWAIT)
372 elif self._state == self.S_WAIT:
373 self._setState(self.S_IDLE)
374 self._dispatcher.unsetIdleCallback()
378 ########################################
394 height, width = self.win().getmaxyx()
395 if self._parameter is not None:
396 self.win().addstr(1,2,self._parameter[:width-4].ljust(width-4), curses.A_BOLD)
397 self.win().addch(3,3,curses.ACS_TTEE)
398 self.win().addch(height-3,3,curses.ACS_BTEE)
399 self.win().addch(height/2,1,'-')
401 self._redrawController()
404 def _redrawState(self):
405 self._redrawController()
407 def _updateWindow(self):
410 def _flt(self, value, width):
411 return ('%.3f' % value)[:width].ljust(width)
413 def _redrawValue(self):
414 height, width = self.win().getmaxyx()
416 if self._value is not None:
417 pos = height - 3 - int( (self._value - self._min) * (height-6)
418 / (self._max - self._min) + .5 )
419 if self._max is not None:
420 self.win().addstr(2,2, self._flt(self._max,width-7))
421 if pos is not None and pos == 3:
422 self.win().addstr(pos, 5, self._flt(self._value,width-7), curses.A_BOLD)
424 self.win().addstr(3, 5, "".ljust(width-7))
425 for row in range(4,height-3):
426 if pos is not None and row == pos:
427 self.win().addch(pos,3,curses.ACS_PLUS)
428 self.win().addstr(pos, 5, self._flt(self._value,width-7), curses.A_BOLD)
430 self.win().addch(row,3,curses.ACS_VLINE)
431 self.win().addstr(row, 5, "".ljust(width-7))
432 if pos is not None and pos == height-3:
433 self.win().addstr(pos, 5, self._flt(self._value,width-7), curses.A_BOLD)
435 self.win().addstr(height-3, 5, "".ljust(width-7))
436 if self._min is not None:
437 self.win().addstr(height-2,2,self._flt(self._min,width-7))
439 def _redrawController(self, refresh=True):
440 if self._controlValue is None: return
441 height, width = self.win().getmaxyx()
442 pos = height - 3 - int( (self._controlValue + 2) * (height-6) / 4 + .5 )
443 for row in range(3,height-2):
445 self.win().addch(row,2,('N','R','W','S','I')[self._state])
447 self.win().addch(row,2,' ')
449 class StepController(Actions.Action):
451 def __init__(self, name, controller, direction):
452 Actions.Action.__init__(self, name)
453 self._controller = controller
454 self._direction = direction
456 def __call__(self, binding):
457 self._controller.stepValue(self._direction)
460 def register( viewmanager,
473 viewmanager.registerView( View(context, label, numeric_switches, alpha_switches, x, y, dx, size) )
475 if device is not None:
476 source = Source(device, context, bits)
477 dispatcher.registerSource( source )
480 def registerController( viewmanager, dispatcher, keylist, source, context, name, x, y, dx, dy,
481 controller, low, high ):
482 controller = Controller(context, name, x, y, dx, dy, keylist, dispatcher,
483 controller, source, low, high)
484 viewmanager.registerView( controller )