diff --git a/direct/src/leveleditor/LevelEditor.py b/direct/src/leveleditor/LevelEditor.py index a251c18c39..e8579c8279 100644 --- a/direct/src/leveleditor/LevelEditor.py +++ b/direct/src/leveleditor/LevelEditor.py @@ -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) diff --git a/direct/src/tkpanels/DirectSessionPanel.py b/direct/src/tkpanels/DirectSessionPanel.py index 08eeb4bb84..99de95073c 100644 --- a/direct/src/tkpanels/DirectSessionPanel.py +++ b/direct/src/tkpanels/DirectSessionPanel.py @@ -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'] = ( diff --git a/direct/src/tkpanels/MopathRecorder.py b/direct/src/tkpanels/MopathRecorder.py index 20ec984ec4..d82fe5c1e5 100644 --- a/direct/src/tkpanels/MopathRecorder.py +++ b/direct/src/tkpanels/MopathRecorder.py @@ -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) diff --git a/direct/src/tkpanels/ParticlePanel.py b/direct/src/tkpanels/ParticlePanel.py index 2c806644e8..32c8d2c6e9 100644 --- a/direct/src/tkpanels/ParticlePanel.py +++ b/direct/src/tkpanels/ParticlePanel.py @@ -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) ###################################################################### diff --git a/direct/src/tkpanels/Placer.py b/direct/src/tkpanels/Placer.py index 41846a0434..803126907b 100644 --- a/direct/src/tkpanels/Placer.py +++ b/direct/src/tkpanels/Placer.py @@ -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']: diff --git a/direct/src/tkwidgets/AppShell.py b/direct/src/tkwidgets/AppShell.py index 91f40e41d1..3bd1fcdb73 100644 --- a/direct/src/tkwidgets/AppShell.py +++ b/direct/src/tkwidgets/AppShell.py @@ -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, diff --git a/direct/src/tkwidgets/Dial.py b/direct/src/tkwidgets/Dial.py index 93c2f9faae..4a554d3d10 100644 --- a/direct/src/tkwidgets/Dial.py +++ b/direct/src/tkwidgets/Dial.py @@ -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 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 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__': diff --git a/direct/src/tkwidgets/EntryScale.py b/direct/src/tkwidgets/EntryScale.py index aa469f2044..3dd6f908bb 100644 --- a/direct/src/tkwidgets/EntryScale.py +++ b/direct/src/tkwidgets/EntryScale.py @@ -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('', self.__onPress) self.scale.bind('', self.__onRelease) self.scale.bind('', 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: diff --git a/direct/src/tkwidgets/Floater.py b/direct/src/tkwidgets/Floater.py index c1eec7dbaa..079e09f09e 100644 --- a/direct/src/tkwidgets/Floater.py +++ b/direct/src/tkwidgets/Floater.py @@ -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('', self._startFloaterTask) - self.scale.bind('', self._floaterReset) - # In case you wish to interact using keys - self.scale.bind('', self._floaterKeyCommand) - self.scale.bind('', self._floaterReset) - self.scale.bind('', self._floaterKeyCommand) - self.scale.bind('', 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('', self.mouseDown) + self._canvas.bind('', self.mouseMotion) + self._canvas.bind('', self.mouseUp) + self._canvas.bind('', self.popupFloaterMenu) + self._canvas.bind('', self.mouseReset) + self._canvas.bind('', self.popupFloaterMenu) + self._canvas.bind('', self.highlightIcon) + self._canvas.bind('', self.restoreIcon) + self._canvas.tag_bind('floater', '', self.mouseDown) + self._canvas.tag_bind('floater', '', self.mouseMotion) + self._canvas.tag_bind('floater', '', 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 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 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('', 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('', self.validateEntryInput) + self._entry.bind('', 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 in entry """ + if self['preCallback']: + apply(self['preCallback'], self['callbackData']) + + def _onReturnRelease(self, *args): + """ User redefinable callback executed on 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: diff --git a/direct/src/tkwidgets/VectorWidgets.py b/direct/src/tkwidgets/VectorWidgets.py index 962e8e01c5..886ffd2c16 100644 --- a/direct/src/tkwidgets/VectorWidgets.py +++ b/direct/src/tkwidgets/VectorWidgets.py @@ -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) diff --git a/direct/src/tkwidgets/WidgetPropertiesDialog.py b/direct/src/tkwidgets/WidgetPropertiesDialog.py index 9b1413f50c..f897fa46b2 100644 --- a/direct/src/tkwidgets/WidgetPropertiesDialog.py +++ b/direct/src/tkwidgets/WidgetPropertiesDialog.py @@ -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