*** empty log message ***

This commit is contained in:
Mark Mine 2000-11-10 00:04:51 +00:00
parent f96734023b
commit 81cbc5013f
9 changed files with 1273 additions and 862 deletions

View File

@ -1,5 +1,16 @@
from PandaModules import *
from PandaObject import * from PandaObject import *
X_AXIS = Vec3(1,0,0)
Y_AXIS = Vec3(0,1,0)
Z_AXIS = Vec3(0,0,1)
NEG_X_AXIS = Vec3(-1,0,0)
NEG_Y_AXIS = Vec3(0,-1,0)
NEG_Z_AXIS = Vec3(0,0,-1)
ZERO_VEC = ORIGIN = Vec3(0)
UNIT_VEC = Vec3(1)
ZERO_POINT = Point3(0)
class LineNodePath(NodePath): class LineNodePath(NodePath):
def __init__(self, parent = None, **kw): def __init__(self, parent = None, **kw):
@ -71,3 +82,5 @@ def planeIntersect (lineOrigin, lineDir, planeOrigin, normal):
hitPt = lineDir * t hitPt = lineDir * t
return hitPt + lineOrigin return hitPt + lineOrigin
def roundTo(value, divisor):
return round(value/float(divisor)) * divisor

View File

@ -43,8 +43,10 @@ class DirectGrid(NodePath,PandaObject):
# Initialize Grid characteristics # Initialize Grid characteristics
self.fXyzSnap = 1 self.fXyzSnap = 1
self.fHprSnap = 1
self.gridSize = 100.0 self.gridSize = 100.0
self.gridSpacing = 5.0 self.gridSpacing = 5.0
self.snapAngle = 15.0
self.enable() self.enable()
def enable(self): def enable(self):
@ -97,23 +99,27 @@ class DirectGrid(NodePath,PandaObject):
major.create() major.create()
self.gridBack.setScale(scaledSize) self.gridBack.setScale(scaledSize)
def roundTo(self, value, divisor):
return round(value/float(divisor)) * divisor
def setXyzSnap(self, fSnap): def setXyzSnap(self, fSnap):
self.fXyzSnap = fSnap self.fXyzSnap = fSnap
def getXyzSnap(self): def getXyzSnap(self):
return self.fXyzSnap return self.fXyzSnap
def snapToGrid(self, point): def setHprSnap(self, fSnap):
self.fHprSnap = fSnap
def getHprSnap(self):
return self.fHprSnap
def computeSnapPoint(self, point):
# Start of with current point
self.snapPos.assign(point)
# Snap if necessary
if self.fXyzSnap: if self.fXyzSnap:
self.snapPos.set( self.snapPos.set(
roundTo(point[0], self.gridSpacing), roundTo(self.snapPos[0], self.gridSpacing),
roundTo(point[1], self.gridSpacing), roundTo(self.snapPos[1], self.gridSpacing),
roundTo(point[2], self.gridSpacing)) roundTo(self.snapPos[2], self.gridSpacing))
else:
self.snapPos.assign(point)
# Move snap marker to this point # Move snap marker to this point
self.snapMarker.setPos(self.snapPos) self.snapMarker.setPos(self.snapPos)
@ -121,6 +127,15 @@ class DirectGrid(NodePath,PandaObject):
# Return the hit point # Return the hit point
return self.snapPos return self.snapPos
def computeSnapAngle(self, angle):
return roundTo(angle, self.snapAngle)
def setSnapAngle(self, angle):
self.snapAngle = angle
def getSnapAngle(self):
return self.snapAngle
def setGridSpacing(self, spacing): def setGridSpacing(self, spacing):
self.gridSpacing = spacing self.gridSpacing = spacing
self.updateGrid() self.updateGrid()

View File

@ -18,12 +18,10 @@ class DirectNodePath(NodePath):
# and its center of action (COA) # and its center of action (COA)
self.mCoa2Dnp = Mat4() self.mCoa2Dnp = Mat4()
self.mCoa2Dnp.assign(Mat4.identMat()) self.mCoa2Dnp.assign(Mat4.identMat())
self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1)) # self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1))
# Transform from nodePath to widget # Transform from nodePath to widget
self.mDnp2Widget = Mat4() self.mDnp2Widget = Mat4()
self.mDnp2Widget.assign(Mat4.identMat()) self.mDnp2Widget.assign(Mat4.identMat())
# Use value of this pointer as unique ID
self.id = self.node().this
def highlight(self): def highlight(self):
self.bbox.show() self.bbox.show()
@ -65,7 +63,7 @@ class SelectedNodePaths(PandaObject):
self.deselectAll() self.deselectAll()
# Get this pointer # Get this pointer
id = nodePath.node().this id = nodePath.id()
# First see if its already in the selected dictionary # First see if its already in the selected dictionary
dnp = self.selectedDict.get(id, None) dnp = self.selectedDict.get(id, None)
# If so, we're done # If so, we're done
@ -84,14 +82,14 @@ class SelectedNodePaths(PandaObject):
# Show its bounding box # Show its bounding box
dnp.highlight() dnp.highlight()
# Add it to the selected dictionary # Add it to the selected dictionary
self.selectedDict[dnp.id] = dnp self.selectedDict[dnp.id()] = dnp
# And update last # And update last
self.last = dnp self.last = dnp
return dnp return dnp
def deselect(self, nodePath): def deselect(self, nodePath):
# Get this pointer # Get this pointer
id = nodePath.node().this id = nodePath.id()
# See if it is in the selected dictionary # See if it is in the selected dictionary
dnp = self.selectedDict.get(id, None) dnp = self.selectedDict.get(id, None)
if dnp: if dnp:
@ -108,11 +106,16 @@ class SelectedNodePaths(PandaObject):
list = [] list = []
for key in self.selectedDict.keys(): for key in self.selectedDict.keys():
list.append(self.selectedDict[key]) list.append(self.selectedDict[key])
return list
def __getitem__(self,index):
return self.selectedAsList()[index]
def deselectedAsList(self): def deselectedAsList(self):
list = [] list = []
for key in self.deselectedDict.keys(): for key in self.deselectedDict.keys():
list.append(self.deselectedDict[key]) list.append(self.deselectedDict[key])
return list
def forEachSelectedNodePathDo(self, func): def forEachSelectedNodePathDo(self, func):
duplicateKeys = self.selectedDict.keys()[:] duplicateKeys = self.selectedDict.keys()[:]
@ -171,7 +174,7 @@ class SelectedNodePaths(PandaObject):
def getDirectNodePath(self, nodePath): def getDirectNodePath(self, nodePath):
# Get this pointer # Get this pointer
id = nodePath.node().this id = nodePath.id()
# First check selected dict # First check selected dict
dnp = self.selectedDict.get(id, None) dnp = self.selectedDict.get(id, None)
if dnp: if dnp:

View File

@ -43,6 +43,10 @@ class DirectSession(PandaObject):
self.iRay = self.iRayList[0] self.iRay = self.iRayList[0]
self.hitPt = Point3(0.0) self.hitPt = Point3(0.0)
# One run through the context task to init everything
for context in self.contextList:
context.contextTask(None)
self.actionEvents = [('select', self.select), self.actionEvents = [('select', self.select),
('deselect', self.deselect), ('deselect', self.deselect),
('deselectAll', self.deselectAll), ('deselectAll', self.deselectAll),
@ -89,8 +93,9 @@ class DirectSession(PandaObject):
def followSelectedNodePathTask(self, state): def followSelectedNodePathTask(self, state):
mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render) mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render)
mCoa2Render.decomposeMatrix( decomposeMatrix(mCoa2Render,
self.scale,self.hpr,self.pos,getDefaultCoordinateSystem()) self.scale,self.hpr,self.pos,
getDefaultCoordinateSystem())
self.widget.setPosHpr(self.pos,self.hpr) self.widget.setPosHpr(self.pos,self.hpr)
return Task.cont return Task.cont

View File

@ -4,6 +4,10 @@
of the NodePath class of the NodePath class
""" """
def id(self):
"""Returns the bottom node's this pointer as a unique id"""
return self.node().this
def getNodePathName(self): def getNodePathName(self):
from PandaModules import * from PandaModules import *
# Initialize to a default value # Initialize to a default value
@ -70,7 +74,8 @@
def getAncestry(self): def getAncestry(self):
from PandaObject import * from PandaObject import *
if self.node() != render.node(): node = self.node()
if ((node != render.node()) | (node != hidden.node())):
ancestry = self.getParent().getAncestry() ancestry = self.getParent().getAncestry()
ancestry.append(self) ancestry.append(self)
return ancestry return ancestry

View File

@ -14,10 +14,10 @@ Generates Python code for the C++ libraries listed.
Example: Example:
Linux: Linux:
ppython -d generatePythonCode -v -d $DIRECT/lib/py -e $DIRECT/src/extensions -i libdtool libpandaexpress libpanda libdirect ppython -d generatePythonCode -v -d $DIRECT/lib/py -e $DIRECT/src/extensions -i libdtool libpandaexpress libpanda libdirect libtoontown
Windows: Windows:
ppython -d generatePythonCode -v -d `cygpath -w $DIRECT/lib/py` -e `cygpath -w $DIRECT/src/extensions` -i libdtool libpandaexpress libpanda libdirect ppython -d generatePythonCode -v -d `cygpath -w $DIRECT/lib/py` -e `cygpath -w $DIRECT/src/extensions` -i libdtool libpandaexpress libpanda libdirect libtoontown
Options: Options:

File diff suppressed because it is too large Load Diff

View File

@ -4,28 +4,31 @@ from DirectGeometry import *
class PieMenu(NodePath, PandaObject): class PieMenu(NodePath, PandaObject):
def __init__(self, direct, menu, action = None, fUpdateOnlyOnChange = 1): def __init__(self, direct, menu, action = None, fUpdateOnlyOnChange = 1):
NodePath.__init__(self) NodePath.__init__(self)
# Become the menu # Create a toplevel node for aspect ratio scaling
self.assign(menu) self.assign(hidden.attachNewNode(NamedNode('PieMenu')))
# Attach the menu
self.menu = menu
self.menu.reparentTo(self)
# Initialize instance variables # Initialize instance variables
self.direct = direct self.direct = direct
self.numItems = self.getNumChildren() self.numItems = self.menu.getNumChildren()
self.degreesPerItem = 360.0/self.numItems self.degreesPerItem = 360.0/self.numItems
self.sfx = self.getSx() self.itemOffset = self.degreesPerItem / 2.0
self.sfz = self.getSz() self.sfx = self.menu.getSx()
self.sfz = self.menu.getSz()
# Record target and action # Record target and action
self.action = action self.action = action
self.initialState = None self.initialState = None
# Marking lines # Marking lines
self.lines = LineNodePath(self) self.lines = LineNodePath(self.menu)
self.lines.setColor(VBase4(1)) self.lines.setColor(VBase4(1))
self.lines.setThickness(1) self.lines.setThickness(1)
# Set flags # Set flags
self.fUpdateOnlyOnChange = fUpdateOnlyOnChange self.fUpdateOnlyOnChange = fUpdateOnlyOnChange
self.itemOffset = 0
def performAction(self, value): def performAction(self, value):
if action: if self.action:
action(value) self.action(value)
def removePieMenuTask(self): def removePieMenuTask(self):
taskMgr.removeTasksNamed('pieMenuTask') taskMgr.removeTasksNamed('pieMenuTask')
@ -43,7 +46,9 @@ class PieMenu(NodePath, PandaObject):
# Pop up menu # Pop up menu
self.reparentTo(render2d) self.reparentTo(render2d)
self.setPos(self.originX,0.0,self.originY) self.setPos(self.originX,0.0,self.originY)
# Compensate for window aspect ratio
self.setScale(1.0, 1.0,1.0)
#self.direct.chan.width/float(self.direct.chan.height))
# Start drawing the selection line # Start drawing the selection line
self.lines.reset() self.lines.reset()
self.lines.moveTo(0,0,0) self.lines.moveTo(0,0,0)
@ -62,7 +67,7 @@ class PieMenu(NodePath, PandaObject):
deltaY = mouseY - self.originY deltaY = mouseY - self.originY
# Update the line # Update the line
self.lines.setVertex(1,(deltaX/sfx),0.0,(deltaY / sfz)) self.lines.setVertex(1,(deltaX/self.sfx),0.0,(deltaY/self.sfz))
# How far from starting point has user moved the cursor? # How far from starting point has user moved the cursor?
if ((abs(deltaX) < 0.1) & (abs(deltaY) < 0.1)): if ((abs(deltaX) < 0.1) & (abs(deltaY) < 0.1)):
@ -74,15 +79,16 @@ class PieMenu(NodePath, PandaObject):
else: else:
# Alway let use know mouse is in the center # Alway let use know mouse is in the center
self.performAction(-1) self.performAction(-1)
self.currItem = -1 self.currItem = -1
else:
# Outside of the center
# Interacting with menu # Interacting with menu
# subtract half a slice to effectively center item # subtract half a slice to effectively center item
menuAngle = rad2Deg(math.atan2(deltaY, deltaX)) + self.itemOffset menuAngle = rad2Deg(math.atan2(deltaY, deltaX)) + self.itemOffset
if menuAngle < 0.0: if menuAngle < 0.0:
menuAngle = menuAngle + 360.0 menuAngle = menuAngle + 360.0
menuAngle = menuAngle % 360.0 menuAngle = menuAngle % 360.0
newItem = math.floor(menuAngle / self.degreesPerItem) newItem = int(math.floor(menuAngle / self.degreesPerItem))
if self.fUpdateOnlyOnChange: if self.fUpdateOnlyOnChange:
if (self.currItem != newItem): if (self.currItem != newItem):
@ -109,3 +115,4 @@ class PieMenu(NodePath, PandaObject):
def setUpdateOnlyOnChange(self,flag): def setUpdateOnlyOnChange(self,flag):
self.fUpdateOnlyOnChange = flag self.fUpdateOnlyOnChange = flag

View File

@ -1,87 +1,93 @@
title = 'DIRECT Floater megawidget' """
Floater Class: Velocity style controller for floating point values with
a label, entry (validated), and scale
"""
import string from Tkinter import *
import Tkinter
import Pmw import Pmw
import string
OK = 1
ERROR = 0
class Floater(Pmw.MegaWidget): class Floater(Pmw.MegaWidget):
""" Megawidget containing a label, an entry, and a scale. "Velocity style floating point controller"
Used as a velocity style controller for floating point values
"""
def __init__(self, parent = None, **kw): def __init__(self, parent = None, **kw):
# Define the megawidget options. # Define the megawidget options.
optiondefs = ( optiondefs = (
('command', None, None), ('initialValue', 0.0, Pmw.INITOPT),
('value', 0.0, self._updateValue),
('text', '', self._updateLabelText),
('min', None, None),
('max', None, None),
('resolution', None, None), ('resolution', None, None),
('command', None, None),
('maxVelocity', 100.0, None), ('maxVelocity', 100.0, None),
('errorbackground', 'pink', None), ('min', None, self._updateValidate),
('max', None, self._updateValidate),
('text', 'Floater', self._updateLabelText),
('significantDigits', 2, self._setSigDigits), ('significantDigits', 2, self._setSigDigits),
) )
self.defineoptions(kw, optiondefs) self.defineoptions(kw, optiondefs)
# Initialise base class (after defining options). # Initialise superclass
Pmw.MegaWidget.__init__(self, parent) Pmw.MegaWidget.__init__(self, parent)
# Initialize some variables # Initialize some class variables
self.value = 0.0 self.value = self['initialValue']
self.velocity = 0.0 self.velocity = 0.0
self.entryValue = Tkinter.StringVar()
self.entryFormat = '%.2f' self.entryFormat = '%.2f'
self.normalBackground = None
# Create the components. # Create the components.
interior = self.interior()
interior['relief'] = 'groove'
interior['borderwidth'] = 2
self.infoFrame = self.createcomponent('frame', # Setup up container
(), None, interior = self.interior()
Tkinter.Frame, interior) interior.configure(relief = GROOVE, borderwidth = 2)
self.infoFrame.pack(expand = 1, fill = 'both')
# Create a label and an entry
self.labelFrame = self.createcomponent('frame', (), None,
Frame, interior)
# Create an entry field to display and validate the floater's value
self.entryValue = StringVar()
self.entryValue.set(self['initialValue'])
self.entry = self.createcomponent('entryField',
# Access floaters entry using "entry"
(('entry', 'entryField_entry'),),
None,
Pmw.EntryField, self.labelFrame,
entry_width = 10,
validate = { 'validator' : 'real',
'min' : self['min'],
'max' : self['max'],
'minstrict' : 0,
'maxstrict' : 0},
entry_justify = 'right',
entry_textvar = self.entryValue,
command = self._entryCommand)
self.entry.pack(side='left',padx = 4)
# Create the Floater's label # Create the Floater's label
self.label = self.createcomponent('label', self.label = self.createcomponent('label', (), None,
(), None, Label, self.labelFrame,
Tkinter.Label, self.infoFrame,
text = self['text'], text = self['text'],
anchor = 'center',
width = 12, width = 12,
anchor = 'center',
font = "Arial 12 bold") font = "Arial 12 bold")
self.label.pack(side='left', expand = 1, fill = 'x') self.label.pack(side='left', expand = 1, fill = 'x')
# Create an entry field to display and validate the floater's value # Now pack the frame
self.entry = self.createcomponent('entry', self.labelFrame.pack(expand = 1, fill = 'both')
(), None,
Tkinter.Entry, self.infoFrame,
width = 10,
justify = 'right',
textvar = self.entryValue)
self.entry.pack(side='left',padx = 4)
self.entry.bind('<Return>', self._entryCommand)
# Create the scale component. # Create the scale component.
self.scale = self.createcomponent('scale', self.scale = self.createcomponent('scale', (), None,
(), None, Scale, interior,
Tkinter.Scale, interior,
command = self._scaleToVelocity, command = self._scaleToVelocity,
orient = 'horizontal', orient = 'horizontal',
length = 150, length = 150,
from_ = -1.0, from_ = -1.0,
to = 1.0, to = 1.0,
resolution = 0.01, resolution = 0.001,
showvalue = 0) showvalue = 0)
self.scale.pack(expand = 1, fill = 'x') self.scale.pack(expand = 1, fill = 'x')
# Set scale to the middle of its range
self.scale.set(0.0) self.scale.set(0.0)
# When interacting with mouse:
# Add scale bindings: When interacting with mouse:
self.scale.bind('<Button-1>', self._startFloaterTask) self.scale.bind('<Button-1>', self._startFloaterTask)
self.scale.bind('<ButtonRelease-1>', self._floaterReset) self.scale.bind('<ButtonRelease-1>', self._floaterReset)
# In case you wish to interact using keys # In case you wish to interact using keys
@ -90,17 +96,31 @@ class Floater(Pmw.MegaWidget):
self.scale.bind('<KeyPress-Left>', self._floaterKeyCommand) self.scale.bind('<KeyPress-Left>', self._floaterKeyCommand)
self.scale.bind('<KeyRelease-Left>', self._floaterReset) self.scale.bind('<KeyRelease-Left>', self._floaterReset)
# Check keywords and initialise options. # Check keywords and initialise options based on input values.
self.initialiseoptions(Floater) self.initialiseoptions(Floater)
# Now that the widgets have been created, update significant digits def label(self):
self._setSigDigits() return self.label
self._updateValue() def scale(self):
return self.scale
def entry(self):
return self.entry
def _updateLabelText(self):
self.label['text'] = self['text']
def _updateValidate(self):
self.configure(entryField_validate = {
'validator' : 'real',
'min' : self['min'],
'max' : self['max'],
'minstrict' : 0,
'maxstrict' : 0})
def _scaleToVelocity(self, strVal): def _scaleToVelocity(self, strVal):
# convert scale val to float # convert scale val to float
val = string.atof(strVal) val = string.atof(strVal)
# retain sign of velocity by only calling abs once # Square val, but retain sign of velocity by only calling abs once
self.velocity = self['maxVelocity'] * val * abs(val) self.velocity = self['maxVelocity'] * val * abs(val)
def _startFloaterTask(self,event): def _startFloaterTask(self,event):
@ -109,7 +129,7 @@ class Floater(Pmw.MegaWidget):
def _floaterTask(self): def _floaterTask(self):
if self.velocity != 0.0: if self.velocity != 0.0:
self.setValue( self.value + self.velocity ) self.set( self.value + self.velocity )
if self._fFloaterTask: if self._fFloaterTask:
self.after(50, self._floaterTask) self.after(50, self._floaterTask)
@ -120,90 +140,205 @@ class Floater(Pmw.MegaWidget):
def _floaterKeyCommand(self, event): def _floaterKeyCommand(self, event):
if self.velocity != 0.0: if self.velocity != 0.0:
self.setValue( self.value + self.velocity ) self.set( self.value + self.velocity )
def _entryCommand(self, event = None): def _entryCommand(self, event = None):
try: try:
val = string.atof( self.entryValue.get() ) val = string.atof( self.entryValue.get() )
self.setValue( val ) self.set( val )
except ValueError: except ValueError:
# invalid entry, ring bell set background to warning color pass
self.entry.bell()
if self.normalBackground is None:
self.normalBackground = self.entry.cget('background')
self.entry.configure( background = self['errorbackground'] )
def _updateValue(self): def _setSigDigits(self):
self.setValue(self['value']) sd = self['significantDigits']
self.entryFormat = '%.' + '%d' % sd + 'f'
# And reset value to reflect change
self.entryValue.set( self.entryFormat % self.value )
def setValue(self, newVal): def get(self):
return self.value
def set(self, newVal, fCommand = 1):
# Clamp value
if self['min'] is not None: if self['min'] is not None:
if newVal < self['min']: if newVal < self['min']:
newVal = self['min'] newVal = self['min']
if self['max'] is not None: if self['max'] is not None:
if newVal > self['max']: if newVal > self['max']:
newVal = self['max'] newVal = self['max']
# Round by resolution
if self['resolution'] is not None: if self['resolution'] is not None:
newVal = round(newVal / self['resolution']) * self['resolution'] newVal = round(newVal / self['resolution']) * self['resolution']
# Update floater's value # Update floater's value
self.value = newVal self.value = newVal
# Update entry to reflect formatted value # Update entry to reflect formatted value
self.entryValue.set( self.entryFormat % self.value ) self.entryValue.set( self.entryFormat % self.value )
# Reset background self.entry.checkentry()
if self.normalBackground is not None:
self.entry.configure(background = self.normalBackground)
self.normalBackground = None
# execute command # execute command
command = self['command'] if fCommand & (self['command'] is not None):
if command is not None: self['command']( newVal )
command( newVal )
def _setSigDigits(self):
sd = self['significantDigits']
self.entryFormat = '%.' + '%d' % sd + 'f'
self.scale['resolution'] = 10 ** (-1.0 * sd)
# And reset value to reflect change
self.entryValue.set( self.entryFormat % self.value )
def _updateLabelText(self): class FloaterGroup(Pmw.MegaToplevel):
self.label['text'] = self['text'] def __init__(self, parent = None, **kw):
# Default group size
DEFAULT_DIM = 1
# Default value depends on *actual* group size, test for user input
DEFAULT_VALUE = [0.0] * kw.get('dim', DEFAULT_DIM)
DEFAULT_LABELS = map(lambda x: 'v[%d]' % x,
range(kw.get('dim', DEFAULT_DIM)))
#define the megawidget options
INITOPT = Pmw.INITOPT
optiondefs = (
('dim', DEFAULT_DIM, INITOPT),
('side', TOP, INITOPT),
('title', 'Floater Group', None),
# A tuple of initial values, one for each floater
('initialValue', DEFAULT_VALUE, INITOPT),
# The command to be executed any time one of the floaters is updated
('command', None, None),
# A tuple of labels, one for each floater
('labels', DEFAULT_LABELS, self._updateLabels),
)
self.defineoptions(kw, optiondefs)
# Initialize the toplevel widget
Pmw.MegaToplevel.__init__(self, parent)
# Create the components
interior = self.interior()
# Get a copy of the initial value (making sure its a list)
self._value = list(self['initialValue'])
# The Menu Bar
self.balloon = Pmw.Balloon()
menubar = self.createcomponent('menubar',(), None,
Pmw.MenuBar, (interior,),
balloon = self.balloon)
menubar.pack(fill=X)
# FloaterGroup Menu
menubar.addmenu('Floater Group', 'Floater Group Operations')
menubar.addmenuitem(
'Floater Group', 'command', 'Reset the Floater Group panel',
label = 'Reset',
command = lambda s = self: s.reset())
menubar.addmenuitem(
'Floater Group', 'command', 'Dismiss Floater Group panel',
label = 'Dismiss', command = self.withdraw)
menubar.addmenu('Help', 'Floater Group Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menubar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
self.floaterList = []
for index in range(self['dim']):
# Add a group alias so you can configure the floaters via:
# fg.configure(Floater_XXX = YYY)
f = self.createcomponent(
'floater%d' % index, (), 'Floater', Floater,
(interior,), initialValue = self._value[index],
text = self['labels'][index])
# Do this separately so command doesn't get executed during construction
f['command'] = lambda val, s=self, i=index: s._floaterSetAt(i, val)
f.pack(side = self['side'], expand = 1, fill = X)
self.floaterList.append(f)
# Make sure floaters are initialized
self.set(self['initialValue'])
# Make sure input variables processed
self.initialiseoptions(FloaterGroup)
def _updateLabels(self):
if self['labels']:
for index in range(self['dim']):
self.floaterList[index]['text'] = self['labels'][index]
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
def get(self):
return self._value
def getAt(self,index):
return self._value[index]
# This is the command is used to set the groups value
def set(self, value, fCommand = 1):
for i in range(self['dim']):
self._value[i] = value[i]
# Update floater, but don't execute its command
self.floaterList[i].set(value[i], 0)
if fCommand & (self['command'] is not None):
self['command'](self._value)
def setAt(self, index, value):
# Update floater and execute its command
self.floaterList[index].set(value)
# This is the command used by the floater
def _floaterSetAt(self, index, value):
self._value[index] = value
if self['command']:
self['command'](self._value)
def reset(self):
self.set(self['initialValue'])
Pmw.forwardmethods(Floater, Tkinter.Scale, 'scale')
## SAMPLE CODE ## SAMPLE CODE
if __name__ == '__main__': if __name__ == '__main__':
# Initialise Tkinter and Pmw. # Initialise Tkinter and Pmw.
root = Pmw.initialise() root = Toplevel()
root.title('Pmw Floater demonstration') root.title('Pmw Floater demonstration')
# Dummy command # Dummy command
def printVal(val): def printVal(val):
print `val` print val
# Create and pack a Floater megawidget. # Create and pack a Floater megawidget.
mega1 = Floater(root) mega1 = Floater(root, command = printVal)
mega1.pack(side = 'left', expand = 1, fill = 'x') mega1.pack(side = 'left', expand = 1, fill = 'x')
"""
# These are things you can set/configure # These are things you can set/configure
mega1['command'] = printVal # Starting value for floater
mega1['initialValue'] = 123.456
mega1['text'] = 'Drive delta X' mega1['text'] = 'Drive delta X'
mega1['min'] = 0.0 mega1['min'] = 0.0
#mega1['max'] = 1000.0 mega1['max'] = 1000.0
mega1['resolution'] = 1.0 mega1['resolution'] = 1.0
# UNCOMMENT THESE TO CUSTOMIZE THE FLOATER
# To change the color of the label: # To change the color of the label:
# mega1.label['foreground'] = 'Red' mega1.label['foreground'] = 'Red'
# Max change/update, default is 100 # Max change/update, default is 100
# To have really fine control, for example # To have really fine control, for example
# mega1['maxVelocity'] = 0.1 # mega1['maxVelocity'] = 0.1
# Number of digits to the right of the decimal point, default = 2 # Number of digits to the right of the decimal point, default = 2
# mega1['significantDigits'] = 5 # mega1['significantDigits'] = 5
"""
# Starting value for floater # To create a floater group to set an RGBA value:
# mega1['value'] = 123.4557 group1 = FloaterGroup(root, dim = 4,
title = 'Simple RGBA Panel',
labels = ('R', 'G', 'B', 'A'),
Floater_min = 0.0,
Floater_max = 255.0,
Floater_resolution = 1.0,
command = printVal)
# Let's go. # Uncomment this if you aren't running in IDLE
#root.mainloop() #root.mainloop()