*** empty log message ***
This commit is contained in:
parent
a16f99c74c
commit
28ab5a02f6
|
|
@ -1,5 +1,9 @@
|
|||
from DirectGuiBase import *
|
||||
|
||||
IMAGE_SORT_INDEX = 10
|
||||
GEOM_SORT_INDEX = 20
|
||||
TEXT_SORT_INDEX = 30
|
||||
|
||||
class DirectButton(DirectGuiBase, NodePath):
|
||||
def __init__(self, parent = guiTop, **kw):
|
||||
# Pass in a background texture, and/or a geometry object,
|
||||
|
|
@ -14,39 +18,57 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
# - a VBase4(L,R,B,T)
|
||||
# - a bounding box object
|
||||
optiondefs = (
|
||||
# Button can have:
|
||||
# A background texture
|
||||
('image', None, self.setImage),
|
||||
# A midground geometry item
|
||||
('geom', None, self.setGeom),
|
||||
('text', '', self.setText),
|
||||
# A foreground text node
|
||||
('text', None, self.setText),
|
||||
# Command to be called on button click
|
||||
('command', None, None),
|
||||
('extraArgs', [], None),
|
||||
# Which mouse buttons can be used to click the button
|
||||
('commandButtons', (1,), self.setCommandButtons),
|
||||
# Buttons initial state
|
||||
('state', NORMAL, self.setState),
|
||||
# Button frame characteristics
|
||||
('relief', FLAT, self.setRelief),
|
||||
('frameColor', (1,1,1,1), self.setFrameColor),
|
||||
('borderWidth', (.1,.1), self.setBorderWidth),
|
||||
('frameSize', None, self.setFrameSize),
|
||||
('pressEffect', 1, None),
|
||||
('padSX', 1.2, None),
|
||||
('padSZ', 1.1, None),
|
||||
('pos', None, None),
|
||||
('scale', None, None),
|
||||
('state', NORMAL, self.setState),
|
||||
('pad', (.25,.15), self.resetFrameSize),
|
||||
# Sounds to be used for button events
|
||||
('rolloverSound', None, None),
|
||||
('clickSound', None, None),
|
||||
# Can only be specified at time of widget contruction
|
||||
# Do the text/graphics appear to move when the button is clicked
|
||||
('pressEffect', 1, INITOPT),
|
||||
# Initial pos/scale of the button
|
||||
('pos', None, INITOPT),
|
||||
('scale', None, INITOPT),
|
||||
)
|
||||
# Update options to reflect keyword parameters
|
||||
apply(DirectGuiBase.__init__, (self, optiondefs, ('text',)), kw)
|
||||
# Initialize the superclass
|
||||
# Merge keyword options with default options
|
||||
self.defineoptions(kw, optiondefs,
|
||||
dynamicGroups = ('text', 'geom', 'image'))
|
||||
|
||||
# Initialize superclasses
|
||||
DirectGuiBase.__init__(self)
|
||||
NodePath.__init__(self)
|
||||
# Create a button
|
||||
self.guiItem = PGButton()
|
||||
self.guiId = self.guiItem.getId()
|
||||
# Attach button to parent and make that self
|
||||
self.assign(parent.attachNewNode( self.guiItem ) )
|
||||
# Set up names
|
||||
# Initialize names
|
||||
self.guiItem.setName(self.guiId)
|
||||
self.setName(self.guiId + 'NodePath')
|
||||
# Get a handle on the button's hidden node paths for each state
|
||||
self.stateNodePath = []
|
||||
for i in range(4):
|
||||
self.stateNodePath.append(NodePath(self.guiItem.getStateDef(i)))
|
||||
# If specifed, add scaling to the pressed state to make it look
|
||||
# like the button is moving when you press it
|
||||
if self['pressEffect']:
|
||||
np = self.stateNodePath[1].attachNewNode('pressEffect')
|
||||
np.setScale(0.98)
|
||||
|
|
@ -58,33 +80,38 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
# For holding bounds info
|
||||
self.ll = Point3(0)
|
||||
self.ur = Point3(0)
|
||||
# Call initialization functions if necessary
|
||||
# To avoid doing things redundantly
|
||||
# Call option initialization functions
|
||||
# To avoid doing things redundantly set fInit flag
|
||||
self.fInit = 1
|
||||
self.initialiseoptions(DirectButton)
|
||||
self.fInit = 0
|
||||
# Allow changes to take effect
|
||||
# Now allow changes to take effect
|
||||
self.updateFrameStyle()
|
||||
if not self['frameSize']:
|
||||
self.setFrameSize()
|
||||
# Update pose
|
||||
# Update pose to initial values
|
||||
if self['pos']:
|
||||
if type(self['pos']) == type(()):
|
||||
apply(self.setPos, self['pos'])
|
||||
pos = self['pos']
|
||||
# Can either be a Point3 or a tuple of 3 values
|
||||
if isintance(pos, Point3):
|
||||
self.setPos(pos)
|
||||
else:
|
||||
apply(self.setPos, (self['pos'],))
|
||||
apply(self.setPos, pos)
|
||||
if self['scale']:
|
||||
if type(self['scale']) == type(()):
|
||||
apply(self.setScale, self['scale'])
|
||||
scale = self['scale']
|
||||
# Can either be a Vec3 or a tuple of 3 values
|
||||
if (isinstance(scale, Vec3) or
|
||||
(type(scale) == types.IntType) or
|
||||
(type(scale) == types.FloatType)):
|
||||
self.setScale(scale)
|
||||
else:
|
||||
apply(self.setScale, (self['scale'],))
|
||||
apply(self.setScale, self['scale'])
|
||||
|
||||
def updateFrameStyle(self):
|
||||
for i in range(4):
|
||||
self.guiItem.setFrameStyle(i, self.frameStyle[i])
|
||||
|
||||
def setRelief(self, fSetStyle = 1):
|
||||
print 'setting Frame'
|
||||
relief = self['relief']
|
||||
if relief == None:
|
||||
for i in range(4):
|
||||
|
|
@ -104,7 +131,8 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
self.updateFrameStyle()
|
||||
|
||||
def resetFrameSize(self):
|
||||
self.setFrameSize(fClearFrame = 1)
|
||||
if not self.fInit:
|
||||
self.setFrameSize(fClearFrame = 1)
|
||||
|
||||
def setFrameSize(self, fClearFrame = 0):
|
||||
if self['frameSize']:
|
||||
|
|
@ -121,8 +149,10 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
# Clear out frame before computing bounds
|
||||
self.stateNodePath[0].calcTightBounds(self.ll, self.ur)
|
||||
# Scale bounds to give a pad around graphics
|
||||
bounds = (self.ll[0] * self['padSX'], self.ur[0] * self['padSX'],
|
||||
self.ll[2] * self['padSZ'], self.ur[2] * self['padSZ'])
|
||||
bounds = (self.ll[0] - self['pad'][0],
|
||||
self.ur[0] + self['pad'][0],
|
||||
self.ll[2] - self['pad'][1],
|
||||
self.ur[2] + self['pad'][1])
|
||||
# Restore frame style if necessary
|
||||
if (frameType != PGFrameStyle.TNone):
|
||||
self.frameStyle[0].setType(frameType)
|
||||
|
|
@ -160,6 +190,7 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
OnscreenText.OnscreenText,
|
||||
(), parent = self.stateNodePath[i],
|
||||
text = text[i], scale = 1,
|
||||
sort = TEXT_SORT_INDEX,
|
||||
mayChange = 1)
|
||||
else:
|
||||
self[component + '_text'] = text[i]
|
||||
|
|
@ -179,6 +210,7 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
component, (), 'geom',
|
||||
OnscreenGeom.OnscreenGeom,
|
||||
(), parent = self.stateNodePath[i],
|
||||
sort = GEOM_SORT_INDEX,
|
||||
geom = geom[i], scale = 1)
|
||||
else:
|
||||
self[component + '_geom'] = geom[i]
|
||||
|
|
@ -206,6 +238,7 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
component, (), 'image',
|
||||
OnscreenImage.OnscreenImage,
|
||||
(), parent = self.stateNodePath[i],
|
||||
sort = IMAGE_SORT_INDEX,
|
||||
image = image[i], scale = 1)
|
||||
else:
|
||||
self[component + '_image'] = image[i]
|
||||
|
|
@ -239,5 +272,10 @@ class DirectButton(DirectGuiBase, NodePath):
|
|||
|
||||
def commandFunc(self, event):
|
||||
if self['command']:
|
||||
self['command'](event)
|
||||
# Pass any extra args to command
|
||||
apply(self['command'], self['extraArgs'])
|
||||
|
||||
def destroy(self):
|
||||
DirectGuiBase.destroy(self)
|
||||
# Get rid of node path
|
||||
self.removeNode()
|
||||
|
|
|
|||
|
|
@ -1,14 +1,95 @@
|
|||
from DirectGuiGlobals import *
|
||||
"""
|
||||
Base class for all Direct Gui items. Handles composite widgets and
|
||||
command line argument parsing.
|
||||
"""
|
||||
|
||||
# Symbolic constants for the indexes into an optionInfo list.
|
||||
_OPT_DEFAULT = 0
|
||||
_OPT_VALUE = 1
|
||||
_OPT_FUNCTION = 2
|
||||
|
||||
"""
|
||||
Code Overview:
|
||||
|
||||
1 Each widget defines a set of options (optiondefs) as a list of tuples
|
||||
of the form ('name', defaultValue, handler).
|
||||
'name' is the name of the option (used during construction of configure)
|
||||
handler can be: None, method, or INITOPT. If a method is specified,
|
||||
it will be called during widget construction (via initialiseoptions),
|
||||
if the Handler is specified as an INITOPT, this is an option that can
|
||||
only be set during widget construction.
|
||||
|
||||
2) DirectGuiBase.defineoptions is called. defineoption creates:
|
||||
|
||||
self._constructorKeywords = { keyword : [value, useFlag] }
|
||||
a dictionary of the keyword options specified as part of the constructor
|
||||
keywords can be of the form 'component_option', where component is
|
||||
the name of a widget's component, a component group or a component alias
|
||||
|
||||
self._dynamicGroups, a list of group names for which it is permissible
|
||||
to specify options before components of that group are created.
|
||||
If a widget is a derived class the order of execution would be:
|
||||
foo.optiondefs = {}
|
||||
foo.defineoptions()
|
||||
fooParent()
|
||||
fooParent.optiondefs = {}
|
||||
fooParent.definoptions()
|
||||
|
||||
3) addoptions is called. This combines options specified as keywords to
|
||||
the widget constructor (stored in self._constuctorKeywords)
|
||||
with the default options (stored in optiondefs). Results are stored in
|
||||
self._optionInfo = { keyword: [default, current, handler] }
|
||||
If a keyword is of the form 'component_option' it is left in the
|
||||
self._constructorKeywords dictionary (for use by component constructors),
|
||||
otherwise it is 'used', and deleted from self._constructorKeywords.
|
||||
Notes: - constructor keywords override the defaults.
|
||||
- derived class default values override parent class defaults
|
||||
- derived class handler functions override parent class functions
|
||||
|
||||
4) Superclass initialization methods are called (resulting in nested calls
|
||||
to define options (see 2 above)
|
||||
|
||||
5) Widget components are created via calls to self.createcomponent.
|
||||
User can specify aliases and groups for each component created.
|
||||
|
||||
Aliases are alternate names for components, e.g. a widget may have a
|
||||
component with a name 'entryField', which itself may have a component
|
||||
named 'entry', you could add an alias 'entry' for the 'entryField_entry'
|
||||
These are stored in self.__componentAliases. If an alias is found,
|
||||
all keyword entries which use that alias are expanded to their full
|
||||
form (to avoid conversion later)
|
||||
|
||||
Groups allow option specifications that apply to all members of the group.
|
||||
If a widget has components: 'text1', 'text2', and 'text3' which all belong
|
||||
to the 'text' group, they can be all configured with keywords of the form:
|
||||
'text_keyword' (e.g. text_font = 'comic.rgb'). A component's group
|
||||
is stored as the fourth element of its entry in self.__componentInfo
|
||||
|
||||
Note: the widget constructors have access to all remaining keywords in
|
||||
_constructorKeywords (those not transferred to _optionInfo by
|
||||
define/addoptions). If a component defines an alias that applies to
|
||||
one of the keywords, that keyword is replaced with a new keyword with
|
||||
the alias expanded.
|
||||
|
||||
If a keyword (or substituted alias keyword) is used during creation of the
|
||||
component, it is deleted from self._constructorKeywords. If a group
|
||||
keyword applies to the component, that keyword is marked as used, but is
|
||||
not deleted from self._constructorKeywords, in case it applies to another
|
||||
component. If any constructor keywords remain at the end of component
|
||||
construction (and initialisation), an error is raised.
|
||||
|
||||
5) initialiseoptions is called. This method calls any option handlers to
|
||||
respond to any keyword/default values, then checks to see if any keywords
|
||||
are left unused. If so, an error is raised.
|
||||
"""
|
||||
|
||||
class DirectGuiBase(PandaObject):
|
||||
def __init__(self, optiondefs, dynamicGroups, **kw):
|
||||
def __init__(self):
|
||||
# Default id of all gui object, subclasses should override this
|
||||
self.guiId = 'guiObject'
|
||||
# List of all active hooks
|
||||
self.hookDict = {}
|
||||
# Mapping from each megawidget option to a list of information
|
||||
# about the option
|
||||
# - default value
|
||||
|
|
@ -58,14 +139,19 @@ class DirectGuiBase(PandaObject):
|
|||
# no components with this group have been created.
|
||||
# self._dynamicGroups = ()
|
||||
|
||||
self.defineoptions(kw, optiondefs, dynamicGroups)
|
||||
|
||||
def defineoptions(self, keywords, optionDefs, dynamicGroups = ()):
|
||||
""" defineoptions(keywords, optionDefs, dynamicGroups = {}) """
|
||||
# Create options, providing the default value and the method
|
||||
# to call when the value is changed. If any option created by
|
||||
# base classes has the same name as one in <optionDefs>, the
|
||||
# base class's value and function will be overriden.
|
||||
|
||||
# keywords is a dictionary of keyword/value pairs from the constructor
|
||||
# optionDefs is a dictionary of default options for the widget
|
||||
# dynamicGroups is a tuple of component groups for which you can
|
||||
# specify options even though no components of this group have
|
||||
# been created
|
||||
|
||||
# This should be called before the constructor of the base
|
||||
# class, so that default values defined in the derived class
|
||||
# override those in the base class.
|
||||
|
|
@ -83,6 +169,7 @@ class DirectGuiBase(PandaObject):
|
|||
self.addoptions(optionDefs)
|
||||
|
||||
def addoptions(self, optionDefs):
|
||||
""" addoptions(optionDefs) - add option def to option info """
|
||||
# Add additional options, providing the default value and the
|
||||
# method to call when the value is changed. See
|
||||
# "defineoptions" for more details
|
||||
|
|
@ -105,12 +192,13 @@ class DirectGuiBase(PandaObject):
|
|||
# Overridden by keyword, use keyword value
|
||||
value = keywords[name][0]
|
||||
optionInfo[name] = [default, value, function]
|
||||
# Delete it from self._constructorKeywords
|
||||
del keywords[name]
|
||||
else:
|
||||
# Use optionDefs value
|
||||
optionInfo[name] = [default, default, function]
|
||||
elif optionInfo[name][FUNCTION] is None:
|
||||
# Override function
|
||||
# Only override function if not defined by derived class
|
||||
optionInfo[name][FUNCTION] = function
|
||||
else:
|
||||
# This option is of the form "component_option". If this is
|
||||
|
|
@ -121,11 +209,24 @@ class DirectGuiBase(PandaObject):
|
|||
keywords[name] = [default, 0]
|
||||
|
||||
def initialiseoptions(self, myClass):
|
||||
"""
|
||||
initialiseoptions(myClass) - call all initialisation functions
|
||||
to initialize widget options to default of keyword value
|
||||
"""
|
||||
# This is to make sure this method class is only called by
|
||||
# the most specific class in the class hierarchy
|
||||
if self.__class__ is myClass:
|
||||
# Call the configuration callback function for every option.
|
||||
FUNCTION = _OPT_FUNCTION
|
||||
for info in self._optionInfo.values():
|
||||
func = info[FUNCTION]
|
||||
if func is not None and func is not INITOPT:
|
||||
func()
|
||||
|
||||
# Now check if anything is left over
|
||||
unusedOptions = []
|
||||
keywords = self._constructorKeywords
|
||||
for name in keywords.keys():
|
||||
print name
|
||||
used = keywords[name][1]
|
||||
if not used:
|
||||
# This keyword argument has not been used. If it
|
||||
|
|
@ -142,18 +243,20 @@ class DirectGuiBase(PandaObject):
|
|||
text = 'Unknown options "'
|
||||
raise KeyError, text + string.join(unusedOptions, ', ') + \
|
||||
'" for ' + myClass.__name__
|
||||
|
||||
# Call the configuration callback function for every option.
|
||||
FUNCTION = _OPT_FUNCTION
|
||||
for info in self._optionInfo.values():
|
||||
func = info[FUNCTION]
|
||||
if func is not None and func is not INITOPT:
|
||||
func()
|
||||
|
||||
def isinitoption(self, option):
|
||||
"""
|
||||
isinitoption(option)
|
||||
Is this opition one that can only be specified at construction?
|
||||
"""
|
||||
return self._optionInfo[option][_OPT_FUNCTION] is INITOPT
|
||||
|
||||
def options(self):
|
||||
"""
|
||||
options()
|
||||
Print out a list of available widget options.
|
||||
Does not include subcomponent options.
|
||||
"""
|
||||
options = []
|
||||
if hasattr(self, '_optionInfo'):
|
||||
for option, info in self._optionInfo.items():
|
||||
|
|
@ -164,7 +267,10 @@ class DirectGuiBase(PandaObject):
|
|||
return options
|
||||
|
||||
def configure(self, option=None, **kw):
|
||||
# Query or configure the megawidget options.
|
||||
"""
|
||||
configure(option = None)
|
||||
Query or configure the megawidget options.
|
||||
"""
|
||||
#
|
||||
# If not empty, *kw* is a dictionary giving new
|
||||
# values for some of the options of this gui item
|
||||
|
|
@ -232,29 +338,39 @@ class DirectGuiBase(PandaObject):
|
|||
index = string.find(option, '_')
|
||||
if index >= 0:
|
||||
# This option may be of the form <component>_<option>.
|
||||
# e.g. if alias ('efEntry', 'entryField_entry')
|
||||
# and option = efEntry_width
|
||||
# component = efEntry, componentOption = width
|
||||
component = option[:index]
|
||||
componentOption = option[(index + 1):]
|
||||
|
||||
# Expand component alias
|
||||
if componentAliases_has_key(component):
|
||||
# component = entryField, subcomponent = entry
|
||||
component, subComponent = componentAliases[component]
|
||||
if subComponent is not None:
|
||||
# componentOption becomes entry_width
|
||||
componentOption = subComponent + '_' \
|
||||
+ componentOption
|
||||
|
||||
# Expand option string to write on error
|
||||
# option = entryField_entry_width
|
||||
option = component + '_' + componentOption
|
||||
|
||||
# Does this component exist
|
||||
if componentInfo_has_key(component):
|
||||
# Get the configure func for the named component
|
||||
# component = entryField
|
||||
componentConfigFuncs = [componentInfo[component][1]]
|
||||
else:
|
||||
# Check if this is a group name and configure all
|
||||
# components in the group.
|
||||
componentConfigFuncs = []
|
||||
# For each component
|
||||
for info in componentInfo.values():
|
||||
# Check if it is a member of this group
|
||||
if info[4] == component:
|
||||
# Yes, append its config func
|
||||
componentConfigFuncs.append(info[1])
|
||||
|
||||
if len(componentConfigFuncs) == 0 and \
|
||||
|
|
@ -268,6 +384,8 @@ class DirectGuiBase(PandaObject):
|
|||
for componentConfigFunc in componentConfigFuncs:
|
||||
if not indirectOptions_has_key(componentConfigFunc):
|
||||
indirectOptions[componentConfigFunc] = {}
|
||||
# Create a dictionary of keyword/values keyed
|
||||
# on configuration function
|
||||
indirectOptions[componentConfigFunc][componentOption] \
|
||||
= value
|
||||
else:
|
||||
|
|
@ -275,6 +393,7 @@ class DirectGuiBase(PandaObject):
|
|||
'" for ' + self.__class__.__name__
|
||||
|
||||
# Call the configure methods for any components.
|
||||
# Pass in the dictionary of keyword/values created above
|
||||
map(apply, indirectOptions.keys(),
|
||||
((),) * len(indirectOptions), indirectOptions.values())
|
||||
|
||||
|
|
@ -290,8 +409,10 @@ class DirectGuiBase(PandaObject):
|
|||
apply(self.configure, (), {key: value})
|
||||
|
||||
def cget(self, option):
|
||||
# Get current configuration setting.
|
||||
|
||||
"""
|
||||
cget(option)
|
||||
Get current configuration setting for this option
|
||||
"""
|
||||
# Return the value of an option, for example myWidget['font'].
|
||||
if self._optionInfo.has_key(option):
|
||||
return self._optionInfo[option][_OPT_VALUE]
|
||||
|
|
@ -332,11 +453,14 @@ class DirectGuiBase(PandaObject):
|
|||
|
||||
def createcomponent(self, componentName, componentAliases, componentGroup,
|
||||
widgetClass, *widgetArgs, **kw):
|
||||
"""Create a component (during construction or later)."""
|
||||
"""
|
||||
Create a component (during construction or later) for this widget.
|
||||
"""
|
||||
# Check for invalid component name
|
||||
if '_' in componentName:
|
||||
raise ValueError, \
|
||||
'Component name "%s" must not contain "_"' % componentName
|
||||
|
||||
# Get construction keywords
|
||||
if hasattr(self, '_constructorKeywords'):
|
||||
keywords = self._constructorKeywords
|
||||
|
|
@ -347,8 +471,10 @@ class DirectGuiBase(PandaObject):
|
|||
# Create aliases to the component and its sub-components.
|
||||
index = string.find(component, '_')
|
||||
if index < 0:
|
||||
# Just a shorter name for one of this widget's components
|
||||
self.__componentAliases[alias] = (component, None)
|
||||
else:
|
||||
# An alias for a component of one of this widget's components
|
||||
mainComponent = component[:index]
|
||||
subComponent = component[(index + 1):]
|
||||
self.__componentAliases[alias] = (mainComponent, subComponent)
|
||||
|
|
@ -356,7 +482,6 @@ class DirectGuiBase(PandaObject):
|
|||
# Remove aliases from the constructor keyword arguments by
|
||||
# replacing any keyword arguments that begin with *alias*
|
||||
# with corresponding keys beginning with *component*.
|
||||
|
||||
alias = alias + '_'
|
||||
aliasLen = len(alias)
|
||||
for option in keywords.keys():
|
||||
|
|
@ -420,19 +545,24 @@ class DirectGuiBase(PandaObject):
|
|||
remainingComponents = name[(index + 1):]
|
||||
|
||||
# Expand component alias
|
||||
# Example entry which is an alias for entryField_entry
|
||||
if self.__componentAliases.has_key(component):
|
||||
# component = entryField, subComponent = entry
|
||||
component, subComponent = self.__componentAliases[component]
|
||||
if subComponent is not None:
|
||||
if remainingComponents is None:
|
||||
# remainingComponents = entry
|
||||
remainingComponents = subComponent
|
||||
else:
|
||||
remainingComponents = subComponent + '_' \
|
||||
+ remainingComponents
|
||||
|
||||
# Get the component from __componentInfo dictionary
|
||||
widget = self.__componentInfo[component][0]
|
||||
if remainingComponents is None:
|
||||
# Not looking for subcomponent
|
||||
return widget
|
||||
else:
|
||||
# Recursive call on subcomponent
|
||||
return widget.component(remainingComponents)
|
||||
|
||||
def components(self):
|
||||
|
|
@ -452,15 +582,33 @@ class DirectGuiBase(PandaObject):
|
|||
del self.__componentInfo[name]
|
||||
|
||||
def destroy(self):
|
||||
# Clean up optionInfo in case it contains circular references
|
||||
# in the function field, such as self._settitle in class
|
||||
# MegaToplevel.
|
||||
# Clean out any hooks
|
||||
for event in self.hookDict.keys():
|
||||
self.ignore(event)
|
||||
|
||||
self._optionInfo = {}
|
||||
|
||||
def bind(self, sequence, command):
|
||||
self.accept(sequence + '-' + self.guiId, command)
|
||||
def bind(self, event, command):
|
||||
"""
|
||||
Bind the command (which should expect one arg) to the specified
|
||||
event (such as ENTER, EXIT, B1PRESS, B1CLICK, etc.)
|
||||
See DirectGuiGlobals for possible events
|
||||
"""
|
||||
# Need to tack on gui item specific id
|
||||
gEvent = event + self.guiId
|
||||
self.accept(gEvent, command)
|
||||
# Keep track of all events you're accepting
|
||||
self.hookDict[gEvent] = command
|
||||
|
||||
def unbind(self, sequence):
|
||||
self.ignore(sequence + '-' + self.guiId)
|
||||
def unbind(self, event):
|
||||
"""
|
||||
Unbind the specified event
|
||||
"""
|
||||
# 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])
|
||||
|
||||
|
||||
class DirectGuiWidget(DirectGuiBase):
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,27 @@
|
|||
"""
|
||||
Global definitions used by Direct Gui Classes and handy constants
|
||||
that can be used during widget construction
|
||||
"""
|
||||
|
||||
from PandaObject import *
|
||||
from PGTop import *
|
||||
from PGButton import *
|
||||
# Import these after PGButton to get actual class definitions
|
||||
from PGItem import *
|
||||
from PGFrameStyle import *
|
||||
# Helper classes used as components of Direct Gui Widgets
|
||||
import OnscreenText
|
||||
import OnscreenGeom
|
||||
import OnscreenImage
|
||||
import types
|
||||
|
||||
# USEFUL GUI CONSTANTS
|
||||
|
||||
# Widget state
|
||||
NORMAL = 'normal'
|
||||
DISABLED = 'disabled'
|
||||
|
||||
# Frame style
|
||||
FLAT = PGFrameStyle.TFlat
|
||||
RAISED = PGFrameStyle.TBevelOut
|
||||
SUNKEN = PGFrameStyle.TBevelIn
|
||||
|
|
@ -31,10 +41,11 @@ def getGenericMouseEvent(event, mouse):
|
|||
elif event == 'release':
|
||||
eventFunc = PGButton().getReleaseEvent
|
||||
eventString = eventFunc(mb)
|
||||
return eventString[:eventString.rfind('-')]
|
||||
return eventString[:eventString.rfind('-') + 1]
|
||||
|
||||
ENTER = 'enter'
|
||||
EXIT = 'exit'
|
||||
# User can bind commands to these gui events
|
||||
ENTER = 'enter-'
|
||||
EXIT = 'exit-'
|
||||
B1CLICK = getGenericMouseEvent('click', 1)
|
||||
B2CLICK = getGenericMouseEvent('click', 2)
|
||||
B3CLICK = getGenericMouseEvent('click', 3)
|
||||
|
|
|
|||
|
|
@ -11,18 +11,20 @@ smiley = loader.loadModel('models/directmodels/smiley')
|
|||
db = DirectButton(image = 'phase_4/maps/middayskyB.jpg',
|
||||
geom = smiley,
|
||||
text = ('Hi!', 'Ouch!', 'Bye!', 'ZZZZ!'),
|
||||
scale = .15, relief = 'raised')
|
||||
scale = .15, relief = 'raised',
|
||||
# Here we set an option for a component of the button
|
||||
geom1_color = Vec4(1,0,0,1),
|
||||
# Here is an example of a component group option
|
||||
text_pos = (.6, -.8))
|
||||
|
||||
# Adjust text position and scale
|
||||
db['text_pos'] = (.6, -.8)
|
||||
db['text_scale'] = .5
|
||||
# Set the color of the pressed button's geometry
|
||||
db['geom1_color'] = Vec4(1,0,0,1)
|
||||
# You can set component or component group options after a gui item
|
||||
# has been created
|
||||
db['text_scale'] = 0.5
|
||||
|
||||
# Specify the button's command
|
||||
# Note, command must expect one argument
|
||||
def dummyCmd(event):
|
||||
# Here we specify the button's command
|
||||
def dummyCmd():
|
||||
print 'POW!!!!'
|
||||
|
||||
db['command'] = dummyCmd
|
||||
|
||||
# Get a handle on the geometry for the rollover state
|
||||
|
|
@ -63,6 +65,8 @@ def ouch(event):
|
|||
db.bind(ENTER, shrink)
|
||||
db.bind(EXIT, expand)
|
||||
db.bind(B1PRESS, ouch)
|
||||
|
||||
# Pop up placer when button 2 is pressed
|
||||
db.bind(B2PRESS, lambda x, s = db: s.place())
|
||||
|
||||
# To get rid of button and clear out hooks call:
|
||||
# db.destroy()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ class OnscreenGeom(PandaObject, NodePath):
|
|||
hpr = None,
|
||||
scale = None,
|
||||
color = None,
|
||||
parent = aspect2d):
|
||||
parent = aspect2d,
|
||||
sort = 0):
|
||||
"""__init__(self, ...)
|
||||
|
||||
Make a geom node from string or a node path,
|
||||
|
|
@ -40,11 +41,12 @@ class OnscreenGeom(PandaObject, NodePath):
|
|||
# We ARE a node path. Initially, we're an empty node path.
|
||||
NodePath.__init__(self)
|
||||
# Assign geometry
|
||||
self.sort = sort
|
||||
if isinstance(geom, NodePath):
|
||||
self.assign(geom.copyTo(parent))
|
||||
self.assign(geom.copyTo(parent, self.sort))
|
||||
elif type(geom) == type(''):
|
||||
self.assign(loader.loadModelCopy(geom))
|
||||
self.reparentTo(parent)
|
||||
self.reparentTo(parent, self.sort)
|
||||
|
||||
# Adjust pose
|
||||
# Set pos
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ class OnscreenImage(PandaObject, NodePath):
|
|||
hpr = None,
|
||||
scale = None,
|
||||
color = None,
|
||||
parent = aspect2d):
|
||||
parent = aspect2d,
|
||||
sort = 0):
|
||||
"""__init__(self, ...)
|
||||
|
||||
Make a image node from string or a node path,
|
||||
|
|
@ -41,13 +42,13 @@ class OnscreenImage(PandaObject, NodePath):
|
|||
NodePath.__init__(self)
|
||||
# Assign geometry
|
||||
if isinstance(image, NodePath):
|
||||
self.assign(image.copyTo(parent))
|
||||
self.assign(image.copyTo(parent, sort))
|
||||
elif type(image) == type(''):
|
||||
# Assume its a file name and create a texture card
|
||||
tex = loader.loadTexture(image)
|
||||
cm = CardMaker()
|
||||
cm.setFrame(-1, 1, -1, 1)
|
||||
self.assign(parent.attachNewNode(cm.generate()))
|
||||
self.assign(parent.attachNewNode(cm.generate(), sort))
|
||||
self.setTexture(tex)
|
||||
elif type(image) == type(()):
|
||||
# Assume its a file+node name, extract texture from node
|
||||
|
|
@ -56,7 +57,7 @@ class OnscreenImage(PandaObject, NodePath):
|
|||
node = model.find(image[1])
|
||||
if node:
|
||||
self.assign(node)
|
||||
self.reparentTo(parent)
|
||||
self.reparentTo(parent, sort)
|
||||
else:
|
||||
print 'OnscreenImage: node %s not found' % image[1]
|
||||
return
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class OnscreenText(PandaObject, NodePath):
|
|||
drawOrder = GuiGlobals.getDefaultDrawOrder(),
|
||||
font = GuiGlobals.getDefaultFont(),
|
||||
parent = aspect2d,
|
||||
sort = 0,
|
||||
mayChange = 0):
|
||||
"""__init__(self, ...)
|
||||
|
||||
|
|
@ -204,7 +205,7 @@ class OnscreenText(PandaObject, NodePath):
|
|||
self.isClean = 0
|
||||
|
||||
# Set ourselves up as the NodePath that points to this node.
|
||||
self.assign(parent.attachNewNode(self.textNode))
|
||||
self.assign(parent.attachNewNode(self.textNode, sort))
|
||||
|
||||
def cleanup(self):
|
||||
"""cleanup(self)
|
||||
|
|
|
|||
Loading…
Reference in New Issue