Browse Source

added EventGroup

Darren Ranalli 19 years ago
parent
commit
4f77115b94
1 changed files with 104 additions and 0 deletions
  1. 104 0
      direct/src/showbase/EventGroup.py

+ 104 - 0
direct/src/showbase/EventGroup.py

@@ -0,0 +1,104 @@
+from direct.showbase import DirectObject
+from direct.showbase.PythonUtil import SerialNum, Functor
+
+class EventGroup(DirectObject.DirectObject):
+    """This class allows you to group together multiple events and treat
+    them as a single event. The EventGroup will not send out its event until
+    all of its sub-events have occured."""
+
+    _SerialNum = SerialNum()
+
+    def __init__(self, name, subEvents=None, doneEvent=None):
+        """
+        Provide a meaningful name to aid debugging.
+
+        doneEvent is optional. If not provided, a unique done event will be
+        generated and is available as EventGroup.getDoneEvent().
+
+        Examples:
+        
+        # waits for gotRed and gotBlue, then sends out 'gotColors'
+        EventGroup('getRedAndBlue', ('gotRed', 'gotBlue'), doneEvent='gotColors')
+
+        # waits for two interests to close, then calls self._handleBothInterestsClosed()
+        # uses EventGroup.getDoneEvent() and EventGroup.newEvent() to generate unique,
+        # disposable event names
+        eGroup = EventGroup('closeInterests')
+        self.acceptOnce(eGroup.getDoneEvent(), self._handleBothInterestsClosed)
+        base.cr.closeInterest(interest1, event=eGroup.newEvent('closeInterest1'))
+        base.cr.closeInterest(interest2, event=eGroup.newEvent('closeInterest2'))
+        """
+        self._name = name
+        self._subEvents = set()
+        self._completedEvents = set()
+        if doneEvent is None:
+            # no doneEvent provided, allocate a unique event name
+            doneEvent = 'EventGroup-%s-%s-Done' % (
+                EventGroup._SerialNum.next(), self._name)
+        self._doneEvent = doneEvent
+        self._completed = False
+
+        if subEvents is not None:
+            # add the events that were passed in to start with, more may be added
+            # later via newEvent()
+            for event in subEvents:
+                self.addEvent(event)
+
+    def destroy(self):
+        del self._name
+        del self._subEvents
+        del self._completedEvents
+        del self._doneEvent
+        self.ignoreAll()
+
+    def getName(self):
+        return self._name
+
+    def getDoneEvent(self):
+        return self._doneEvent
+
+    def isCompleted(self):
+        return self._completed
+
+    def addEvent(self, eventName):
+        """ Adds a new event to the list of sub-events that we're waiting on.
+        Returns the name of the event. """
+        if self._completed:
+            self.notify.error('addEvent(\'%s\') called on completed EventGroup \'%s\'' % (
+                eventName, self.getName()))
+        if eventName in self._subEvents:
+            self.notify.error('addEvent(\'%s\'): event already in EventGroup \'%s\'' % (
+                eventName, self.getName()))
+        self._subEvents.add(eventName)
+        self.acceptOnce(eventName, Functor(self._subEventComplete, eventName))
+        return eventName
+
+    def newEvent(self, name):
+        """ Pass in an event name and it will be unique-ified for you and added
+        to this EventGroup. TIP: there's no need to repeat information in this event
+        name that is already in the name of the EventGroup object.
+        Returns the new event name. """
+        return self.addEvent('%s-SubEvent-%s-%s' % (
+            self._name, EventGroup._SerialNum.next(), name))
+
+    def _subEventComplete(self, subEventName, *args, **kwArgs):
+        if subEventName in self._completedEvents:
+            self.notify.warning('_subEventComplete: \'%s\' already received' %
+                                subEventName)
+        else:
+            self._completedEvents.add(subEventName)
+            if self._completedEvents == self._subEvents:
+                self._signalComplete()
+
+    def _signalComplete(self):
+        self._completed = True
+        messenger.send(self._doneEvent)
+        self.destroy()
+        
+    def __repr__(self):
+        return '%s(\'%s\', %s, doneEvent=\'%s\') # completed=%s' % (
+            self.__class__.__name__,
+            self._name,
+            tuple(self._subEvents),
+            self._doneEvent,
+            tuple(self._completedEvents))