mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
*** empty log message ***
This commit is contained in:
parent
0f4d293597
commit
235cd02cb7
@ -4435,7 +4435,7 @@ class LevelEditorPanel(Pmw.MegaToplevel):
|
||||
self.fUpdateSelected = 1
|
||||
# Handle to the toplevels hull
|
||||
hull = self.component('hull')
|
||||
hull.geometry('400x550')
|
||||
hull.geometry('400x515')
|
||||
|
||||
balloon = self.balloon = Pmw.Balloon(hull)
|
||||
# Start with balloon help disabled
|
||||
@ -4737,63 +4737,73 @@ class LevelEditorPanel(Pmw.MegaToplevel):
|
||||
self.addKernFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Kern',
|
||||
maxVelocity=1.0,
|
||||
#maxVelocity=1.0,
|
||||
command=self.setSignBaselineKern)
|
||||
self.addKernFloater.grid(row=4, column=0, rowspan=2, columnspan=3)
|
||||
self.addKernFloater.grid(row=4, column=0, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addWiggleFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Wiggle',
|
||||
maxVelocity=10.0,
|
||||
#maxVelocity=10.0,
|
||||
command=self.setSignBaselineWiggle)
|
||||
self.addWiggleFloater.grid(row=6, column=0, rowspan=2, columnspan=3)
|
||||
self.addWiggleFloater.grid(row=6, column=0, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addStumbleFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Stumble',
|
||||
maxVelocity=1.0,
|
||||
#maxVelocity=1.0,
|
||||
command=self.setSignBaselineStumble)
|
||||
self.addStumbleFloater.grid(row=8, column=0, rowspan=2, columnspan=3)
|
||||
self.addStumbleFloater.grid(row=8, column=0, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addStompFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Stomp',
|
||||
maxVelocity=1.0,
|
||||
#maxVelocity=1.0,
|
||||
command=self.setSignBaselineStomp)
|
||||
self.addStompFloater.grid(row=10, column=0, rowspan=2, columnspan=3)
|
||||
self.addStompFloater.grid(row=10, column=0, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addCurveFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Curve',
|
||||
maxVelocity = 1.0,
|
||||
#maxVelocity = 1.0,
|
||||
command=self.setSignBaselineCurve)
|
||||
self.addCurveFloater.grid(row=12, column=0, rowspan=2, columnspan=3)
|
||||
self.addCurveFloater.grid(row=12, column=0, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addXFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='X',
|
||||
maxVelocity=1.0,
|
||||
#maxVelocity=1.0,
|
||||
command=self.setDNATargetX)
|
||||
self.addXFloater.grid(row=4, column=3, rowspan=2, columnspan=3)
|
||||
self.addXFloater.grid(row=4, column=3, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addZFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Z',
|
||||
maxVelocity=1.0,
|
||||
#maxVelocity=1.0,
|
||||
command=self.setDNATargetZ)
|
||||
self.addZFloater.grid(row=6, column=3, rowspan=2, columnspan=3)
|
||||
self.addZFloater.grid(row=6, column=3, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addScaleXFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Scale X',
|
||||
maxVelocity=1.0,
|
||||
#maxVelocity=1.0,
|
||||
command=self.setDNATargetScaleX)
|
||||
self.addScaleXFloater.grid(row=8, column=3, rowspan=2, columnspan=3)
|
||||
self.addScaleXFloater.grid(row=8, column=3, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addScaleZFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Scale Z',
|
||||
maxVelocity=1.0,
|
||||
#maxVelocity=1.0,
|
||||
command=self.setDNATargetScaleZ)
|
||||
self.addScaleZFloater.grid(row=10, column=3, rowspan=2, columnspan=3)
|
||||
self.addScaleZFloater.grid(row=10, column=3, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
self.addRollFloater = Floater.Floater(
|
||||
gridFrame,
|
||||
text='Roll',
|
||||
maxVelocity=10.0,
|
||||
#maxVelocity=10.0,
|
||||
command=self.setDNATargetRoll)
|
||||
self.addRollFloater.grid(row=12, column=3, rowspan=2, columnspan=3)
|
||||
self.addRollFloater.grid(row=12, column=3, rowspan=2, columnspan=3,
|
||||
sticky = EW)
|
||||
|
||||
gridFrame.pack(fill=BOTH)
|
||||
|
||||
|
@ -369,7 +369,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.pConstantAttenuation = EntryScale.EntryScale(
|
||||
pointPage,
|
||||
text = 'Constant Attenuation',
|
||||
min = 0.0, max = 1.0, initialValue = 1.0)
|
||||
min = 0.0, max = 1.0, value = 1.0)
|
||||
self.pConstantAttenuation['command'] = self.setConstantAttenuation
|
||||
self.pConstantAttenuation.pack(fill = X, expand = 0)
|
||||
self.bind(self.pConstantAttenuation,
|
||||
@ -378,7 +378,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.pLinearAttenuation = EntryScale.EntryScale(
|
||||
pointPage,
|
||||
text = 'Linear Attenuation',
|
||||
min = 0.0, max = 1.0, initialValue = 0.0)
|
||||
min = 0.0, max = 1.0, value = 0.0)
|
||||
self.pLinearAttenuation['command'] = self.setLinearAttenuation
|
||||
self.pLinearAttenuation.pack(fill = X, expand = 0)
|
||||
self.bind(self.pLinearAttenuation,
|
||||
@ -387,7 +387,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.pQuadraticAttenuation = EntryScale.EntryScale(
|
||||
pointPage,
|
||||
text = 'Quadratic Attenuation',
|
||||
min = 0.0, max = 1.0, initialValue = 0.0)
|
||||
min = 0.0, max = 1.0, value = 0.0)
|
||||
self.pQuadraticAttenuation['command'] = self.setQuadraticAttenuation
|
||||
self.pQuadraticAttenuation.pack(fill = X, expand = 0)
|
||||
self.bind(self.pQuadraticAttenuation,
|
||||
@ -404,7 +404,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.sConstantAttenuation = EntryScale.EntryScale(
|
||||
spotPage,
|
||||
text = 'Constant Attenuation',
|
||||
min = 0.0, max = 1.0, initialValue = 1.0)
|
||||
min = 0.0, max = 1.0, value = 1.0)
|
||||
self.sConstantAttenuation['command'] = self.setConstantAttenuation
|
||||
self.sConstantAttenuation.pack(fill = X, expand = 0)
|
||||
self.bind(self.sConstantAttenuation,
|
||||
@ -413,7 +413,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.sLinearAttenuation = EntryScale.EntryScale(
|
||||
spotPage,
|
||||
text = 'Linear Attenuation',
|
||||
min = 0.0, max = 1.0, initialValue = 0.0)
|
||||
min = 0.0, max = 1.0, value = 0.0)
|
||||
self.sLinearAttenuation['command'] = self.setLinearAttenuation
|
||||
self.sLinearAttenuation.pack(fill = X, expand = 0)
|
||||
self.bind(self.sLinearAttenuation,
|
||||
@ -422,7 +422,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.sQuadraticAttenuation = EntryScale.EntryScale(
|
||||
spotPage,
|
||||
text = 'Quadratic Attenuation',
|
||||
min = 0.0, max = 1.0, initialValue = 0.0)
|
||||
min = 0.0, max = 1.0, value = 0.0)
|
||||
self.sQuadraticAttenuation['command'] = self.setQuadraticAttenuation
|
||||
self.sQuadraticAttenuation.pack(fill = X, expand = 0)
|
||||
self.bind(self.sQuadraticAttenuation,
|
||||
@ -431,7 +431,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.sExponent = EntryScale.EntryScale(
|
||||
spotPage,
|
||||
text = 'Exponent',
|
||||
min = 0.0, max = 1.0, initialValue = 0.0)
|
||||
min = 0.0, max = 1.0, value = 0.0)
|
||||
self.sExponent['command'] = self.setExponent
|
||||
self.sExponent.pack(fill = X, expand = 0)
|
||||
self.bind(self.sExponent,
|
||||
@ -478,7 +478,7 @@ class DirectSessionPanel(AppShell):
|
||||
gridPage,
|
||||
text = 'Grid Spacing',
|
||||
min = 0.1,
|
||||
initialValue = direct.grid.getGridSpacing())
|
||||
value = direct.grid.getGridSpacing())
|
||||
self.gridSpacing['command'] = direct.grid.setGridSpacing
|
||||
self.gridSpacing.pack(fill = X, expand = 0)
|
||||
|
||||
@ -486,13 +486,14 @@ class DirectSessionPanel(AppShell):
|
||||
gridPage,
|
||||
text = 'Grid Size',
|
||||
min = 1.0,
|
||||
initialValue = direct.grid.getGridSize())
|
||||
value = direct.grid.getGridSize())
|
||||
self.gridSize['command'] = direct.grid.setGridSize
|
||||
self.gridSize.pack(fill = X, expand = 0)
|
||||
|
||||
self.gridSnapAngle = Dial.AngleDial(
|
||||
gridPage,
|
||||
text = 'Snap Angle',
|
||||
style = Dial.DIAL_MINI,
|
||||
value = direct.grid.getSnapAngle())
|
||||
self.gridSnapAngle['command'] = direct.grid.setSnapAngle
|
||||
self.gridSnapAngle.pack(fill = X, expand = 0)
|
||||
@ -544,7 +545,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.jbXyzSF = EntryScale.EntryScale(
|
||||
joyboxFrame,
|
||||
text = 'XYZ Scale Factor',
|
||||
initialValue = 1.0,
|
||||
value = 1.0,
|
||||
hull_relief = RIDGE, hull_borderwidth = 2,
|
||||
min = 1.0, max = 100.0)
|
||||
self.jbXyzSF['command'] = (
|
||||
@ -555,7 +556,7 @@ class DirectSessionPanel(AppShell):
|
||||
self.jbHprSF = EntryScale.EntryScale(
|
||||
joyboxFrame,
|
||||
text = 'HPR Scale Factor',
|
||||
initialValue = 1.0,
|
||||
value = 1.0,
|
||||
hull_relief = RIDGE, hull_borderwidth = 2,
|
||||
min = 1.0, max = 100.0)
|
||||
self.jbHprSF['command'] = (
|
||||
|
@ -370,7 +370,7 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
'Number of samples in resampled curve',
|
||||
resolution = 1, min = 2, max = 1000, command = self.setNumSamples)
|
||||
widget.component('hull')['relief'] = RIDGE
|
||||
widget.onRelease = widget.onReturnRelease = self.sampleCurve
|
||||
widget['preCallback'] = widget['postCallback'] = self.sampleCurve
|
||||
|
||||
frame = Frame(resampleFrame)
|
||||
self.createButton(
|
||||
@ -395,7 +395,7 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
min = 1, max = 100, resolution = 1,
|
||||
command = self.setDesampleFrequency)
|
||||
widget.component('hull')['relief'] = RIDGE
|
||||
widget.onRelease = widget.onReturnRelease = self.desampleCurve
|
||||
widget['postCallback'] = self.desampleCurve
|
||||
desampleFrame.pack(fill = X, expand = 0, pady = 2)
|
||||
|
||||
## REFINE PAGE ##
|
||||
@ -410,29 +410,28 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
'Begin time of refine pass',
|
||||
resolution = 0.01,
|
||||
command = self.setRecordStart)
|
||||
widget.onPress = self.setRefineMode
|
||||
widget.onRelease = widget.onReturnRelease = (
|
||||
lambda s = self: s.getPrePoints('Refine'))
|
||||
widget['preCallback'] = self.setRefineMode
|
||||
widget['postCallback'] = lambda s = self: s.getPrePoints('Refine')
|
||||
widget = self.createEntryScale(
|
||||
refineFrame, 'Refine Page',
|
||||
'Control Start',
|
||||
'Time when full control of node path is given during refine pass',
|
||||
resolution = 0.01,
|
||||
command = self.setControlStart)
|
||||
widget.onPress = widget.onReturn = self.setRefineMode
|
||||
widget['preCallback'] = self.setRefineMode
|
||||
widget = self.createEntryScale(
|
||||
refineFrame, 'Refine Page',
|
||||
'Control Stop',
|
||||
'Time when node path begins transition back to original curve',
|
||||
resolution = 0.01,
|
||||
command = self.setControlStop)
|
||||
widget.onPress = widget.onReturn = self.setRefineMode
|
||||
widget['preCallback'] = self.setRefineMode
|
||||
widget = self.createEntryScale(refineFrame, 'Refine Page', 'Refine To',
|
||||
'Stop time of refine pass',
|
||||
resolution = 0.01,
|
||||
command = self.setRefineStop)
|
||||
widget.onPress = self.setRefineMode
|
||||
widget.onRelease = widget.onReturnRelease = self.getPostPoints
|
||||
widget['preCallback'] = self.setRefineMode
|
||||
widget['postCallback'] = self.getPostPoints
|
||||
refineFrame.pack(fill = X)
|
||||
|
||||
## EXTEND PAGE ##
|
||||
@ -447,16 +446,15 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
'Begin time of extend pass',
|
||||
resolution = 0.01,
|
||||
command = self.setRecordStart)
|
||||
widget.onPress = self.setExtendMode
|
||||
widget.onRelease = widget.onReturnRelease = (
|
||||
lambda s = self: s.getPrePoints('Extend'))
|
||||
widget['preCallback'] = self.setExtendMode
|
||||
widget['postCallback'] = lambda s = self: s.getPrePoints('Extend')
|
||||
widget = self.createEntryScale(
|
||||
extendFrame, 'Extend Page',
|
||||
'Control Start',
|
||||
'Time when full control of node path is given during extend pass',
|
||||
resolution = 0.01,
|
||||
command = self.setControlStart)
|
||||
widget.onPress = widget.onReturn = self.setExtendMode
|
||||
widget['preCallback'] = self.setExtendMode
|
||||
extendFrame.pack(fill = X)
|
||||
|
||||
## CROP PAGE ##
|
||||
@ -529,48 +527,48 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
sfFrame, 'Style', 'Num Segs',
|
||||
'Set number of segments used to approximate each parametric unit',
|
||||
min = 1.0, max = 400, resolution = 1.0,
|
||||
initialValue = 40,
|
||||
value = 40,
|
||||
command = self.setNumSegs, side = TOP)
|
||||
widget.component('hull')['relief'] = RIDGE
|
||||
widget = self.createEntryScale(
|
||||
sfFrame, 'Style', 'Num Ticks',
|
||||
'Set number of tick marks drawn for each unit of time',
|
||||
min = 0.0, max = 10.0, resolution = 1.0,
|
||||
initialValue = 0.0,
|
||||
value = 0.0,
|
||||
command = self.setNumTicks, side = TOP)
|
||||
widget.component('hull')['relief'] = RIDGE
|
||||
widget = self.createEntryScale(
|
||||
sfFrame, 'Style', 'Tick Scale',
|
||||
'Set visible size of time tick marks',
|
||||
min = 0.01, max = 100.0, resolution = 0.01,
|
||||
initialValue = 5.0,
|
||||
value = 5.0,
|
||||
command = self.setTickScale, side = TOP)
|
||||
widget.component('hull')['relief'] = RIDGE
|
||||
self.createColorEntry(
|
||||
sfFrame, 'Style', 'Path Color',
|
||||
'Color of curve',
|
||||
command = self.setPathColor,
|
||||
initialValue = [255.0,255.0,255.0,255.0])
|
||||
value = [255.0,255.0,255.0,255.0])
|
||||
self.createColorEntry(
|
||||
sfFrame, 'Style', 'Knot Color',
|
||||
'Color of knots',
|
||||
command = self.setKnotColor,
|
||||
initialValue = [0,0,255.0,255.0])
|
||||
value = [0,0,255.0,255.0])
|
||||
self.createColorEntry(
|
||||
sfFrame, 'Style', 'CV Color',
|
||||
'Color of CVs',
|
||||
command = self.setCvColor,
|
||||
initialValue = [255.0,0,0,255.0])
|
||||
value = [255.0,0,0,255.0])
|
||||
self.createColorEntry(
|
||||
sfFrame, 'Style', 'Tick Color',
|
||||
'Color of Ticks',
|
||||
command = self.setTickColor,
|
||||
initialValue = [255.0,0,0,255.0])
|
||||
value = [255.0,0,0,255.0])
|
||||
self.createColorEntry(
|
||||
sfFrame, 'Style', 'Hull Color',
|
||||
'Color of Hull',
|
||||
command = self.setHullColor,
|
||||
initialValue = [255.0,128.0,128.0,255.0])
|
||||
value = [255.0,128.0,128.0,255.0])
|
||||
|
||||
#drawFrame.pack(fill = X)
|
||||
|
||||
@ -585,7 +583,7 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
widget = self.createLabeledEntry(
|
||||
frame, 'Recording', 'Record Hook',
|
||||
'Hook used to start/stop recording',
|
||||
initialValue = self.startStopHook,
|
||||
value = self.startStopHook,
|
||||
command = self.setStartStopHook)[0]
|
||||
label = self.getWidget('Recording', 'Record Hook-Label')
|
||||
label.configure(width = 16, anchor = W)
|
||||
@ -593,7 +591,7 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
widget = self.createLabeledEntry(
|
||||
frame, 'Recording', 'Keyframe Hook',
|
||||
'Hook used to add a new keyframe',
|
||||
initialValue = self.keyframeHook,
|
||||
value = self.keyframeHook,
|
||||
command = self.setKeyframeHook)[0]
|
||||
label = self.getWidget('Recording', 'Keyframe Hook-Label')
|
||||
label.configure(width = 16, anchor = W)
|
||||
@ -1678,12 +1676,12 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
return self.variableDict[category + '-' + text]
|
||||
|
||||
def createLabeledEntry(self, parent, category, text, balloonHelp,
|
||||
initialValue = '', command = None,
|
||||
value = '', command = None,
|
||||
relief = 'sunken', side = LEFT,
|
||||
expand = 1, width = 12):
|
||||
frame = Frame(parent)
|
||||
variable = StringVar()
|
||||
variable.set(initialValue)
|
||||
variable.set(value)
|
||||
label = Label(frame, text = text)
|
||||
label.pack(side = LEFT, fill = X)
|
||||
self.bind(label, balloonHelp)
|
||||
|
@ -20,7 +20,7 @@ class ParticlePanel(AppShell):
|
||||
# Override class variables
|
||||
appname = 'Particle Panel'
|
||||
frameWidth = 375
|
||||
frameHeight = 775
|
||||
frameHeight = 575
|
||||
usecommandarea = 0
|
||||
usestatusarea = 0
|
||||
balloonState = 'both'
|
||||
@ -374,7 +374,7 @@ class ParticlePanel(AppShell):
|
||||
self.createVector3Entry(boxPage, 'Box Emitter', 'Max',
|
||||
'Max point defining emitter box',
|
||||
command = self.setEmitterBoxPoint2,
|
||||
initialValue = (1.0, 1.0, 1.0))
|
||||
value = (1.0, 1.0, 1.0))
|
||||
# Disc page #
|
||||
discPage = self.emitterNotebook.add('DiscEmitter')
|
||||
self.createFloater(discPage, 'Disc Emitter', 'Radius',
|
||||
@ -408,7 +408,7 @@ class ParticlePanel(AppShell):
|
||||
self.createVector3Entry(linePage, 'Line Emitter', 'Max',
|
||||
'Max point defining emitter line',
|
||||
command = self.setEmitterLinePoint2,
|
||||
initialValue = (1.0, 0.0, 0.0))
|
||||
value = (1.0, 0.0, 0.0))
|
||||
# Point page #
|
||||
emitterPointPage = self.emitterNotebook.add('PointEmitter')
|
||||
self.createVector3Entry(emitterPointPage, 'Point Emitter', 'Position',
|
||||
@ -736,13 +736,11 @@ class ParticlePanel(AppShell):
|
||||
|
||||
def createFloater(self, parent, category, text, balloonHelp,
|
||||
command = None, min = 0.0, resolution = None,
|
||||
significantDigits = 3,
|
||||
maxVelocity = 10.0, **kw):
|
||||
numDigits = 3, **kw):
|
||||
kw['text'] = text
|
||||
kw['min'] = min
|
||||
kw['maxVelocity'] = maxVelocity
|
||||
kw['resolution'] = resolution
|
||||
kw['significantDigits'] = significantDigits
|
||||
kw['floater_resolution'] = resolution
|
||||
kw['numDigits'] = numDigits
|
||||
widget = apply(Floater.Floater, (parent,), kw)
|
||||
# Do this after the widget so command isn't called on creation
|
||||
widget['command'] = command
|
||||
@ -754,6 +752,7 @@ class ParticlePanel(AppShell):
|
||||
def createAngleDial(self, parent, category, text, balloonHelp,
|
||||
command = None, **kw):
|
||||
kw['text'] = text
|
||||
kw['style'] = Dial.DIAL_MINI
|
||||
widget = apply(Dial.AngleDial,(parent,), kw)
|
||||
# Do this after the widget so command isn't called on creation
|
||||
widget['command'] = command
|
||||
@ -1771,7 +1770,7 @@ class ParticlePanel(AppShell):
|
||||
self.createFloater(frame, pageName, forceName + ' Amplitude',
|
||||
'Force amplitude multiplier',
|
||||
command = setAmplitude,
|
||||
initialValue = force.getAmplitude())
|
||||
value = force.getAmplitude())
|
||||
cbf = Frame(frame, relief = FLAT)
|
||||
self.createCheckbutton(cbf, pageName, forceName + ' Mass Dependent',
|
||||
('On: force depends on mass; ' +
|
||||
@ -1808,7 +1807,7 @@ class ParticlePanel(AppShell):
|
||||
self.createVector3Entry(frame, pageName, forceName,
|
||||
'Set force direction and magnitude',
|
||||
command = setVec,
|
||||
initialValue = [vec[0], vec[1], vec[2]])
|
||||
value = [vec[0], vec[1], vec[2]])
|
||||
self.createForceActiveWidget(frame, pageName, forceName, force)
|
||||
|
||||
def createLinearRandomForceWidget(self, forcePage, pageName, count,
|
||||
@ -1828,7 +1827,7 @@ class ParticlePanel(AppShell):
|
||||
self.createFloater(frame, pageName, forceName + ' Coef',
|
||||
'Set linear friction force',
|
||||
command = setCoef, min = None,
|
||||
initialValue = force.getCoef())
|
||||
value = force.getCoef())
|
||||
self.createForceActiveWidget(frame, pageName, forceName, force)
|
||||
|
||||
def createLinearCylinderVortexForceWidget(self, forcePage, pageName,
|
||||
@ -1845,15 +1844,15 @@ class ParticlePanel(AppShell):
|
||||
self.createFloater(frame, pageName, forceName + ' Coef',
|
||||
'Set linear cylinder vortex coefficient',
|
||||
command = setCoef,
|
||||
initialValue = force.getCoef())
|
||||
value = force.getCoef())
|
||||
self.createFloater(frame, pageName, forceName + ' Length',
|
||||
'Set linear cylinder vortex length',
|
||||
command = setLength,
|
||||
initialValue = force.getLength())
|
||||
value = force.getLength())
|
||||
self.createFloater(frame, pageName, forceName + ' Radius',
|
||||
'Set linear cylinder vortex radius',
|
||||
command = setRadius,
|
||||
initialValue = force.getRadius())
|
||||
value = force.getRadius())
|
||||
self.createForceActiveWidget(frame, pageName, forceName, force)
|
||||
|
||||
def createLinearDistanceForceWidget(self, forcePage, pageName,
|
||||
@ -1896,12 +1895,12 @@ class ParticlePanel(AppShell):
|
||||
'Set center of force',
|
||||
command = setForceCenter,
|
||||
label_width = 16,
|
||||
initialValue = [vec[0], vec[1], vec[2]])
|
||||
value = [vec[0], vec[1], vec[2]])
|
||||
self.createFloater(frame, pageName, forceName + ' Radius',
|
||||
'Set falloff radius',
|
||||
command = setRadius,
|
||||
min = 0.01,
|
||||
initialValue = force.getRadius())
|
||||
value = force.getRadius())
|
||||
self.createForceActiveWidget(frame, pageName, forceName, force)
|
||||
|
||||
######################################################################
|
||||
|
@ -18,8 +18,8 @@ class Placer(AppShell):
|
||||
# Override class variables here
|
||||
appname = 'Placer Panel'
|
||||
frameWidth = 625
|
||||
frameHeight = 290
|
||||
usecommandarea = 1
|
||||
frameHeight = 215
|
||||
usecommandarea = 0
|
||||
usestatusarea = 0
|
||||
|
||||
def __init__(self, parent = None, **kw):
|
||||
@ -82,6 +82,7 @@ class Placer(AppShell):
|
||||
def createInterface(self):
|
||||
# The interior of the toplevel panel
|
||||
interior = self.interior()
|
||||
interior['relief'] = FLAT
|
||||
# Add placer commands to menubar
|
||||
self.menuBar.addmenu('Placer', 'Placer Panel Operations')
|
||||
self.menuBar.addmenuitem('Placer', 'command',
|
||||
@ -159,20 +160,16 @@ class Placer(AppShell):
|
||||
self.redoButton.pack(side = 'left', expand = 0)
|
||||
self.bind(self.redoButton, 'Redo last operation')
|
||||
|
||||
# The master frame for the dials
|
||||
dialFrame = Frame(interior)
|
||||
dialFrame.pack(fill = 'both', expand = 1)
|
||||
|
||||
# Create and pack the Pos Controls
|
||||
posGroup = Pmw.Group(dialFrame,
|
||||
posGroup = Pmw.Group(interior,
|
||||
tag_pyclass = Menubutton,
|
||||
tag_text = 'Position',
|
||||
tag_font=('MSSansSerif', 14, 'bold'),
|
||||
tag_font=('MSSansSerif', 14),
|
||||
tag_activebackground = '#909090',
|
||||
ring_relief = 'flat')
|
||||
ring_relief = RIDGE)
|
||||
posMenubutton = posGroup.component('tag')
|
||||
self.bind(posMenubutton, 'Position menu operations')
|
||||
posMenu = Menu(posMenubutton)
|
||||
posMenu = Menu(posMenubutton, tearoff = 0)
|
||||
posMenu.add_command(label = 'Set to zero', command = self.zeroPos)
|
||||
posMenu.add_command(label = 'Reset initial',
|
||||
command = self.resetPos)
|
||||
@ -183,56 +180,50 @@ class Placer(AppShell):
|
||||
# Create the dials
|
||||
self.posX = self.createcomponent('posX', (), None,
|
||||
Floater.Floater, (posInterior,),
|
||||
text = 'X',
|
||||
initialValue = 0.0,
|
||||
text = 'X', relief = FLAT,
|
||||
value = 0.0,
|
||||
label_foreground = 'Red')
|
||||
self.posX['command'] = self.xform
|
||||
self.posX['commandData'] = ['x']
|
||||
self.posX['preCallback'] = self.xformStart
|
||||
self.posX['postCallback'] = self.xformStop
|
||||
self.posX['callbackData'] = ['x']
|
||||
self.posX.onReturn = self.xformStart
|
||||
self.posX.onReturnRelease = self.xformStop
|
||||
self.posX.onPress = self.xformStart
|
||||
self.posX.onRelease = self.xformStop
|
||||
self.posX.pack(expand=1,fill='both')
|
||||
|
||||
self.posY = self.createcomponent('posY', (), None,
|
||||
Floater.Floater, (posInterior,),
|
||||
text = 'Y',
|
||||
initialValue = 0.0,
|
||||
text = 'Y', relief = FLAT,
|
||||
value = 0.0,
|
||||
label_foreground = '#00A000')
|
||||
self.posY['command'] = self.xform
|
||||
self.posY['commandData'] = ['y']
|
||||
self.posY['preCallback'] = self.xformStart
|
||||
self.posY['postCallback'] = self.xformStop
|
||||
self.posY['callbackData'] = ['y']
|
||||
self.posY.onReturn = self.xformStart
|
||||
self.posY.onReturnRelease = self.xformStop
|
||||
self.posY.onPress = self.xformStart
|
||||
self.posY.onRelease = self.xformStop
|
||||
self.posY.pack(expand=1,fill='both')
|
||||
|
||||
self.posZ = self.createcomponent('posZ', (), None,
|
||||
Floater.Floater, (posInterior,),
|
||||
text = 'Z',
|
||||
initialValue = 0.0,
|
||||
text = 'Z', relief = FLAT,
|
||||
value = 0.0,
|
||||
label_foreground = 'Blue')
|
||||
self.posZ['command'] = self.xform
|
||||
self.posZ['commandData'] = ['z']
|
||||
self.posZ['preCallback'] = self.xformStart
|
||||
self.posZ['postCallback'] = self.xformStop
|
||||
self.posZ['callbackData'] = ['z']
|
||||
self.posZ.onReturn = self.xformStart
|
||||
self.posZ.onReturnRelease = self.xformStop
|
||||
self.posZ.onPress = self.xformStart
|
||||
self.posZ.onRelease = self.xformStop
|
||||
self.posZ.pack(expand=1,fill='both')
|
||||
|
||||
# Create and pack the Hpr Controls
|
||||
hprGroup = Pmw.Group(dialFrame,
|
||||
hprGroup = Pmw.Group(interior,
|
||||
tag_pyclass = Menubutton,
|
||||
tag_text = 'Orientation',
|
||||
tag_font=('MSSansSerif', 14, 'bold'),
|
||||
tag_font=('MSSansSerif', 14),
|
||||
tag_activebackground = '#909090',
|
||||
ring_relief = 'flat')
|
||||
ring_relief = RIDGE)
|
||||
hprMenubutton = hprGroup.component('tag')
|
||||
self.bind(hprMenubutton, 'Orientation menu operations')
|
||||
hprMenu = Menu(hprMenubutton)
|
||||
hprMenu = Menu(hprMenubutton, tearoff = 0)
|
||||
hprMenu.add_command(label = 'Set to zero', command = self.zeroHpr)
|
||||
hprMenu.add_command(label = 'Reset initial', command = self.resetHpr)
|
||||
hprMenubutton['menu'] = hprMenu
|
||||
@ -242,41 +233,41 @@ class Placer(AppShell):
|
||||
# Create the dials
|
||||
self.hprH = self.createcomponent('hprH', (), None,
|
||||
Dial.AngleDial, (hprInterior,),
|
||||
style = Dial.DIAL_MINI,
|
||||
text = 'H', value = 0.0,
|
||||
relief = FLAT,
|
||||
label_foreground = 'blue')
|
||||
self.hprH['command'] = self.xform
|
||||
self.hprH['commandData'] = ['h']
|
||||
self.hprH['preCallback'] = self.xformStart
|
||||
self.hprH['postCallback'] = self.xformStop
|
||||
self.hprH['callbackData'] = ['h']
|
||||
self.hprH['onReturnPress'] = self.xformStart
|
||||
self.hprH['onReturnRelease'] = self.xformStop
|
||||
self.hprH['onButtonPress'] = self.xformStart
|
||||
self.hprH['onButtonRelease'] = self.xformStop
|
||||
self.hprH.pack(expand=1,fill='both')
|
||||
|
||||
self.hprP = self.createcomponent('hprP', (), None,
|
||||
Dial.AngleDial, (hprInterior,),
|
||||
style = Dial.DIAL_MINI,
|
||||
text = 'P', value = 0.0,
|
||||
relief = FLAT,
|
||||
label_foreground = 'red')
|
||||
self.hprP['command'] = self.xform
|
||||
self.hprP['commandData'] = ['p']
|
||||
self.hprP['preCallback'] = self.xformStart
|
||||
self.hprP['postCallback'] = self.xformStop
|
||||
self.hprP['callbackData'] = ['p']
|
||||
self.hprP['onReturnPress'] = self.xformStart
|
||||
self.hprP['onReturnRelease'] = self.xformStop
|
||||
self.hprP['onButtonPress'] = self.xformStart
|
||||
self.hprP['onButtonRelease'] = self.xformStop
|
||||
self.hprP.pack(expand=1,fill='both')
|
||||
|
||||
self.hprR = self.createcomponent('hprR', (), None,
|
||||
Dial.AngleDial, (hprInterior,),
|
||||
style = Dial.DIAL_MINI,
|
||||
text = 'R', value = 0.0,
|
||||
relief = FLAT,
|
||||
label_foreground = '#00A000')
|
||||
self.hprR['command'] = self.xform
|
||||
self.hprR['commandData'] = ['r']
|
||||
self.hprR['preCallback'] = self.xformStart
|
||||
self.hprR['postCallback'] = self.xformStop
|
||||
self.hprR['callbackData'] = ['r']
|
||||
self.hprR['onReturnPress'] = self.xformStart
|
||||
self.hprR['onReturnRelease'] = self.xformStop
|
||||
self.hprR['onButtonPress'] = self.xformStart
|
||||
self.hprR['onButtonRelease'] = self.xformStop
|
||||
self.hprR.pack(expand=1,fill='both')
|
||||
|
||||
# Create and pack the Scale Controls
|
||||
@ -284,18 +275,18 @@ class Placer(AppShell):
|
||||
self.scalingMode = StringVar()
|
||||
self.scalingMode.set('Scale Uniform')
|
||||
# The scaling widgets
|
||||
scaleGroup = Pmw.Group(dialFrame,
|
||||
scaleGroup = Pmw.Group(interior,
|
||||
tag_text = 'Scale Uniform',
|
||||
tag_pyclass = Menubutton,
|
||||
tag_font=('MSSansSerif', 14, 'bold'),
|
||||
tag_font=('MSSansSerif', 14),
|
||||
tag_activebackground = '#909090',
|
||||
ring_relief = 'flat')
|
||||
ring_relief = RIDGE)
|
||||
self.scaleMenubutton = scaleGroup.component('tag')
|
||||
self.bind(self.scaleMenubutton, 'Scale menu operations')
|
||||
self.scaleMenubutton['textvariable'] = self.scalingMode
|
||||
|
||||
# Scaling menu
|
||||
scaleMenu = Menu(self.scaleMenubutton)
|
||||
scaleMenu = Menu(self.scaleMenubutton, tearoff = 0)
|
||||
scaleMenu.add_command(label = 'Set to unity',
|
||||
command = self.unitScale)
|
||||
scaleMenu.add_command(label = 'Reset initial',
|
||||
@ -313,48 +304,45 @@ class Placer(AppShell):
|
||||
|
||||
# Create the dials
|
||||
self.scaleX = self.createcomponent('scaleX', (), None,
|
||||
Dial.Dial, (scaleInterior,),
|
||||
Floater.Floater, (scaleInterior,),
|
||||
text = 'X Scale',
|
||||
relief = FLAT,
|
||||
min = 0.0001, value = 1.0,
|
||||
resetValue = 1.0,
|
||||
label_foreground = 'Red')
|
||||
self.scaleX['command'] = self.xform
|
||||
self.scaleX['commandData'] = ['sx']
|
||||
self.scaleX['callbackData'] = ['sx']
|
||||
self.scaleX['onReturnPress'] = self.xformStart
|
||||
self.scaleX['onReturnRelease'] = self.xformStop
|
||||
self.scaleX['onButtonPress'] = self.xformStart
|
||||
self.scaleX['onButtonRelease'] = self.xformStop
|
||||
self.scaleX['preCallback'] = self.xformStart
|
||||
self.scaleX['postCallback'] = self.xformStop
|
||||
self.scaleX.pack(expand=1,fill='both')
|
||||
|
||||
self.scaleY = self.createcomponent('scaleY', (), None,
|
||||
Dial.Dial, (scaleInterior,),
|
||||
Floater.Floater, (scaleInterior,),
|
||||
text = 'Y Scale',
|
||||
relief = FLAT,
|
||||
min = 0.0001, value = 1.0,
|
||||
resetValue = 1.0,
|
||||
label_foreground = '#00A000')
|
||||
self.scaleY['command'] = self.xform
|
||||
self.scaleY['commandData'] = ['sy']
|
||||
self.scaleY['callbackData'] = ['sy']
|
||||
self.scaleY['onReturnPress'] = self.xformStart
|
||||
self.scaleY['onReturnRelease'] = self.xformStop
|
||||
self.scaleY['onButtonPress'] = self.xformStart
|
||||
self.scaleY['onButtonRelease'] = self.xformStop
|
||||
self.scaleY['preCallback'] = self.xformStart
|
||||
self.scaleY['postCallback'] = self.xformStop
|
||||
self.scaleY.pack(expand=1,fill='both')
|
||||
|
||||
self.scaleZ = self.createcomponent('scaleZ', (), None,
|
||||
Dial.Dial, (scaleInterior,),
|
||||
Floater.Floater, (scaleInterior,),
|
||||
text = 'Z Scale',
|
||||
relief = FLAT,
|
||||
min = 0.0001, value = 1.0,
|
||||
resetValue = 1.0,
|
||||
label_foreground = 'Blue')
|
||||
self.scaleZ['command'] = self.xform
|
||||
self.scaleZ['commandData'] = ['sz']
|
||||
self.scaleZ['callbackData'] = ['sz']
|
||||
self.scaleZ['onReturnPress'] = self.xformStart
|
||||
self.scaleZ['onReturnRelease'] = self.xformStop
|
||||
self.scaleZ['onButtonPress'] = self.xformStart
|
||||
self.scaleZ['onButtonRelease'] = self.xformStop
|
||||
self.scaleZ['preCallback'] = self.xformStart
|
||||
self.scaleZ['postCallback'] = self.xformStop
|
||||
self.scaleZ.pack(expand=1,fill='both')
|
||||
|
||||
# Make sure appropriate labels are showing
|
||||
@ -363,33 +351,6 @@ class Placer(AppShell):
|
||||
self.selectNodePathNamed('init')
|
||||
self.selectRefNodePathNamed('parent')
|
||||
|
||||
self.createButtons()
|
||||
|
||||
def createButtons(self):
|
||||
self.buttonAdd('Zero All',
|
||||
helpMessage='Zero Node Path',
|
||||
statusMessage='Zero Node Path',
|
||||
command=self.zeroAll)
|
||||
self.buttonAdd('Reset All',
|
||||
helpMessage='Reset Node Path',
|
||||
statusMessage='Reset Node Path',
|
||||
command=self.resetAll)
|
||||
self.buttonAdd('Print Info',
|
||||
helpMessage='Print Node Path Info',
|
||||
statusMessage='Print Node Path Info',
|
||||
command=self.printNodePathInfo)
|
||||
self.buttonAdd('Toggle Widget Viz',
|
||||
helpMessage='Toggle Object Handles Visability',
|
||||
statusMessage='Toggle Object Handles Visability',
|
||||
command=direct.toggleWidgetVis)
|
||||
self.buttonAdd(
|
||||
'Toggle Widget Mode',
|
||||
helpMessage='Toggle Widget Move/COA Mode',
|
||||
statusMessage='Toggle Widget Move/COA Mode',
|
||||
command=direct.manipulationControl.toggleObjectHandlesMode)
|
||||
|
||||
# Make all buttons as wide as widest
|
||||
self.alignbuttons()
|
||||
|
||||
### WIDGET OPERATIONS ###
|
||||
def setMovementMode(self, movementMode):
|
||||
@ -715,8 +676,17 @@ class Placer(AppShell):
|
||||
|
||||
def updateResetValues(self, nodePath):
|
||||
self.initPos.assign(nodePath.getPos())
|
||||
self.posX['resetValue'] = self.initPos[0]
|
||||
self.posY['resetValue'] = self.initPos[1]
|
||||
self.posZ['resetValue'] = self.initPos[2]
|
||||
self.initHpr.assign(nodePath.getHpr())
|
||||
self.hprH['resetValue'] = self.initHpr[0]
|
||||
self.hprP['resetValue'] = self.initHpr[1]
|
||||
self.hprR['resetValue'] = self.initHpr[2]
|
||||
self.initScale.assign(nodePath.getScale())
|
||||
self.scaleX['resetValue'] = self.initScale[0]
|
||||
self.scaleY['resetValue'] = self.initScale[1]
|
||||
self.scaleZ['resetValue'] = self.initScale[2]
|
||||
|
||||
def resetAll(self):
|
||||
if self['nodePath']:
|
||||
|
@ -328,14 +328,14 @@ class AppShell(Pmw.MegaWidget, PandaObject):
|
||||
return widget
|
||||
|
||||
def newCreateLabeledEntry(self, parent, category, text, help = '',
|
||||
command = None, initialValue = '',
|
||||
command = None, value = '',
|
||||
width = 12, relief = SUNKEN,
|
||||
side = LEFT, fill = X, expand = 0):
|
||||
""" createLabeledEntry(parent, category, text, [options]) """
|
||||
# Create labeled entry
|
||||
frame = Frame(parent)
|
||||
variable = StringVar()
|
||||
variable.set(initialValue)
|
||||
variable.set(value)
|
||||
label = Label(frame, text = text)
|
||||
label.pack(side = LEFT, fill = X, expand = 0)
|
||||
entry = Entry(frame, width = width, relief = relief,
|
||||
|
@ -1,6 +1,6 @@
|
||||
from Tkinter import *
|
||||
from PandaModules import ClockObject
|
||||
from WidgetPropertiesDialog import *
|
||||
import WidgetPropertiesDialog
|
||||
import Pmw
|
||||
import Task
|
||||
import math
|
||||
@ -17,7 +17,7 @@ DIAL_FULL = 'full'
|
||||
DIAL_MINI = 'mini'
|
||||
|
||||
DIAL_FULL_SIZE = 45
|
||||
DIAL_MINI_SIZE = 20
|
||||
DIAL_MINI_SIZE = 30
|
||||
|
||||
globalClock = ClockObject.getGlobalClock()
|
||||
|
||||
@ -29,13 +29,8 @@ class Dial(Pmw.MegaWidget):
|
||||
def __init__(self, parent = None, **kw):
|
||||
#define the megawidget options
|
||||
INITOPT = Pmw.INITOPT
|
||||
if 'full' == kw.get('style', DIAL_FULL):
|
||||
DIAL_SIZE = DIAL_FULL_SIZE
|
||||
else:
|
||||
DIAL_SIZE = DIAL_MINI_SIZE
|
||||
optiondefs = (
|
||||
('style', DIAL_FULL, INITOPT),
|
||||
('dial_size', DIAL_SIZE, None),
|
||||
# Widget relief
|
||||
('relief', GROOVE, None),
|
||||
# Widget borderwidth
|
||||
@ -46,21 +41,30 @@ class Dial(Pmw.MegaWidget):
|
||||
('numDigits', 2, self.setEntryFormat),
|
||||
('command', None, None),
|
||||
('commandData', [], None),
|
||||
('callbackData', [], self.setCallbackData),
|
||||
('min', None, self.setMin),
|
||||
('max', None, self.setMax),
|
||||
('base', 0.0, self.setBase),
|
||||
('delta', 1.0, self.setDelta),
|
||||
('onReturnPress', None, None),
|
||||
('onReturnRelease', None, None),
|
||||
('onButtonPress', None, self.setButtonPressCmd),
|
||||
('onButtonRelease', None, self.setButtonReleaseCmd),
|
||||
# Callbacks to execute when updating widget's value
|
||||
('preCallback', None, self.setPreCallbackCmd),
|
||||
('postCallback', None, self.setPostCallbackCmd),
|
||||
# Extra data to be passed to callback function, needs to be a list
|
||||
('callbackData', [], self.setCallbackData),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize the superclass
|
||||
Pmw.MegaWidget.__init__(self, parent)
|
||||
|
||||
# Override size if style specified by size is not
|
||||
if not kw.has_key('dial_size'):
|
||||
if self['style'] == DIAL_FULL:
|
||||
dialSize = DIAL_FULL_SIZE
|
||||
else:
|
||||
dialSize = DIAL_MINI_SIZE
|
||||
else:
|
||||
dialSize = DIAL_FULL_SIZE
|
||||
|
||||
# Create the components
|
||||
interior = self.interior()
|
||||
interior.configure(relief = self['relief'], bd = self['borderwidth'])
|
||||
@ -68,15 +72,24 @@ class Dial(Pmw.MegaWidget):
|
||||
# The Dial
|
||||
self._dial = self.createcomponent('dial', (), None,
|
||||
DialWidget, (interior,),
|
||||
size = dialSize,
|
||||
command = self.setEntry,
|
||||
value = self['value'])
|
||||
|
||||
self._dial.propertyDict['numDigits'] = {
|
||||
'widget' : self,
|
||||
'type' : 'integer',
|
||||
'help' : 'Enter number of digits after decimal point.'
|
||||
}
|
||||
self._dial.propertyList.append('numDigits')
|
||||
self._dial.addPropertyToDialog(
|
||||
'text',
|
||||
{'widget' : self,
|
||||
'type' : 'string',
|
||||
'help' : 'Enter label text for Dial.'
|
||||
}
|
||||
)
|
||||
self._dial.addPropertyToDialog(
|
||||
'numDigits',
|
||||
{'widget' : self,
|
||||
'type' : 'integer',
|
||||
'help' : 'Enter number of digits after decimal point.'
|
||||
}
|
||||
)
|
||||
|
||||
# The Label
|
||||
self._label = self.createcomponent('label', (), None,
|
||||
@ -99,14 +112,14 @@ class Dial(Pmw.MegaWidget):
|
||||
|
||||
if self['style'] == DIAL_FULL:
|
||||
# Attach dial to entry
|
||||
self._dial.grid(rowspan = 2, columnspan = 2)
|
||||
self._dial.grid(rowspan = 2, columnspan = 2, padx = 2, pady = 2)
|
||||
self._label.grid(row = 0, col = 2, sticky = EW)
|
||||
self._entry.grid(row = 1, col = 2, sticky = EW)
|
||||
interior.columnconfigure(2, weight = 1)
|
||||
else:
|
||||
self._label.grid(row=0,col=0, sticky = EW)
|
||||
self._entry.grid(row=0,col=1, sticky = EW)
|
||||
self._dial.grid(row=0,col=2)
|
||||
self._dial.grid(row=0,col=2, padx = 2, pady = 2)
|
||||
interior.columnconfigure(0, weight = 1)
|
||||
|
||||
# Make sure input variables processed
|
||||
@ -144,13 +157,13 @@ class Dial(Pmw.MegaWidget):
|
||||
|
||||
def _onReturnPress(self, *args):
|
||||
""" User redefinable callback executed on <Return> in entry """
|
||||
if self['onReturnPress']:
|
||||
apply(self['onReturnPress'], self['callbackData'])
|
||||
if self['preCallback']:
|
||||
apply(self['preCallback'], self['callbackData'])
|
||||
|
||||
def _onReturnRelease(self, *args):
|
||||
""" User redefinable callback executed on <Return> release in entry """
|
||||
if self['onReturnRelease']:
|
||||
apply(self['onReturnRelease'], self['callbackData'])
|
||||
if self['postCallback']:
|
||||
apply(self['postCallback'], self['callbackData'])
|
||||
|
||||
# Pass settings down to dial
|
||||
def setCallbackData(self):
|
||||
@ -175,11 +188,12 @@ class Dial(Pmw.MegaWidget):
|
||||
def setLabel(self):
|
||||
self._label['text'] = self['text']
|
||||
|
||||
def setButtonPressCmd(self):
|
||||
self._dial['onButtonPress'] = self['onButtonPress']
|
||||
def setPreCallbackCmd(self):
|
||||
self._dial['preCallback'] = self['preCallback']
|
||||
|
||||
def setPostCallbackCmd(self):
|
||||
self._dial['postCallback'] = self['postCallback']
|
||||
|
||||
def setButtonReleaseCmd(self):
|
||||
self._dial['onButtonRelease'] = self['onButtonRelease']
|
||||
|
||||
class AngleDial(Dial):
|
||||
def __init__(self, parent = None, **kw):
|
||||
@ -237,10 +251,11 @@ class DialWidget(Pmw.MegaWidget):
|
||||
('command', None, None),
|
||||
# Extra data to be passed to command function
|
||||
('commandData', [], None),
|
||||
# Extra data to be passed to callback function
|
||||
# Callback's to execute during mouse interaction
|
||||
('preCallback', None, None),
|
||||
('postCallback', None, None),
|
||||
# Extra data to be passed to callback function, needs to be a list
|
||||
('callbackData', [], None),
|
||||
('onButtonPress', None, None),
|
||||
('onButtonRelease', None, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
@ -262,31 +277,6 @@ class DialWidget(Pmw.MegaWidget):
|
||||
# Radius of the inner knob
|
||||
inner_radius = max(3,radius * INNER_SF)
|
||||
|
||||
# A Dictionary of dictionaries
|
||||
self.propertyDict = {
|
||||
'min' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'fNone' : 1,
|
||||
'help' : 'Minimum allowable dial value, Enter None for no minimum'},
|
||||
'max' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'fNone' : 1,
|
||||
'help' : 'Maximum allowable dial value, Enter None for no maximum'},
|
||||
'base' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'help' : 'Dial value = base + delta * numRevs'},
|
||||
'delta' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'help' : 'Dial value = base + delta * numRevs'},
|
||||
'numSegments' : { 'widget' : self,
|
||||
'type' : 'integer',
|
||||
'help' : 'Number of segments to divide dial into'},
|
||||
'resetValue' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'help' : 'Enter value to set dial to on reset.'}
|
||||
}
|
||||
self.propertyList = ['min', 'max', 'base', 'delta', 'numSegments', 'resetValue']
|
||||
|
||||
# The canvas
|
||||
self._canvas = self.createcomponent('canvas', (), None,
|
||||
Canvas, (interior,),
|
||||
@ -312,6 +302,32 @@ class DialWidget(Pmw.MegaWidget):
|
||||
fill = '#A0A0A0',
|
||||
tags = ('knob',))
|
||||
|
||||
# A Dictionary of dictionaries used for the popup property dialog
|
||||
self.propertyDict = {
|
||||
'min' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'fNone' : 1,
|
||||
'help' : 'Minimum allowable dial value, Enter None for no minimum'},
|
||||
'max' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'fNone' : 1,
|
||||
'help' : 'Maximum allowable dial value, Enter None for no maximum'},
|
||||
'base' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'help' : 'Dial value = base + delta * numRevs'},
|
||||
'delta' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'help' : 'Dial value = base + delta * numRevs'},
|
||||
'numSegments' : { 'widget' : self,
|
||||
'type' : 'integer',
|
||||
'help' : 'Number of segments to divide dial into'},
|
||||
'resetValue' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'help' : 'Enter value to set dial to on reset.'}
|
||||
}
|
||||
self.propertyList = ['min', 'max', 'base', 'delta',
|
||||
'resetValue', 'numSegments']
|
||||
|
||||
# The popup menu
|
||||
self._popupMenu = Menu(interior, tearoff = 0)
|
||||
self._fSnap = IntVar()
|
||||
@ -325,8 +341,11 @@ class DialWidget(Pmw.MegaWidget):
|
||||
self._popupMenu.add_checkbutton(label = 'Rollover',
|
||||
variable = self._fRollover,
|
||||
command = self.setRollover)
|
||||
self._popupMenu.add_command(label = 'Properties...',
|
||||
command = self.getProperties)
|
||||
self._popupMenu.add_command(
|
||||
label = 'Properties...',
|
||||
command = self.popupPropertiesDialog)
|
||||
self._popupMenu.add_command(label = 'Zero Dial',
|
||||
command = self.zero)
|
||||
self._popupMenu.add_command(label = 'Reset Dial',
|
||||
command = self.reset)
|
||||
|
||||
@ -375,6 +394,14 @@ class DialWidget(Pmw.MegaWidget):
|
||||
# Record value
|
||||
self.value = value
|
||||
|
||||
# Set floater to zero
|
||||
def zero(self):
|
||||
"""
|
||||
self.reset()
|
||||
Set dial to zero
|
||||
"""
|
||||
self.set(0.0)
|
||||
|
||||
# Reset dial to reset value
|
||||
def reset(self):
|
||||
"""
|
||||
@ -384,6 +411,7 @@ class DialWidget(Pmw.MegaWidget):
|
||||
self.set(self['resetValue'])
|
||||
|
||||
def mouseReset(self,event):
|
||||
# If not over any canvas item
|
||||
if not self._canvas.find_withtag(CURRENT):
|
||||
self.reset()
|
||||
|
||||
@ -465,7 +493,6 @@ class DialWidget(Pmw.MegaWidget):
|
||||
# Update value
|
||||
currT = globalClock.getFrameTime()
|
||||
dt = currT - state.lastTime
|
||||
#self.set(self.value + self['delta'] * self.knobSF * dt)
|
||||
self.set(self.value + self.knobSF * dt)
|
||||
state.lastTime = currT
|
||||
return Task.cont
|
||||
@ -548,24 +575,28 @@ class DialWidget(Pmw.MegaWidget):
|
||||
self['fRollover'] = self._fRollover.get()
|
||||
|
||||
# This handles the popup dial min dialog
|
||||
def getProperties(self):
|
||||
def popupPropertiesDialog(self):
|
||||
# Popup dialog to adjust widget properties
|
||||
WidgetPropertiesDialog(
|
||||
WidgetPropertiesDialog.WidgetPropertiesDialog(
|
||||
self.propertyDict,
|
||||
propertyList = self.propertyList,
|
||||
title = 'Dial Widget Properties',
|
||||
parent = self._canvas)
|
||||
|
||||
def addPropertyToDialog(self, property, pDict):
|
||||
self.propertyDict[property] = pDict
|
||||
self.propertyList.append(property)
|
||||
|
||||
# User callbacks
|
||||
def _onButtonPress(self, *args):
|
||||
""" User redefinable callback executed on button press """
|
||||
if self['onButtonPress']:
|
||||
apply(self['onButtonPress'], self['callbackData'])
|
||||
if self['preCallback']:
|
||||
apply(self['preCallback'], self['callbackData'])
|
||||
|
||||
def _onButtonRelease(self, *args):
|
||||
""" User redefinable callback executed on button release """
|
||||
if self['onButtonRelease']:
|
||||
apply(self['onButtonRelease'], self['callbackData'])
|
||||
if self['postCallback']:
|
||||
apply(self['postCallback'], self['callbackData'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -19,14 +19,16 @@ class EntryScale(Pmw.MegaWidget):
|
||||
|
||||
# Define the megawidget options.
|
||||
optiondefs = (
|
||||
('initialValue', 0.0, Pmw.INITOPT),
|
||||
('value', 0.0, Pmw.INITOPT),
|
||||
('resolution', 0.001, None),
|
||||
('command', None, None),
|
||||
('preCallback', None, None),
|
||||
('postCallback', None, None),
|
||||
('callbackData', [], None),
|
||||
('min', 0.0, self._updateValidate),
|
||||
('max', 100.0, self._updateValidate),
|
||||
('text', 'EntryScale', self._updateLabelText),
|
||||
('significantDigits', 2, self._setSigDigits),
|
||||
('numDigits', 2, self._setSigDigits),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
@ -34,7 +36,7 @@ class EntryScale(Pmw.MegaWidget):
|
||||
Pmw.MegaWidget.__init__(self, parent)
|
||||
|
||||
# Initialize some class variables
|
||||
self.value = self['initialValue']
|
||||
self.value = self['value']
|
||||
self.entryFormat = '%.2f'
|
||||
self.fScaleCommand = 0
|
||||
|
||||
@ -49,7 +51,7 @@ class EntryScale(Pmw.MegaWidget):
|
||||
Frame, interior)
|
||||
# Create an entry field to display and validate the entryScale's value
|
||||
self.entryValue = StringVar()
|
||||
self.entryValue.set(self['initialValue'])
|
||||
self.entryValue.set(self['value'])
|
||||
self.entry = self.createcomponent('entryField',
|
||||
# Access widget's entry using "entry"
|
||||
(('entry', 'entryField_entry'),),
|
||||
@ -105,7 +107,7 @@ class EntryScale(Pmw.MegaWidget):
|
||||
showvalue = 0)
|
||||
self.scale.pack(side = 'left', expand = 1, fill = 'x')
|
||||
# Set scale to the middle of its range
|
||||
self.scale.set(self['initialValue'])
|
||||
self.scale.set(self['value'])
|
||||
self.scale.bind('<Button-1>', self.__onPress)
|
||||
self.scale.bind('<ButtonRelease-1>', self.__onRelease)
|
||||
self.scale.bind('<Button-3>', self.askForResolution)
|
||||
@ -218,7 +220,7 @@ class EntryScale(Pmw.MegaWidget):
|
||||
pass
|
||||
|
||||
def _setSigDigits(self):
|
||||
sd = self['significantDigits']
|
||||
sd = self['numDigits']
|
||||
self.entryFormat = '%.' + '%d' % sd + 'f'
|
||||
# And reset value to reflect change
|
||||
self.entryValue.set( self.entryFormat % self.value )
|
||||
@ -260,7 +262,8 @@ class EntryScale(Pmw.MegaWidget):
|
||||
|
||||
def __onPress(self, event):
|
||||
# First execute onpress callback
|
||||
apply(self.onPress, self['callbackData'])
|
||||
if self['preCallback']:
|
||||
apply(self['preCallback'], self['callbackData'])
|
||||
# Now enable slider command
|
||||
self.fScaleCommand = 1
|
||||
|
||||
@ -272,7 +275,8 @@ class EntryScale(Pmw.MegaWidget):
|
||||
# Now disable slider command
|
||||
self.fScaleCommand = 0
|
||||
# First execute onpress callback
|
||||
apply(self.onRelease, self['callbackData'])
|
||||
if self['postCallback']:
|
||||
apply(self['postCallback'], self['callbackData'])
|
||||
|
||||
def onRelease(self, *args):
|
||||
""" User redefinable callback executed on button release """
|
||||
@ -295,9 +299,11 @@ class EntryScaleGroup(Pmw.MegaToplevel):
|
||||
('side', TOP, INITOPT),
|
||||
('title', 'Group', None),
|
||||
# A tuple of initial values, one for each entryScale
|
||||
('initialValue', DEFAULT_VALUE, INITOPT),
|
||||
('value', DEFAULT_VALUE, INITOPT),
|
||||
# The command to be executed any time one of the entryScales is updated
|
||||
('command', None, None),
|
||||
('preCallback', None, None),
|
||||
('postCallback', None, None),
|
||||
# A tuple of labels, one for each entryScale
|
||||
('labels', DEFAULT_LABELS, self._updateLabels),
|
||||
# Destroy or withdraw
|
||||
@ -311,7 +317,7 @@ class EntryScaleGroup(Pmw.MegaToplevel):
|
||||
# Create the components
|
||||
interior = self.interior()
|
||||
# Get a copy of the initial value (making sure its a list)
|
||||
self._value = list(self['initialValue'])
|
||||
self._value = list(self['value'])
|
||||
|
||||
# The Menu Bar
|
||||
self.balloon = Pmw.Balloon()
|
||||
@ -349,7 +355,7 @@ class EntryScaleGroup(Pmw.MegaToplevel):
|
||||
# fg.configure(Valuator_XXX = YYY)
|
||||
f = self.createcomponent(
|
||||
'entryScale%d' % index, (), 'Valuator', EntryScale,
|
||||
(interior,), initialValue = self._value[index],
|
||||
(interior,), value = 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._entryScaleSetAt(i, val)
|
||||
@ -357,13 +363,13 @@ class EntryScaleGroup(Pmw.MegaToplevel):
|
||||
# Callbacks
|
||||
f.onReturn = self.__onReturn
|
||||
f.onReturnRelease = self.__onReturnRelease
|
||||
f.onPress = self.__onPress
|
||||
f.onRelease = self.__onRelease
|
||||
f['preCallback'] = self.__onPress
|
||||
f['postCallback'] = self.__onRelease
|
||||
f.pack(side = self['side'], expand = 1, fill = X)
|
||||
self.entryScaleList.append(f)
|
||||
|
||||
# Make sure entryScales are initialized
|
||||
self.set(self['initialValue'])
|
||||
self.set(self['value'])
|
||||
|
||||
# Make sure input variables processed
|
||||
self.initialiseoptions(EntryScaleGroup)
|
||||
@ -405,7 +411,7 @@ class EntryScaleGroup(Pmw.MegaToplevel):
|
||||
self['command'](self._value)
|
||||
|
||||
def reset(self):
|
||||
self.set(self['initialValue'])
|
||||
self.set(self['value'])
|
||||
|
||||
def __onReturn(self, esg):
|
||||
# Execute onReturn callback
|
||||
@ -425,7 +431,8 @@ class EntryScaleGroup(Pmw.MegaToplevel):
|
||||
|
||||
def __onPress(self, esg):
|
||||
# Execute onPress callback
|
||||
apply(self.onPress, esg.get())
|
||||
if self['preCallback']:
|
||||
apply(self['preCallback'], esg.get())
|
||||
|
||||
def onPress(self, *args):
|
||||
""" User redefinable callback executed on button press """
|
||||
@ -433,7 +440,8 @@ class EntryScaleGroup(Pmw.MegaToplevel):
|
||||
|
||||
def __onRelease(self, esg):
|
||||
# Execute onRelease callback
|
||||
apply(self.onRelease, esg.get())
|
||||
if self['postCallback']:
|
||||
apply(self['postCallback'], esg.get())
|
||||
|
||||
def onRelease(self, *args):
|
||||
""" User redefinable callback executed on button release """
|
||||
@ -455,7 +463,7 @@ def rgbPanel(nodePath, callback = None):
|
||||
esg = EntryScaleGroup(title = 'RGBA Panel: ' + nodePath.getName(),
|
||||
dim = 4,
|
||||
labels = ['R','G','B','A'],
|
||||
initialValue = [int(initColor[0]),
|
||||
value = [int(initColor[0]),
|
||||
int(initColor[1]),
|
||||
int(initColor[2]),
|
||||
int(initColor[3])],
|
||||
@ -499,7 +507,7 @@ def rgbPanel(nodePath, callback = None):
|
||||
# Set callback
|
||||
def onRelease(r,g,b,a, nodePath = nodePath):
|
||||
messenger.send('RGBPanel_setColor', [nodePath, r,g,b,a])
|
||||
esg.onRelease = onRelease
|
||||
esg['postCallback'] = onRelease
|
||||
return esg
|
||||
|
||||
## SAMPLE CODE
|
||||
@ -519,7 +527,7 @@ if __name__ == '__main__':
|
||||
"""
|
||||
# These are things you can set/configure
|
||||
# Starting value for entryScale
|
||||
mega1['initialValue'] = 123.456
|
||||
mega1['value'] = 123.456
|
||||
mega1['text'] = 'Drive delta X'
|
||||
mega1['min'] = 0.0
|
||||
mega1['max'] = 1000.0
|
||||
@ -530,7 +538,7 @@ if __name__ == '__main__':
|
||||
# To have really fine control, for example
|
||||
# mega1['maxVelocity'] = 0.1
|
||||
# Number of digits to the right of the decimal point, default = 2
|
||||
# mega1['significantDigits'] = 5
|
||||
# mega1['numDigits'] = 5
|
||||
"""
|
||||
|
||||
# To create a entryScale group to set an RGBA value:
|
||||
|
@ -5,214 +5,431 @@ Floater Class: Velocity style controller for floating point values with
|
||||
from PandaObject import *
|
||||
from Tkinter import *
|
||||
import Pmw
|
||||
import WidgetPropertiesDialog
|
||||
import string
|
||||
|
||||
class Floater(Pmw.MegaWidget):
|
||||
"Velocity style floating point controller"
|
||||
|
||||
def __init__(self, parent = None, **kw):
|
||||
globalClock = ClockObject.getGlobalClock()
|
||||
|
||||
# Define the megawidget options.
|
||||
|
||||
FLOATER_FULL = 'full'
|
||||
FLOATER_MINI = 'mini'
|
||||
|
||||
FLOATER_WIDTH = 25
|
||||
FLOATER_HEIGHT = 20
|
||||
|
||||
class FloaterWidget(Pmw.MegaWidget):
|
||||
sfBase = 3.0
|
||||
sfDist = 15
|
||||
deadband = 10
|
||||
def __init__(self, parent = None, **kw):
|
||||
#define the megawidget options
|
||||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
('initialValue', 0.0, Pmw.INITOPT),
|
||||
('resolution', None, None),
|
||||
('command', None, None),
|
||||
('commandData', [], None),
|
||||
('callbackData', [], None),
|
||||
('maxVelocity', 10.0, None),
|
||||
('min', None, self._updateValidate),
|
||||
('max', None, self._updateValidate),
|
||||
('text', 'Floater', self._updateLabelText),
|
||||
('significantDigits', 2, self._setSigDigits),
|
||||
## Appearance
|
||||
# Edge size of the floater
|
||||
('width', FLOATER_WIDTH, INITOPT),
|
||||
('height', FLOATER_HEIGHT, INITOPT),
|
||||
# Color
|
||||
('background', 'white', INITOPT),
|
||||
# Widget relief
|
||||
('relief', SUNKEN, self.setRelief),
|
||||
# Widget borderwidth
|
||||
('borderwidth', 2, self.setBorderwidth),
|
||||
## Values
|
||||
# Initial value of floater, use self.set to change value
|
||||
('value', 0.0, INITOPT),
|
||||
('min', None, None),
|
||||
('max', None, None),
|
||||
('resolution', None, None),
|
||||
('numDigits', 2, self.setNumDigits),
|
||||
# Value floater jumps to on reset
|
||||
('resetValue', 0.0, None),
|
||||
## Behavior
|
||||
# Able to adjust max/min
|
||||
('fAdjustable', 1, None),
|
||||
# Command to execute on floater updates
|
||||
('command', None, None),
|
||||
# Extra data to be passed to command function
|
||||
('commandData', [], None),
|
||||
# Callback's to execute during mouse interaction
|
||||
('preCallback', None, None),
|
||||
('postCallback', None, None),
|
||||
# Extra data to be passed to callback function, needs to be a list
|
||||
('callbackData', [], None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialise superclass
|
||||
|
||||
#print 'FLOATER WIDGET', self['resetValue']
|
||||
|
||||
# Initialize the superclass
|
||||
Pmw.MegaWidget.__init__(self, parent)
|
||||
|
||||
# Initialize some class variables
|
||||
self.value = self['initialValue']
|
||||
self.velocity = 0.0
|
||||
self.entryFormat = '%.2f'
|
||||
# Set up some local and instance variables
|
||||
# Current value
|
||||
self.value = self['value']
|
||||
|
||||
# Create the components.
|
||||
|
||||
# Setup up container
|
||||
# Create the components
|
||||
interior = self.interior()
|
||||
interior.configure(relief = GROOVE, borderwidth = 2)
|
||||
|
||||
# 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
|
||||
self.label = self.createcomponent('label', (), None,
|
||||
Label, self.labelFrame,
|
||||
text = self['text'],
|
||||
width = 12,
|
||||
anchor = 'center',
|
||||
font = "Arial 10 bold")
|
||||
self.label.pack(side='left', expand = 1, fill = 'x')
|
||||
# The canvas
|
||||
width = self['width']
|
||||
height = self['height']
|
||||
self._canvas = self.createcomponent('canvas', (), None,
|
||||
Canvas, (interior,),
|
||||
width = self['width'],
|
||||
height = self['height'],
|
||||
background = self['background'],
|
||||
highlightthickness = 0,
|
||||
scrollregion = (-width/2.0,
|
||||
-height/2.0,
|
||||
width/2.0,
|
||||
height/2.0))
|
||||
self._canvas.pack(expand = 1, fill = BOTH)
|
||||
|
||||
# Now pack the frame
|
||||
self.labelFrame.pack(expand = 1, fill = 'both')
|
||||
# The floater icon
|
||||
self._canvas.create_polygon(-width/2.0, 0, -2.0, -height/2.0,
|
||||
-2.0, height/2.0,
|
||||
fill = '#A0A0A0',
|
||||
tags = ('floater',))
|
||||
self._canvas.create_polygon(width/2.0, 0, 2.0, height/2.0,
|
||||
2.0, -height/2.0,
|
||||
fill = '#A0A0A0',
|
||||
tags = ('floater',))
|
||||
|
||||
# Create the scale component.
|
||||
self.scale = self.createcomponent('scale', (), None,
|
||||
Scale, interior,
|
||||
command = self._scaleToVelocity,
|
||||
orient = 'horizontal',
|
||||
length = 150,
|
||||
from_ = -1.0,
|
||||
to = 1.0,
|
||||
resolution = 0.001,
|
||||
showvalue = 0)
|
||||
self.scale.pack(expand = 1, fill = 'x')
|
||||
# Set scale to the middle of its range
|
||||
self.scale.set(0.0)
|
||||
|
||||
# Add scale bindings: When interacting with mouse:
|
||||
self.scale.bind('<Button-1>', self._startFloaterTask)
|
||||
self.scale.bind('<ButtonRelease-1>', self._floaterReset)
|
||||
# In case you wish to interact using keys
|
||||
self.scale.bind('<KeyPress-Right>', self._floaterKeyCommand)
|
||||
self.scale.bind('<KeyRelease-Right>', self._floaterReset)
|
||||
self.scale.bind('<KeyPress-Left>', self._floaterKeyCommand)
|
||||
self.scale.bind('<KeyRelease-Left>', self._floaterReset)
|
||||
|
||||
# Check keywords and initialise options based on input values.
|
||||
self.initialiseoptions(Floater)
|
||||
# A Dictionary of dictionaries for the popup property dialog
|
||||
self.propertyDict = {
|
||||
'min' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'fNone' : 1,
|
||||
'help' : 'Minimum allowable floater value, Enter None for no minimum'},
|
||||
'max' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'fNone' : 1,
|
||||
'help' : 'Maximum allowable floater value, Enter None for no maximum'},
|
||||
'resetValue' : { 'widget' : self,
|
||||
'type' : 'real',
|
||||
'help' : 'Enter value to set floater to on reset.'}
|
||||
}
|
||||
self.propertyList = ['min', 'max', 'resetValue']
|
||||
|
||||
def label(self):
|
||||
return self.label
|
||||
def scale(self):
|
||||
return self.scale
|
||||
def entry(self):
|
||||
return self.entry
|
||||
|
||||
def _updateLabelText(self):
|
||||
self.label['text'] = self['text']
|
||||
# The popup menu
|
||||
self._popupMenu = Menu(interior, tearoff = 0)
|
||||
|
||||
def _updateValidate(self):
|
||||
self.configure(entryField_validate = {
|
||||
'validator' : 'real',
|
||||
'min' : self['min'],
|
||||
'max' : self['max'],
|
||||
'minstrict' : 0,
|
||||
'maxstrict' : 0})
|
||||
if self['fAdjustable']:
|
||||
self._popupMenu.add_command(
|
||||
label = 'Properties...',
|
||||
command = self.popupPropertiesDialog)
|
||||
self._popupMenu.add_command(label = 'Zero Floater',
|
||||
command = self.zero)
|
||||
self._popupMenu.add_command(label = 'Reset Floater',
|
||||
command = self.reset)
|
||||
|
||||
def _scaleToVelocity(self, strVal):
|
||||
# convert scale val to float
|
||||
val = string.atof(strVal)
|
||||
# Square val, but retain sign of velocity by only calling abs once
|
||||
self.velocity = self['maxVelocity'] * val * abs(val)
|
||||
# Add event bindings
|
||||
self._canvas.bind('<ButtonPress-1>', self.mouseDown)
|
||||
self._canvas.bind('<B1-Motion>', self.mouseMotion)
|
||||
self._canvas.bind('<ButtonRelease-1>', self.mouseUp)
|
||||
self._canvas.bind('<ButtonPress-3>', self.popupFloaterMenu)
|
||||
self._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
|
||||
self._canvas.bind('<ButtonPress-3>', self.popupFloaterMenu)
|
||||
self._canvas.bind('<Enter>', self.highlightIcon)
|
||||
self._canvas.bind('<Leave>', self.restoreIcon)
|
||||
self._canvas.tag_bind('floater', '<ButtonPress-1>', self.mouseDown)
|
||||
self._canvas.tag_bind('floater', '<B1-Motion>', self.mouseMotion)
|
||||
self._canvas.tag_bind('floater', '<ButtonRelease-1>', self.mouseUp)
|
||||
|
||||
def _startFloaterTask(self,event):
|
||||
self._fFloaterTask = 1
|
||||
apply(self.onPress,self['callbackData'])
|
||||
taskMgr.add(self._floaterTask, 'floaterTask')
|
||||
# Make sure input variables processed
|
||||
self.initialiseoptions(FloaterWidget)
|
||||
|
||||
def _floaterTask(self, state):
|
||||
if self.velocity != 0.0:
|
||||
self.set( self.value + self.velocity )
|
||||
return Task.cont
|
||||
|
||||
def _floaterReset(self, event):
|
||||
taskMgr.remove('floaterTask')
|
||||
self.velocity = 0.0
|
||||
self.scale.set(0.0)
|
||||
apply(self.onRelease, self['callbackData'])
|
||||
|
||||
def _floaterKeyCommand(self, event):
|
||||
if self.velocity != 0.0:
|
||||
self.set( self.value + self.velocity )
|
||||
|
||||
def _entryCommand(self, event = None):
|
||||
try:
|
||||
val = string.atof( self.entryValue.get() )
|
||||
apply(self.onReturn,self['callbackData'])
|
||||
self.set( val )
|
||||
apply(self.onReturnRelease,self['callbackData'])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def _setSigDigits(self):
|
||||
sd = self['significantDigits']
|
||||
self.entryFormat = '%.' + '%d' % sd + 'f'
|
||||
# And reset value to reflect change
|
||||
self.entryValue.set( self.entryFormat % self.value )
|
||||
|
||||
def get(self):
|
||||
return self.value
|
||||
|
||||
def set(self, newVal, fCommand = 1):
|
||||
def set(self, value, fCommand = 1):
|
||||
"""
|
||||
self.set(value, fCommand = 1)
|
||||
Set floater to new value, execute command if fCommand == 1
|
||||
"""
|
||||
# Clamp value
|
||||
if self['min'] is not None:
|
||||
if newVal < self['min']:
|
||||
newVal = self['min']
|
||||
if value < self['min']:
|
||||
value = self['min']
|
||||
if self['max'] is not None:
|
||||
if newVal > self['max']:
|
||||
newVal = self['max']
|
||||
if value > self['max']:
|
||||
value = self['max']
|
||||
# Round by resolution
|
||||
if self['resolution'] is not None:
|
||||
newVal = round(newVal / self['resolution']) * self['resolution']
|
||||
|
||||
# Update floater's value
|
||||
self.value = newVal
|
||||
# Update entry to reflect formatted value
|
||||
self.entryValue.set( self.entryFormat % self.value )
|
||||
self.entry.checkentry()
|
||||
|
||||
# execute command
|
||||
if fCommand and (self['command'] is not None):
|
||||
apply(self['command'], [newVal] + self['commandData'])
|
||||
value = round(value / self['resolution']) * self['resolution']
|
||||
|
||||
# Send command if any
|
||||
if fCommand and (self['command'] != None):
|
||||
apply(self['command'], [value] + self['commandData'])
|
||||
# Record value
|
||||
self.value = value
|
||||
|
||||
# Set floater to zero
|
||||
def zero(self):
|
||||
"""
|
||||
self.reset()
|
||||
Set floater to zero
|
||||
"""
|
||||
self.set(0.0)
|
||||
|
||||
# Reset floater to reset value
|
||||
def reset(self):
|
||||
self.set(self['initialValue'])
|
||||
"""
|
||||
self.reset()
|
||||
Reset floater to reset value
|
||||
"""
|
||||
self.set(self['resetValue'])
|
||||
|
||||
def disable(self):
|
||||
self.scale['state'] = 'disabled'
|
||||
self.label['state'] = 'disabled'
|
||||
self.component('entry')['state'] = 'disabled'
|
||||
def mouseReset(self,event):
|
||||
# If not over any canvas item
|
||||
#if not self._canvas.find_withtag(CURRENT):
|
||||
self.reset()
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
self.get()
|
||||
Get current floater value
|
||||
"""
|
||||
return self.value
|
||||
|
||||
def enable(self):
|
||||
self.scale['state'] = 'normal'
|
||||
self.label['state'] = 'normal'
|
||||
self.component('entry')['state'] = 'normal'
|
||||
## Canvas callback functions
|
||||
# Floater velocity controller
|
||||
def mouseDown(self,event):
|
||||
self._onButtonPress()
|
||||
self.velocitySF = 0.0
|
||||
t = taskMgr.add(self.computeVelocity, 'cv')
|
||||
t.lastTime = globalClock.getFrameTime()
|
||||
|
||||
def onReturn(self, *args):
|
||||
""" User redefinable callback executed on <Return> in entry """
|
||||
pass
|
||||
def computeVelocity(self, state):
|
||||
# Update value
|
||||
currT = globalClock.getFrameTime()
|
||||
dt = currT - state.lastTime
|
||||
self.set(self.value + self.velocitySF * dt)
|
||||
state.lastTime = currT
|
||||
return Task.cont
|
||||
|
||||
def onReturnRelease(self, *args):
|
||||
""" User redefinable callback executed on <Return> release in entry """
|
||||
pass
|
||||
def mouseMotion(self, event):
|
||||
# What is the current knob angle
|
||||
self.velocitySF = self.computeVelocitySF(event)
|
||||
|
||||
def onPress(self, *args):
|
||||
def computeVelocitySF(self, event):
|
||||
x = self._canvas.canvasx(event.x)
|
||||
y = self._canvas.canvasy(event.y)
|
||||
offset = max(0, abs(x) - FloaterWidget.deadband)
|
||||
if offset == 0:
|
||||
return 0
|
||||
sf = math.pow(FloaterWidget.sfBase,
|
||||
self.minExp + offset/FloaterWidget.sfDist)
|
||||
if x > 0:
|
||||
return sf
|
||||
else:
|
||||
return -sf
|
||||
|
||||
def mouseUp(self, event):
|
||||
taskMgr.remove('cv')
|
||||
self.velocitySF = 0.0
|
||||
self._onButtonRelease()
|
||||
|
||||
def highlightIcon(self, event):
|
||||
self._canvas.itemconfigure('floater', fill = 'black')
|
||||
|
||||
def restoreIcon(self, event):
|
||||
self._canvas.itemconfigure('floater', fill = '#A0A0A0')
|
||||
|
||||
# Methods to modify floater characteristics
|
||||
def setRelief(self):
|
||||
self.interior()['relief'] = self['relief']
|
||||
|
||||
def setBorderwidth(self):
|
||||
self.interior()['borderwidth'] = self['borderwidth']
|
||||
|
||||
def setNumDigits(self):
|
||||
# Set minimum exponent to use in velocity task
|
||||
self.minExp = math.floor(-self['numDigits']/
|
||||
math.log10(FloaterWidget.sfBase))
|
||||
|
||||
# The following methods are used to handle the popup menu
|
||||
def popupFloaterMenu(self,event):
|
||||
self._popupMenu.post(event.widget.winfo_pointerx(),
|
||||
event.widget.winfo_pointery())
|
||||
|
||||
# Popup dialog to adjust widget properties
|
||||
def popupPropertiesDialog(self):
|
||||
WidgetPropertiesDialog.WidgetPropertiesDialog(
|
||||
self.propertyDict,
|
||||
propertyList = self.propertyList,
|
||||
title = 'Floater Widget Properties',
|
||||
parent = self._canvas)
|
||||
|
||||
def addPropertyToDialog(self, property, pDict):
|
||||
self.propertyDict[property] = pDict
|
||||
self.propertyList.append(property)
|
||||
|
||||
# User callbacks
|
||||
def _onButtonPress(self, *args):
|
||||
""" User redefinable callback executed on button press """
|
||||
pass
|
||||
if self['preCallback']:
|
||||
apply(self['preCallback'], self['callbackData'])
|
||||
|
||||
def onRelease(self, *args):
|
||||
def _onButtonRelease(self, *args):
|
||||
""" User redefinable callback executed on button release """
|
||||
pass
|
||||
if self['postCallback']:
|
||||
apply(self['postCallback'], self['callbackData'])
|
||||
|
||||
|
||||
class Floater(Pmw.MegaWidget):
|
||||
def __init__(self, parent = None, **kw):
|
||||
#define the megawidget options
|
||||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
# Widget relief
|
||||
('relief', GROOVE, None),
|
||||
# Widget borderwidth
|
||||
('borderwidth', 2, None),
|
||||
('value', 0.0, INITOPT),
|
||||
('resetValue', 0.0, self.setResetValue),
|
||||
('text', 'Floater', self.setLabel),
|
||||
('numDigits', 2, self.setEntryFormat),
|
||||
('command', None, None),
|
||||
('commandData', [], None),
|
||||
('min', None, self.setMin),
|
||||
('max', None, self.setMax),
|
||||
# Callbacks to execute when updating widget's value
|
||||
('preCallback', None, self.setButtonPressCmd),
|
||||
('postCallback', None, self.setButtonReleaseCmd),
|
||||
# Extra data to be passed to callback function, needs to be a list
|
||||
('callbackData', [], self.setCallbackData),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize the superclass
|
||||
Pmw.MegaWidget.__init__(self, parent)
|
||||
|
||||
# Create the components
|
||||
interior = self.interior()
|
||||
interior.configure(relief = self['relief'], bd = self['borderwidth'])
|
||||
|
||||
# The Floater
|
||||
#print self['text'], self['value'], self['resetValue']
|
||||
self._floater = self.createcomponent('floater', (), None,
|
||||
FloaterWidget, (interior,),
|
||||
command = self.setEntry,
|
||||
resetValue = self['value'],
|
||||
value = self['value'])
|
||||
|
||||
if not kw.has_key('resetValue'):
|
||||
self['resetValue'] = self['value']
|
||||
self._floater.addPropertyToDialog(
|
||||
'text',
|
||||
{'widget' : self,
|
||||
'type' : 'string',
|
||||
'help' : 'Enter label text for Floater.'
|
||||
}
|
||||
)
|
||||
self._floater.addPropertyToDialog(
|
||||
'numDigits',
|
||||
{'widget' : self,
|
||||
'type' : 'integer',
|
||||
'help' : 'Enter number of digits after decimal point.'
|
||||
}
|
||||
)
|
||||
|
||||
# The Label
|
||||
self._label = self.createcomponent('label', (), None,
|
||||
Label, (interior,),
|
||||
text = self['text'],
|
||||
font = ('MS Sans Serif',12,'bold'),
|
||||
anchor = CENTER)
|
||||
self._label.bind('<ButtonPress-3>', self._floater.popupFloaterMenu)
|
||||
|
||||
# The entry
|
||||
self._entryVal = StringVar()
|
||||
self._entry = self.createcomponent('entry', (), None,
|
||||
Entry, (interior,),
|
||||
justify = RIGHT,
|
||||
width = 12,
|
||||
textvariable = self._entryVal)
|
||||
self._entry.bind('<Return>', self.validateEntryInput)
|
||||
self._entry.bind('<ButtonPress-3>', self._floater.popupFloaterMenu)
|
||||
self._entryBackground = self._entry.cget('background')
|
||||
|
||||
# Position components
|
||||
self._label.grid(row=0,col=0, sticky = EW)
|
||||
self._entry.grid(row=0,col=1, sticky = EW)
|
||||
self._floater.grid(row=0,col=2, padx = 2, pady = 2)
|
||||
interior.columnconfigure(0, weight = 1)
|
||||
|
||||
# Make sure input variables processed
|
||||
self.fInit = 0
|
||||
self.initialiseoptions(Floater)
|
||||
self.fInit = 1
|
||||
|
||||
def set(self, value, fCommand = 1):
|
||||
# Pass fCommand to user specified data (to control if command
|
||||
# is executed or not) to floater which will return it to self.setEntry
|
||||
self._floater['commandData'] = [fCommand]
|
||||
self._floater.set(value)
|
||||
# Restore commandData to 1 so that interaction via floater widget
|
||||
# will result in command being executed, otherwise a set with
|
||||
# commandData == 0 will stick and commands will not be executed
|
||||
self._floater['commandData'] = [1]
|
||||
|
||||
def get(self):
|
||||
return self._floater.get()
|
||||
|
||||
def setEntry(self, value, fCommand = 1):
|
||||
self._entryVal.set(self.entryFormat % value)
|
||||
# Execute command
|
||||
if self.fInit and fCommand and (self['command'] != None):
|
||||
apply(self['command'], [value] + self['commandData'])
|
||||
|
||||
def setEntryFormat(self):
|
||||
self.entryFormat = "%." + "%df" % self['numDigits']
|
||||
self.setEntry(self.get())
|
||||
self._floater['numDigits'] = self['numDigits']
|
||||
|
||||
def validateEntryInput(self, event):
|
||||
input = self._entryVal.get()
|
||||
try:
|
||||
self._onReturnPress()
|
||||
self._entry.configure(background = self._entryBackground)
|
||||
newValue = string.atof(input)
|
||||
self.set(newValue)
|
||||
self._onReturnRelease()
|
||||
except ValueError:
|
||||
self._entry.configure(background = 'Pink')
|
||||
|
||||
def _onReturnPress(self, *args):
|
||||
""" User redefinable callback executed on <Return> in entry """
|
||||
if self['preCallback']:
|
||||
apply(self['preCallback'], self['callbackData'])
|
||||
|
||||
def _onReturnRelease(self, *args):
|
||||
""" User redefinable callback executed on <Return> release in entry """
|
||||
if self['postCallback']:
|
||||
apply(self['postCallback'], self['callbackData'])
|
||||
|
||||
# Pass settings down to floater
|
||||
def setCallbackData(self):
|
||||
# Pass callback data down to floater
|
||||
self._floater['callbackData'] = self['callbackData']
|
||||
|
||||
def setResetValue(self):
|
||||
self._floater['resetValue'] = self['resetValue']
|
||||
|
||||
def setMin(self):
|
||||
self._floater['min'] = self['min']
|
||||
|
||||
def setMax(self):
|
||||
self._floater['max'] = self['max']
|
||||
|
||||
def setLabel(self):
|
||||
self._label['text'] = self['text']
|
||||
|
||||
def setButtonPressCmd(self):
|
||||
self._floater['preCallback'] = self['preCallback']
|
||||
|
||||
def setButtonReleaseCmd(self):
|
||||
self._floater['postCallback'] = self['postCallback']
|
||||
|
||||
|
||||
class FloaterGroup(Pmw.MegaToplevel):
|
||||
def __init__(self, parent = None, **kw):
|
||||
@ -231,7 +448,7 @@ class FloaterGroup(Pmw.MegaToplevel):
|
||||
('side', TOP, INITOPT),
|
||||
('title', 'Floater Group', None),
|
||||
# A tuple of initial values, one for each floater
|
||||
('initialValue', DEFAULT_VALUE, INITOPT),
|
||||
('value', 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
|
||||
@ -245,7 +462,7 @@ class FloaterGroup(Pmw.MegaToplevel):
|
||||
# Create the components
|
||||
interior = self.interior()
|
||||
# Get a copy of the initial value (making sure its a list)
|
||||
self._value = list(self['initialValue'])
|
||||
self._value = list(self['value'])
|
||||
|
||||
# The Menu Bar
|
||||
self.balloon = Pmw.Balloon()
|
||||
@ -279,7 +496,7 @@ class FloaterGroup(Pmw.MegaToplevel):
|
||||
# fg.configure(Valuator_XXX = YYY)
|
||||
f = self.createcomponent(
|
||||
'floater%d' % index, (), 'Valuator', Floater,
|
||||
(interior,), initialValue = self._value[index],
|
||||
(interior,), value = 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)
|
||||
@ -287,7 +504,7 @@ class FloaterGroup(Pmw.MegaToplevel):
|
||||
self.floaterList.append(f)
|
||||
|
||||
# Make sure floaters are initialized
|
||||
self.set(self['initialValue'])
|
||||
self.set(self['value'])
|
||||
|
||||
# Make sure input variables processed
|
||||
self.initialiseoptions(FloaterGroup)
|
||||
@ -329,9 +546,9 @@ class FloaterGroup(Pmw.MegaToplevel):
|
||||
self['command'](self._value)
|
||||
|
||||
def reset(self):
|
||||
self.set(self['initialValue'])
|
||||
|
||||
self.set(self['value'])
|
||||
|
||||
|
||||
## SAMPLE CODE
|
||||
if __name__ == '__main__':
|
||||
# Initialise Tkinter and Pmw.
|
||||
@ -349,7 +566,7 @@ if __name__ == '__main__':
|
||||
"""
|
||||
# These are things you can set/configure
|
||||
# Starting value for floater
|
||||
mega1['initialValue'] = 123.456
|
||||
mega1['value'] = 123.456
|
||||
mega1['text'] = 'Drive delta X'
|
||||
mega1['min'] = 0.0
|
||||
mega1['max'] = 1000.0
|
||||
@ -360,7 +577,7 @@ if __name__ == '__main__':
|
||||
# To have really fine control, for example
|
||||
# mega1['maxVelocity'] = 0.1
|
||||
# Number of digits to the right of the decimal point, default = 2
|
||||
# mega1['significantDigits'] = 5
|
||||
# mega1['numDigits'] = 5
|
||||
"""
|
||||
|
||||
# To create a floater group to set an RGBA value:
|
||||
|
@ -20,7 +20,7 @@ class VectorEntry(Pmw.MegaWidget):
|
||||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
('dim', DEFAULT_DIM, INITOPT),
|
||||
('initialValue', DEFAULT_VALUE, INITOPT),
|
||||
('value', DEFAULT_VALUE, INITOPT),
|
||||
('resetValue', DEFAULT_VALUE, None),
|
||||
('label_width', 12, None),
|
||||
('command', None, None),
|
||||
@ -30,7 +30,7 @@ class VectorEntry(Pmw.MegaWidget):
|
||||
('text', 'Vector:', self._updateText),
|
||||
('min', None, self._updateValidate),
|
||||
('max', None, self._updateValidate),
|
||||
('significantDigits', 2, self._setSigDigits),
|
||||
('numDigits', 2, self._setSigDigits),
|
||||
('valuatorType', VALUATOR, None),
|
||||
('state', 'normal', self._setState),
|
||||
)
|
||||
@ -41,8 +41,8 @@ class VectorEntry(Pmw.MegaWidget):
|
||||
|
||||
# Initialize value
|
||||
# Make sure its a list (and as a byproduct, make a distinct copy)
|
||||
self._value = list(self['initialValue'])
|
||||
self['resetValue'] = self['initialValue']
|
||||
self._value = list(self['value'])
|
||||
self['resetValue'] = self['value']
|
||||
self._floaters = None
|
||||
self.entryFormat = '%.2f'
|
||||
|
||||
@ -103,7 +103,7 @@ class VectorEntry(Pmw.MegaWidget):
|
||||
|
||||
|
||||
# Make sure entries are updated
|
||||
self.set(self['initialValue'])
|
||||
self.set(self['value'])
|
||||
|
||||
# Record entry color
|
||||
self.entryBackground = self.cget('Entry_entry_background')
|
||||
@ -142,9 +142,9 @@ class VectorEntry(Pmw.MegaWidget):
|
||||
self['Entry_entry_width'] = self['entryWidth']
|
||||
|
||||
def _setSigDigits(self):
|
||||
sd = self['significantDigits']
|
||||
sd = self['numDigits']
|
||||
self.entryFormat = '%.' + '%d' % sd + 'f'
|
||||
self.configure(Valuator_significantDigits = sd)
|
||||
self.configure(Valuator_numDigits = sd)
|
||||
# And refresh value to reflect change
|
||||
for index in range(self['dim']):
|
||||
self._refreshEntry(index)
|
||||
@ -232,8 +232,10 @@ class VectorEntry(Pmw.MegaWidget):
|
||||
self.configure(Entry_entry_state = 'disabled')
|
||||
self.configure(Entry_entry_background = '#C0C0C0')
|
||||
# Disable floater Group scale
|
||||
"""
|
||||
self.component('fGroup').configure(
|
||||
Valuator_scale_state = 'disabled')
|
||||
"""
|
||||
# Disable floater group entry
|
||||
self.component('fGroup').configure(
|
||||
Valuator_entry_state = 'disabled')
|
||||
@ -244,8 +246,10 @@ class VectorEntry(Pmw.MegaWidget):
|
||||
self.configure(Entry_entry_state = 'normal')
|
||||
self.configure(Entry_entry_background = self.entryBackground)
|
||||
# Disable floater Group scale
|
||||
"""
|
||||
self.component('fGroup').configure(
|
||||
Valuator_scale_state = 'normal')
|
||||
"""
|
||||
# Disable floater group entry
|
||||
self.component('fGroup').configure(
|
||||
Valuator_entry_state = 'normal')
|
||||
@ -302,7 +306,7 @@ class ColorEntry(VectorEntry):
|
||||
('fGroup_labels', ('R','G','B','A'), None),
|
||||
('min', 0.0, None),
|
||||
('max', 255.0, None),
|
||||
('significantDigits', 0, None),
|
||||
('nuDigits', 0, None),
|
||||
('Valuator_resolution', 1.0, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
@ -110,15 +110,17 @@ class WidgetPropertiesDialog(Toplevel):
|
||||
extra = ''
|
||||
# Set up help string and validator based upon type
|
||||
if entryType == 'real':
|
||||
# Only allow real numbers
|
||||
entry['validate'] = { 'validator' : self.realOrNone }
|
||||
if helpString is None:
|
||||
helpString = 'Enter a floating point number' + extra + '.'
|
||||
elif entryType == 'integer':
|
||||
# Only allow integer values
|
||||
entry['validate'] = { 'validator' : self.intOrNone }
|
||||
if helpString is None:
|
||||
helpString = 'Enter an integer' + extra + '.'
|
||||
else:
|
||||
entry['validate'] = { 'validator' : 'alphanumeric' }
|
||||
# Anything goes with a string widget
|
||||
if helpString is None:
|
||||
helpString = 'Enter a string' + extra + '.'
|
||||
# Bind balloon with help string to entry
|
||||
|
Loading…
x
Reference in New Issue
Block a user