FunctionCall support for positional and keyword arguments

This commit is contained in:
Darren Ranalli 2008-06-24 18:26:42 +00:00
parent 58408195fb
commit d69414689f

View File

@ -5,6 +5,7 @@ __all__ = ['StateVar', 'FunctionCall', 'EnterExit', 'Pulse', 'EventPulse',
'EventArgument', ]
from direct.showbase.DirectObject import DirectObject
import types
class PushesStateChanges:
# base class for objects that broadcast state changes to a set of subscriber objects
@ -141,20 +142,108 @@ if __debug__:
del scn
del sv
class FunctionCall(StateChangeNode):
# calls func with new state whenever state changes
def __init__(self, source, func):
class ReceivesMultipleStateChanges:
# base class for objects that subscribe to state changes from multiple PushesStateChanges
# objects
def __init__(self):
self._key2source = {}
self._source2key = {}
def destroy(self):
keys = self._key2source.keys()
for key in keys:
self._unsubscribe(key)
del self._key2source
del self._source2key
def _subscribeTo(self, source, key):
self._unsubscribe(key)
self._key2source[key] = source
self._source2key[source] = key
source._addSubscription(self)
def _unsubscribe(self, key):
if key in self._key2source:
source = self._key2source[key]
source._removeSubscription(self)
del self._key2source[key]
del self._source2key[source]
def _recvStatePush(self, source):
self._recvMultiStatePush(self._source2key[source], source)
def _recvMultiStatePush(self, key, source):
pass
if __debug__:
rsc = ReceivesMultipleStateChanges()
sv = StateVar(0)
sv2 = StateVar('b')
rsc._subscribeTo(sv, 'a')
rsc._subscribeTo(sv2, 2)
rsc._unsubscribe('a')
rsc.destroy()
del rsc
class FunctionCall(ReceivesMultipleStateChanges, PushesStateChanges):
# calls func with provided args whenever arguments' state changes
def __init__(self, func, *args, **kArgs):
self._initialized = False
ReceivesMultipleStateChanges.__init__(self)
PushesStateChanges.__init__(self, None)
self._func = func
StateChangeNode.__init__(self, source)
self._args = args
self._kArgs = kArgs
# keep a copy of the arguments ready to go, already filled in with
# the value of arguments that push state
self._bakedArgs = []
self._bakedKargs = {}
for i in xrange(len(self._args)):
key = i
arg = self._args[i]
if isinstance(arg, PushesStateChanges):
self._bakedArgs.append(arg.getState())
self._subscribeTo(arg, key)
else:
self._bakedArgs.append(self._args[i])
for key, arg in self._kArgs.iteritems():
if isinstance(arg, PushesStateChanges):
self._bakedKargs[key] = arg.getState()
self._subscribeTo(arg, key)
else:
self._bakedKargs[key] = arg
self._initialized = True
# push the current state to any listeners
self._handleStateChange()
def destroy(self):
StateChangeNode.destroy(self)
ReceivesMultipleStateChanges.destroy(self)
PushesStateChanges.destroy(self)
del self._func
del self._args
del self._kArgs
del self._bakedArgs
del self._bakedKargs
def getState(self):
# for any state recievers that are hooked up to us, they get a tuple
# of (tuple(positional argument values), dict(keyword argument name->value))
return (tuple(self._bakedArgs), dict(self._bakedKargs))
def _recvMultiStatePush(self, key, source):
# one of the arguments changed
# pick up the new value
if isinstance(key, types.StringType):
self._bakedKargs[key] = source.getState()
else:
self._bakedArgs[key] = source.getState()
# and send it out
self._handlePotentialStateChange(self.getState())
def _handleStateChange(self):
self._func(self._value)
StateChangeNode._handleStateChange(self)
if self._initialized:
self._func(*self._bakedArgs, **self._bakedKargs)
PushesStateChanges._handleStateChange(self)
if __debug__:
l = []
@ -162,7 +251,7 @@ if __debug__:
l.append(value)
assert l == []
sv = StateVar(0)
fc = FunctionCall(sv, handler)
fc = FunctionCall(handler, sv)
assert l == [0,]
sv.set(1)
assert l == [0,1,]
@ -175,6 +264,25 @@ if __debug__:
del handler
del l
l = []
def handler(value, kDummy=None, kValue=None, l=l):
l.append((value, kValue))
assert l == []
sv = StateVar(0)
ksv = StateVar('a')
fc = FunctionCall(handler, sv, kValue=ksv)
assert l == [(0,'a',),]
sv.set(1)
assert l == [(0,'a'),(1,'a'),]
ksv.set('b')
assert l == [(0,'a'),(1,'a'),(1,'b'),]
fc.destroy()
sv.destroy()
del fc
del sv
del handler
del l
class EnterExit(StateChangeNode):
# call enterFunc when our state becomes true, exitFunc when it becomes false
def __init__(self, source, enterFunc, exitFunc):
@ -240,7 +348,7 @@ if __debug__:
def handler(value, l=l):
l.append(value)
p = Pulse()
fc = FunctionCall(p, handler)
fc = FunctionCall(handler, p)
assert l == [False, ]
p.sendPulse()
assert l == [False, True, False, ]
@ -268,7 +376,7 @@ if __debug__:
def handler(value, l=l):
l.append(value)
ep = EventPulse('testEvent')
fc = FunctionCall(ep, handler)
fc = FunctionCall(handler, ep)
assert l == [False, ]
messenger.send('testEvent')
assert l == [False, True, False, ]
@ -301,7 +409,7 @@ if __debug__:
def handler(value, l=l):
l.append(value)
ea = EventArgument('testEvent', index=1)
fc = FunctionCall(ea, handler)
fc = FunctionCall(handler, ea)
messenger.send('testEvent', ['a', 'b'])
assert l == [None, 'b', ]
messenger.send('testEvent', [1, 2, 3, ])