Browse Source

*** empty log message ***

Mark Mine 24 years ago
parent
commit
a3b8ed2062

+ 9 - 9
direct/src/gui/DirectButton.py

@@ -1,20 +1,21 @@
-from DirectLabel import *
+from DirectFrame import *
 
-class DirectButton(DirectLabel):
+class DirectButton(DirectFrame):
     """
     DirectButton(parent) - Create a DirectGuiWidget which responds
     to mouse clicks and execute a callback function if defined
     """
     def __init__(self, parent = guiTop, **kw):
-        # Inherits from DirectLabel
-        # A Direct Label can have:
+        # Inherits from DirectFrame
+        # A Direct Frame can have:
         # - A background texture (pass in path to image, or Texture Card)
         # - A midground geometry item (pass in geometry)
         # - A foreground text Node (pass in text string or Onscreen Text)
         # For a direct button:
-        # Each of these has 4 states (ready, press, rollover, disabled)
-        # The same object can be used for all four states or each
+        # Each button has 4 states (ready, press, rollover, disabled)
+        # The same image/geom/text can be used for all four states or each
         # state can have a different text/geom/image
+        # State transitions happen automatically based upon mouse interaction
         # Responds to click event and calls command if None
         optiondefs = (
             # Define type of DirectGuiWidget
@@ -34,11 +35,10 @@ class DirectButton(DirectLabel):
             ('pressEffect',     1,          INITOPT),
             )
         # Merge keyword options with default options
-        self.defineoptions(kw, optiondefs,
-                           dynamicGroups = ('text', 'geom', 'image'))
+        self.defineoptions(kw, optiondefs)
 
         # Initialize superclasses
-        DirectLabel.__init__(self, parent)
+        DirectFrame.__init__(self, parent)
         
         # If specifed, add scaling to the pressed state to make it look
         # like the button is moving when you press it

+ 156 - 0
direct/src/gui/DirectFrame.py

@@ -0,0 +1,156 @@
+from DirectGuiBase import *
+
+class DirectFrame(DirectGuiWidget):
+    def __init__(self, parent = guiTop, **kw):
+        # Inherits from DirectGuiWidget
+        # A Direct Frame can have:
+        # - A background texture (pass in path to image, or Texture Card)
+        # - A midground geometry item (pass in geometry)
+        # - A foreground text Node (pass in text string or Onscreen Text)
+        # Each of these has 1 or more states
+        # The same object can be used for all states or each
+        # state can have a different text/geom/image (for radio button
+        # and check button indicators, for example
+        optiondefs = (
+            # Define type of DirectGuiWidget
+            ('pgFunc',          PGItem,     None),
+            ('numStates',       1,          None),
+            # Frame can have:
+            # A background texture
+            ('image',           None,       self.setImage),
+            # A midground geometry item
+            ('geom',            None,       self.setGeom),
+            # A foreground text node
+            ('text',            None,       self.setText),
+            )
+        # Merge keyword options with default options
+        self.defineoptions(kw, optiondefs,
+                           dynamicGroups = ('text', 'geom', 'image'))
+
+        # Initialize superclasses
+        DirectGuiWidget.__init__(self, parent)
+        
+        # Call option initialization functions
+        self.initialiseoptions(DirectFrame)
+
+    def setText(self):
+        # Determine if user passed in single string or a sequence
+        if self['text'] == None:
+            textList = (None,) * self['numStates']
+        elif type(self['text']) == types.StringType:
+            # If just passing in a single string, make a tuple out of it
+            textList = (self['text'],) * self['numStates']
+        else:
+            # Otherwise, hope that the user has passed in a tuple/list
+            textList = self['text']
+        # Create/destroy components
+        for i in range(self['numStates']):
+            component = 'text' + `i`
+            # If fewer items specified than numStates,
+            # just repeat last item
+            try:
+                text = textList[i]
+            except IndexError:
+                text = textList[-1]
+                
+            if self.hascomponent(component):
+                if text == None:
+                    # Destroy component
+                    self.destroycomponent(component)
+                else:
+                    self[component + '_text'] = text
+            else:
+                if text == None:
+                    return
+                else:
+                    self.createcomponent(
+                        component, (), 'text',
+                        OnscreenText.OnscreenText,
+                        (), parent = self.stateNodePath[i],
+                        text = text, scale = 1,
+                        sort = TEXT_SORT_INDEX,
+                        mayChange = 1)
+
+    def setGeom(self):
+        # Determine argument type
+        if self['geom'] == None:
+            # Passed in None
+            geomList = (None,) * self['numStates']
+        elif isinstance(self['geom'], NodePath):
+            # Passed in a single node path, make a tuple out of it
+            geomList = (self['geom'],) * self['numStates']
+        else:
+            # Otherwise, hope that the user has passed in a tuple/list
+            geomList = self['geom']
+        # Create/destroy components
+        for i in range(self['numStates']):
+            component = 'geom' + `i`
+            # If fewer items specified than numStates,
+            # just repeat last item
+            try:
+                geom = geomList[i]
+            except IndexError:
+                geom = geomList[-1]
+                
+            if self.hascomponent(component):
+                if geom == None:
+                    # Destroy component
+                    self.destroycomponent(component)
+                else:
+                    self[component + '_geom'] = geom
+            else:
+                if geom == None:
+                    return
+                else:
+                    self.createcomponent(
+                        component, (), 'geom',
+                        OnscreenGeom.OnscreenGeom,
+                        (), parent = self.stateNodePath[i],
+                        geom = geom, scale = 1,
+                        sort = GEOM_SORT_INDEX)
+
+    def setImage(self):
+        # Determine argument type
+        arg = self['image']
+        if arg == None:
+            # Passed in None
+            imageList = (None,) * self['numStates']
+        elif type(arg) == types.StringType:
+            # Passed in a single node path, make a tuple out of it
+            imageList = (arg,) * self['numStates']
+        else:
+            # Otherwise, hope that the user has passed in a tuple/list
+            if ((len(arg) == 2) and
+                (type(arg[0]) == types.StringType) and
+                (type(arg[1]) == types.StringType)):
+                # Its a model/node pair of strings
+                image = (arg,) * self['numStates']
+            else:
+                # Assume its a list of node paths
+                imageList = arg
+        # Create/destroy components
+        for i in range(self['numStates']):
+            component = 'image' + `i`
+            # If fewer items specified than numStates,
+            # just repeat last item
+            try:
+                image = imageList[i]
+            except IndexError:
+                image = imageList[-1]
+                
+            if self.hascomponent(component):
+                if image == None:
+                    # Destroy component
+                    self.destroycomponent(component)
+                else:
+                    self[component + '_image'] = image
+            else:
+                if image == None:
+                    return
+                else:
+                    self.createcomponent(
+                        component, (), 'image',
+                        OnscreenImage.OnscreenImage,
+                        (), parent = self.stateNodePath[i],
+                        image = image, scale = 1,
+                        sort = IMAGE_SORT_INDEX)

+ 1 - 0
direct/src/gui/DirectGui.py

@@ -6,6 +6,7 @@ __builtin__.guiTop = aspect2d.attachNewNode(PGTop('DirectGuiTop'))
 guiTop.node().setMouseWatcher(base.mouseWatcher.node())
 
 # Direct Gui Classes
+from DirectFrame import *
 from DirectButton import *
 from DirectLabel import *
 

+ 125 - 25
direct/src/gui/DirectGuiBase.py

@@ -1,4 +1,6 @@
 from DirectGuiGlobals import *
+from DirectGeometry import ROUND_TO
+
 """
 Base class for all Direct Gui items.  Handles composite widgets and
 command line argument parsing.
@@ -89,7 +91,7 @@ class DirectGuiBase(PandaObject):
         # Default id of all gui object, subclasses should override this
         self.guiId = 'guiObject'
         # List of all active hooks
-        self.hookDict = {}
+        self._hookDict = {}
         # To avoid doing things redundantly during initialisation
         self.fInit = 1
 	# Mapping from each megawidget option to a list of information
@@ -141,6 +143,9 @@ class DirectGuiBase(PandaObject):
         # no components with this group have been created.
         # self._dynamicGroups = ()
 
+    def __del__(self):
+        print 'Bye'
+
     def defineoptions(self, keywords, optionDefs, dynamicGroups = ()):
         """ defineoptions(keywords, optionDefs, dynamicGroups = {}) """
 	# Create options, providing the default value and the method
@@ -592,8 +597,11 @@ class DirectGuiBase(PandaObject):
 
     def destroy(self):
         # Clean out any hooks
-        for event in self.hookDict.keys():
+        for event in self._hookDict.keys():
             self.ignore(event)
+        del(self._optionInfo)
+        del(self._hookDict)
+        del(self.__componentInfo)
 
     def bind(self, event, command):
         """
@@ -605,7 +613,7 @@ class DirectGuiBase(PandaObject):
         gEvent = event + self.guiId
         self.accept(gEvent, command)
         # Keep track of all events you're accepting
-        self.hookDict[gEvent] = command
+        self._hookDict[gEvent] = command
         
     def unbind(self, event):
         """
@@ -614,11 +622,20 @@ class DirectGuiBase(PandaObject):
         # Need to tack on gui item specific id
         gEvent = event + self.guiId
         self.ignore(gEvent)
-        if self.hookDict.has_key(gEvent):
-            del(self.hookDict[gEvent])
+        if self._hookDict.has_key(gEvent):
+            del(self._hookDict[gEvent])
 
+def toggleGuiGridSnap():
+    DirectGuiWidget.snapToGrid = 1 - DirectGuiWidget.snapToGrid
+
+def setGuiGridSpacing(spacing):
+    DirectGuiWidget.gridSpacing = spacing
 
 class DirectGuiWidget(DirectGuiBase, NodePath):
+    # Toggle if you wish widget's to snap to grid when draggin
+    snapToGrid = 0
+    gridSpacing = 0.05
+    
     def __init__(self, parent = guiTop, **kw):
         # Direct gui widgets are node paths
         # Direct gui widgets have:
@@ -633,20 +650,20 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
         # -  Can position/scale them
         optiondefs = (
             # Widget's constructor
-            ('pgFunc',          PGItem,     None),
-            ('numStates',       1,          None),
-            ('invertedFrames',  (),         None),
+            ('pgFunc',         PGItem,       None),
+            ('numStates',      1,            None),
+            ('invertedFrames', (),           None),
             # Widget's initial state
-            ('state',           NORMAL,     self.setState),
+            ('state',          NORMAL,       self.setState),
             # Widget's frame characteristics
-            ('relief',          FLAT,       self.setRelief),
-            ('borderWidth',     (.1,.1),    self.setBorderWidth),
-            ('frameSize',       None,       self.setFrameSize),
-            ('frameColor',      (1,1,1,1),  self.setFrameColor),
-            ('pad',             (.25,.15),  self.resetFrameSize),
+            ('relief',         FLAT,         self.setRelief),
+            ('borderWidth',    (.1,.1),      self.setBorderWidth),
+            ('frameSize',      None,         self.setFrameSize),
+            ('frameColor',     (.8,.8,.8,1), self.setFrameColor),
+            ('pad',            (.25,.15),    self.resetFrameSize),
             # Initial pos/scale of the widget
-            ('pos',             None,       INITOPT),
-            ('scale',           None,       INITOPT),
+            ('pos',            None,         INITOPT),
+            ('scale',          None,         INITOPT),
             )
         # Merge keyword options with default options
         self.defineoptions(kw, optiondefs)
@@ -677,8 +694,7 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
             else:
                 apply(self.setScale, self['scale'])
         # Initialize names
-        self.guiItem.setName(self.guiId)
-        self.setName(self.guiId + 'NodePath')
+        self.setName(self.guiId)
         # Create
         self.stateNodePath = []
         for i in range(self['numStates']):
@@ -690,6 +706,14 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
         # For holding bounds info
         self.ll = Point3(0)
         self.ur = Point3(0)
+
+        # Is drag and drop enabled?
+        if base.config.GetBool('direct-gui-edit', 0):
+            self.enableEdit()
+
+        # Bind destroy hook
+        self.bind(DESTROY, self.destroy)
+            
         # Call option initialization functions
         self.initialiseoptions(DirectGuiWidget)
 
@@ -699,6 +723,63 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
         if not self['frameSize']:
             self.setFrameSize()
 
+    def enableEdit(self):
+        self.bind(B2PRESS, self.editStart)
+        self.bind(B2RELEASE, self.editStop)
+        self.bind(PRINT, self.printConfig)
+        mb = ModifierButtons(base.mouseWatcherNode.getModifierButtons())
+        mb.addButton(KeyboardButton.alt())
+        base.mouseWatcherNode.setModifierButtons(mb)
+
+    def disableEdit(self):
+        self.unbind(B2PRESS)
+        self.unbind(B2RELEASE)
+        self.unbind(PRINT)
+        mb = ModifierButtons(base.mouseWatcherNode.getModifierButtons())
+        mb.removeButton(KeyboardButton.alt())
+        base.mouseWatcherNode.setModifierButtons(mb)
+        
+    def editStart(self, event):
+        taskMgr.removeTasksNamed('guiEditTask')
+        vWidget2render2d = self.getPos(render2d)
+        vMouse2render2d = Point3(event.getMouse()[0], 0, event.getMouse()[1])
+        editVec = Vec3(vWidget2render2d - vMouse2render2d)
+        if base.mouseWatcherNode.getModifierButtons().isDown(
+            KeyboardButton.alt()):
+            t = taskMgr.spawnMethodNamed(self.guiScaleTask, 'guiEditTask')
+            t.refPos = vWidget2render2d
+            t.editVecLen = editVec.length()
+            t.initScale = self.getScale()
+        else:
+            t = taskMgr.spawnMethodNamed(self.guiDragTask, 'guiEditTask')
+            t.editVec = editVec
+
+    def guiScaleTask(self, state):
+        mwn = base.mouseWatcherNode
+        if mwn.hasMouse():
+            vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])
+            newEditVecLen = Vec3(state.refPos - vMouse2render2d).length()
+            self.setScale(state.initScale * (newEditVecLen/state.editVecLen))
+        return Task.cont
+
+    def guiDragTask(self, state):
+        mwn = base.mouseWatcherNode
+        if mwn.hasMouse():
+            vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])
+            newPos = vMouse2render2d + state.editVec
+            self.setPos(render2d, newPos)
+            if DirectGuiWidget.snapToGrid:
+                newPos = self.getPos()
+                newPos.set(
+                    ROUND_TO(newPos[0], DirectGuiWidget.gridSpacing),
+                    ROUND_TO(newPos[1], DirectGuiWidget.gridSpacing),
+                    ROUND_TO(newPos[2], DirectGuiWidget.gridSpacing))
+                self.setPos(newPos)
+        return Task.cont
+
+    def editStop(self, event):
+        taskMgr.removeTasksNamed('guiEditTask')
+
     def setState(self):
         if type(self['state']) == type(0):
             self.guiItem.setActive(self['state'])
@@ -744,24 +825,29 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
 
     def setRelief(self, fSetStyle = 1):
         relief = self['relief']
+        # Convert None, and string arguments
         if relief == None:
-            for i in range(self['numStates']):
-                self.frameStyle[i].setType(PGFrameStyle.TNone)
-        elif (relief == FLAT) or (relief == 'flat'):
-            for i in range(self['numStates']):
-                self.frameStyle[i].setType(FLAT)
-        elif (relief == RAISED) or (relief == 'raised'):
+            relief = PGFrameStyle.TNone
+        elif type(relief) == types.StringType:
+            # Convert string to frame style int
+            relief = FrameStyleDict[relief]
+        # Set style
+        if relief == RAISED:
             for i in range(self['numStates']):
                 if i in self['invertedFrames']:
                     self.frameStyle[1].setType(SUNKEN)
                 else:
                     self.frameStyle[i].setType(RAISED)
-        elif (relief == SUNKEN) or (relief == 'sunken'):
+        elif relief == SUNKEN:
             for i in range(self['numStates']):
                 if i in self['invertedFrames']:
                     self.frameStyle[1].setType(RAISED)
                 else:
                     self.frameStyle[i].setType(SUNKEN)
+        else:
+            for i in range(self['numStates']):
+                self.frameStyle[i].setType(relief)
+        # Apply styles
         self.updateFrameStyle()
 
     def setFrameColor(self):
@@ -777,7 +863,21 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
         self.updateFrameStyle()
             
     def destroy(self):
+        # Destroy children
+        for child in self.getChildrenAsList():
+            messenger.send(DESTROY + child.getName())
+        # Call superclass destruction method (clears out hooks)
         DirectGuiBase.destroy(self)
         # Get rid of node path
         self.removeNode()
 
+    def printConfig(self, indent = 0):
+        space = ' ' * indent
+        print space + self.guiId
+        print space + 'Pos:   ' + `self.getPos()`
+        print space + 'Scale: ' + `self.getScale()`
+        # Print out children info
+        for child in self.getChildrenAsList():
+            messenger.send(PRINT + child.getName(), [indent + 2])
+        
+

+ 18 - 27
direct/src/gui/DirectGuiGlobals.py

@@ -33,36 +33,27 @@ DISABLED = 'disabled'
 FLAT = PGFrameStyle.TFlat
 RAISED = PGFrameStyle.TBevelOut
 SUNKEN = PGFrameStyle.TBevelIn
+GROOVE = PGFrameStyle.TGroove
+RIDGE = PGFrameStyle.TRidge
 
-# Use to extract common prefix of mouse click, press, and release events
-def getGenericMouseEvent(event, mouse):
-    if mouse == 1:
-        mb = MouseButton.one()
-    elif mouse == 2:
-        mb = MouseButton.two()
-    elif mouse == 3:
-        mb = MouseButton.three()
-    if event == 'click':
-        eventFunc = PGButton().getClickEvent
-    elif event == 'press':
-        eventFunc = PGButton().getPressEvent
-    elif event == 'release':
-        eventFunc = PGButton().getReleaseEvent
-    eventString = eventFunc(mb)
-    return eventString[:eventString.rfind('-') + 1]
+FrameStyleDict = {'flat' : FLAT, 'raised' : RAISED, 'sunken': SUNKEN,
+                  'groove' : GROOVE, 'ridge' : RIDGE 
+                  }
 
 # User can bind commands to these gui events
-ENTER = 'enter-'
-EXIT = 'exit-'
-B1CLICK = getGenericMouseEvent('click', 1)
-B2CLICK = getGenericMouseEvent('click', 2)
-B3CLICK = getGenericMouseEvent('click', 3)
-B1PRESS = getGenericMouseEvent('press', 1)
-B2PRESS = getGenericMouseEvent('press', 2)
-B3PRESS = getGenericMouseEvent('press', 3)
-B1RELEASE = getGenericMouseEvent('release', 1)
-B2RELEASE = getGenericMouseEvent('release', 2)
-B3RELEASE = getGenericMouseEvent('release', 3)
+DESTROY = 'destroy-'
+PRINT = 'print-'
+ENTER = PGButton.getEnterPrefix()
+EXIT = PGButton.getExitPrefix()
+B1CLICK = PGButton.getClickPrefix() + MouseButton.one().getName() + '-'
+B2CLICK = PGButton.getClickPrefix() + MouseButton.two().getName() + '-'
+B3CLICK = PGButton.getClickPrefix() + MouseButton.three().getName() + '-'
+B1PRESS = PGButton.getPressPrefix() + MouseButton.one().getName() + '-'  
+B2PRESS = PGButton.getPressPrefix() + MouseButton.two().getName() + '-'  
+B3PRESS = PGButton.getPressPrefix() + MouseButton.three().getName() + '-'
+B1RELEASE = PGButton.getReleasePrefix() + MouseButton.one().getName() + '-'  
+B2RELEASE = PGButton.getReleasePrefix() + MouseButton.two().getName() + '-'  
+B3RELEASE = PGButton.getReleasePrefix() + MouseButton.three().getName() + '-'
 
 # For setting the sorting order of a widget's visible components
 IMAGE_SORT_INDEX = 10

+ 2 - 2
direct/src/gui/DirectGuiTest.py

@@ -42,7 +42,7 @@ def ouch(db):
     db.lerpPos(Point3(newX, 0, newZ), 1.0, task = 'runAway',
                blendType = 'easeOut')
 
-dl = DirectLabel(image = 'phase_4/maps/middayskyB.jpg')
+dl = DirectFrame(image = 'phase_4/maps/middayskyB.jpg')
 dl.setScale(.5)
 
 # Create a button with a background image, smiley as a geometry element,
@@ -69,7 +69,7 @@ for i in range(10):
     db.bind(EXIT, lambda x, db = db: expand(db))
     db.bind(B1PRESS, lambda x, db = db: ouch(db))
     # Pop up placer when button 2 is pressed
-    db.bind(B2PRESS, lambda x, db = db: db.place())
+    db.bind(B3PRESS, lambda x, db = db: db.place())
     
     # To get rid of button and clear out hooks call:
     # db.destroy()

+ 21 - 141
direct/src/gui/DirectLabel.py

@@ -1,156 +1,36 @@
-from DirectGuiBase import *
+from DirectFrame import *
 
-class DirectLabel(DirectGuiWidget):
+class DirectLabel(DirectFrame):
+    """
+    DirectLabel(parent) - Create a DirectGuiWidget which has multiple
+    states.  User explicitly chooses a state to display
+    """
     def __init__(self, parent = guiTop, **kw):
-        # Inherits from DirectGuiWidget
-        # A Direct Label can have:
+        # Inherits from DirectFrame
+        # A Direct Frame can have:
         # - A background texture (pass in path to image, or Texture Card)
         # - A midground geometry item (pass in geometry)
         # - A foreground text Node (pass in text string or Onscreen Text)
-        # Each of these has 1 or more states
-        # The same object can be used for all states or each
-        # state can have a different text/geom/image (for radio button
-        # and check button indicators, for example
+        # For a direct label:
+        # Each label has 1 or more states
+        # The same image/geom/text can be used for all states or each
+        # state can have a different text/geom/image
+        # State transitions happen under user control
         optiondefs = (
             # Define type of DirectGuiWidget
-            ('pgFunc',          PGItem,     None),
-            ('numStates',       1,          None),
-            # Label can have:
-            # A background texture
-            ('image',           None,       self.setImage),
-            # A midground geometry item
-            ('geom',            None,       self.setGeom),
-            # A foreground text node
-            ('text',            None,       self.setText),
+            ('pgFunc',          PGItem,    None),
+            ('numStates',       1,         None),
+            ('activeState',     0,         self.setActiveState),
             )
         # Merge keyword options with default options
-        self.defineoptions(kw, optiondefs,
-                           dynamicGroups = ('text', 'geom', 'image'))
+        self.defineoptions(kw, optiondefs)
 
         # Initialize superclasses
-        DirectGuiWidget.__init__(self, parent)
+        DirectFrame.__init__(self, parent)
         
         # Call option initialization functions
         self.initialiseoptions(DirectLabel)
 
-    def setText(self):
-        # Determine if user passed in single string or a sequence
-        if self['text'] == None:
-            textList = (None,) * self['numStates']
-        elif type(self['text']) == types.StringType:
-            # If just passing in a single string, make a tuple out of it
-            textList = (self['text'],) * self['numStates']
-        else:
-            # Otherwise, hope that the user has passed in a tuple/list
-            textList = self['text']
-        # Create/destroy components
-        for i in range(self['numStates']):
-            component = 'text' + `i`
-            # If fewer items specified than numStates,
-            # just repeat last item
-            try:
-                text = textList[i]
-            except IndexError:
-                text = textList[-1]
-                
-            if self.hascomponent(component):
-                if text == None:
-                    # Destroy component
-                    self.destroycomponent(component)
-                else:
-                    self[component + '_text'] = text
-            else:
-                if text == None:
-                    return
-                else:
-                    self.createcomponent(
-                        component, (), 'text',
-                        OnscreenText.OnscreenText,
-                        (), parent = self.stateNodePath[i],
-                        text = text, scale = 1,
-                        sort = TEXT_SORT_INDEX,
-                        mayChange = 1)
-
-    def setGeom(self):
-        # Determine argument type
-        if self['geom'] == None:
-            # Passed in None
-            geomList = (None,) * self['numStates']
-        elif isinstance(self['geom'], NodePath):
-            # Passed in a single node path, make a tuple out of it
-            geomList = (self['geom'],) * self['numStates']
-        else:
-            # Otherwise, hope that the user has passed in a tuple/list
-            geomList = self['geom']
-        # Create/destroy components
-        for i in range(self['numStates']):
-            component = 'geom' + `i`
-            # If fewer items specified than numStates,
-            # just repeat last item
-            try:
-                geom = geomList[i]
-            except IndexError:
-                geom = geomList[-1]
-                
-            if self.hascomponent(component):
-                if geom == None:
-                    # Destroy component
-                    self.destroycomponent(component)
-                else:
-                    self[component + '_geom'] = geom
-            else:
-                if geom == None:
-                    return
-                else:
-                    self.createcomponent(
-                        component, (), 'geom',
-                        OnscreenGeom.OnscreenGeom,
-                        (), parent = self.stateNodePath[i],
-                        geom = geom, scale = 1,
-                        sort = GEOM_SORT_INDEX)
-
-    def setImage(self):
-        # Determine argument type
-        arg = self['image']
-        if arg == None:
-            # Passed in None
-            imageList = (None,) * self['numStates']
-        elif type(arg) == types.StringType:
-            # Passed in a single node path, make a tuple out of it
-            imageList = (arg,) * self['numStates']
-        else:
-            # Otherwise, hope that the user has passed in a tuple/list
-            if ((len(arg) == 2) and
-                (type(arg[0]) == types.StringType) and
-                (type(arg[1]) == types.StringType)):
-                # Its a model/node pair of strings
-                image = (arg,) * self['numStates']
-            else:
-                # Assume its a list of node paths
-                imageList = arg
-        # Create/destroy components
-        for i in range(self['numStates']):
-            component = 'image' + `i`
-            # If fewer items specified than numStates,
-            # just repeat last item
-            try:
-                image = imageList[i]
-            except IndexError:
-                image = imageList[-1]
-                
-            if self.hascomponent(component):
-                if image == None:
-                    # Destroy component
-                    self.destroycomponent(component)
-                else:
-                    self[component + '_image'] = image
-            else:
-                if image == None:
-                    return
-                else:
-                    self.createcomponent(
-                        component, (), 'image',
-                        OnscreenImage.OnscreenImage,
-                        (), parent = self.stateNodePath[i],
-                        image = image, scale = 1,
-                        sort = IMAGE_SORT_INDEX)
+    def setActiveState(self):
+        """ setActiveState - change label to specifed state """
+        self.guiItem.setState(self['activeState'])

+ 1 - 1
direct/src/gui/OnscreenImage.py

@@ -57,7 +57,7 @@ class OnscreenImage(PandaObject, NodePath):
                 node = model.find(image[1])
                 if node:
                     self.assign(node)
-                    self.reparentTo(parent, sort)
+                    self.copyTo(parent, sort)
                 else:
                     print 'OnscreenImage: node %s not found' % image[1]
                     return