mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 18:31:55 -04:00
FunctionCall support for positional and keyword arguments
This commit is contained in:
parent
58408195fb
commit
d69414689f
@ -5,6 +5,7 @@ __all__ = ['StateVar', 'FunctionCall', 'EnterExit', 'Pulse', 'EventPulse',
|
|||||||
'EventArgument', ]
|
'EventArgument', ]
|
||||||
|
|
||||||
from direct.showbase.DirectObject import DirectObject
|
from direct.showbase.DirectObject import DirectObject
|
||||||
|
import types
|
||||||
|
|
||||||
class PushesStateChanges:
|
class PushesStateChanges:
|
||||||
# base class for objects that broadcast state changes to a set of subscriber objects
|
# base class for objects that broadcast state changes to a set of subscriber objects
|
||||||
@ -141,20 +142,108 @@ if __debug__:
|
|||||||
del scn
|
del scn
|
||||||
del sv
|
del sv
|
||||||
|
|
||||||
class FunctionCall(StateChangeNode):
|
class ReceivesMultipleStateChanges:
|
||||||
# calls func with new state whenever state changes
|
# base class for objects that subscribe to state changes from multiple PushesStateChanges
|
||||||
def __init__(self, source, func):
|
# 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
|
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()
|
self._handleStateChange()
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
StateChangeNode.destroy(self)
|
ReceivesMultipleStateChanges.destroy(self)
|
||||||
|
PushesStateChanges.destroy(self)
|
||||||
del self._func
|
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):
|
def _handleStateChange(self):
|
||||||
self._func(self._value)
|
if self._initialized:
|
||||||
StateChangeNode._handleStateChange(self)
|
self._func(*self._bakedArgs, **self._bakedKargs)
|
||||||
|
PushesStateChanges._handleStateChange(self)
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
l = []
|
l = []
|
||||||
@ -162,7 +251,7 @@ if __debug__:
|
|||||||
l.append(value)
|
l.append(value)
|
||||||
assert l == []
|
assert l == []
|
||||||
sv = StateVar(0)
|
sv = StateVar(0)
|
||||||
fc = FunctionCall(sv, handler)
|
fc = FunctionCall(handler, sv)
|
||||||
assert l == [0,]
|
assert l == [0,]
|
||||||
sv.set(1)
|
sv.set(1)
|
||||||
assert l == [0,1,]
|
assert l == [0,1,]
|
||||||
@ -175,6 +264,25 @@ if __debug__:
|
|||||||
del handler
|
del handler
|
||||||
del l
|
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):
|
class EnterExit(StateChangeNode):
|
||||||
# call enterFunc when our state becomes true, exitFunc when it becomes false
|
# call enterFunc when our state becomes true, exitFunc when it becomes false
|
||||||
def __init__(self, source, enterFunc, exitFunc):
|
def __init__(self, source, enterFunc, exitFunc):
|
||||||
@ -240,7 +348,7 @@ if __debug__:
|
|||||||
def handler(value, l=l):
|
def handler(value, l=l):
|
||||||
l.append(value)
|
l.append(value)
|
||||||
p = Pulse()
|
p = Pulse()
|
||||||
fc = FunctionCall(p, handler)
|
fc = FunctionCall(handler, p)
|
||||||
assert l == [False, ]
|
assert l == [False, ]
|
||||||
p.sendPulse()
|
p.sendPulse()
|
||||||
assert l == [False, True, False, ]
|
assert l == [False, True, False, ]
|
||||||
@ -268,7 +376,7 @@ if __debug__:
|
|||||||
def handler(value, l=l):
|
def handler(value, l=l):
|
||||||
l.append(value)
|
l.append(value)
|
||||||
ep = EventPulse('testEvent')
|
ep = EventPulse('testEvent')
|
||||||
fc = FunctionCall(ep, handler)
|
fc = FunctionCall(handler, ep)
|
||||||
assert l == [False, ]
|
assert l == [False, ]
|
||||||
messenger.send('testEvent')
|
messenger.send('testEvent')
|
||||||
assert l == [False, True, False, ]
|
assert l == [False, True, False, ]
|
||||||
@ -301,7 +409,7 @@ if __debug__:
|
|||||||
def handler(value, l=l):
|
def handler(value, l=l):
|
||||||
l.append(value)
|
l.append(value)
|
||||||
ea = EventArgument('testEvent', index=1)
|
ea = EventArgument('testEvent', index=1)
|
||||||
fc = FunctionCall(ea, handler)
|
fc = FunctionCall(handler, ea)
|
||||||
messenger.send('testEvent', ['a', 'b'])
|
messenger.send('testEvent', ['a', 'b'])
|
||||||
assert l == [None, 'b', ]
|
assert l == [None, 'b', ]
|
||||||
messenger.send('testEvent', [1, 2, 3, ])
|
messenger.send('testEvent', [1, 2, 3, ])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user