*** empty log message ***
This commit is contained in:
parent
ae803609f6
commit
a3b8ed2062
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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 *
|
||||
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue