*** empty log message ***

This commit is contained in:
Mark Mine 2000-10-17 18:14:09 +00:00
parent 0067eb1d46
commit f16d63d6ea
12 changed files with 168 additions and 2645 deletions

View File

@ -7,5 +7,6 @@ MODREL PYTHONPATH src/ffi
MODREL PYTHONPATH src/actor
MODREL PYTHONPATH src/distributed
MODREL PYTHONPATH src/showbase
MODREL PYTHONPATH src/directutil
MODREL PYTHONPATH src/tkwidgets
MODREL PYTHONPATH src/tkpanels

View File

@ -0,0 +1,103 @@
from PandaObject import *
class DisplayRegionContext(PandaObject):
def __init__(self, win, camera):
self.win = win
self.camera = camera
self.cam = camera.getChild(0)
self.camNode = self.cam.getNode(0)
self.mouseData = win.getMouseData(0)
self.mouseX = 0.0
self.mouseY = 0.0
#self.spawnContextTask()
def __getitem__(self,key):
return self.__dict__[key]
def spawnContextTask(self):
# First kill the existing task
#taskMgr.removeTasksNamed('DIRECTContextTask')
taskMgr.spawnTaskNamed(Task.Task(self.contextTask),
'DIRECTContextTask')
def contextTask(self, state):
# Window Data
self.width = self.win.getWidth()
self.height = self.win.getHeight()
self.near = self.camNode.getNear()
self.far = self.camNode.getFar()
self.fovH = self.camNode.getHfov()
self.fovV = self.camNode.getVfov()
self.nearWidth = math.tan(deg2Rad(self.fovH / 2.0)) * self.near * 2.0
self.nearHeight = math.tan(deg2Rad(self.fovV / 2.0)) * self.near * 2.0
# Mouse Data
# Last frame
self.mouseLastX = self.mouseX
self.mouseLastY = self.mouseY
# This frame
self.mousePixelX = self.mouseData.getX()
self.mousePixelY = self.mouseData.getY()
self.mouseX = ((self.mousePixelX / float(self.width)) * 2.0) - 1.0
self.mouseY = ((self.mousePixelY / float(self.height)) * -2.0) + 1.0
self.mouseDeltaX = self.mouseX - self.mouseLastX
self.mouseDeltaY = self.mouseY - self.mouseLastY
print self.mouseX, self.mouseY
# Continue the task
return Task.cont
class DirectSession(PandaObject):
def __init__(self):
self.contextList = []
self.contextList.append(DisplayRegionContext(self.win, self.camera))
# Initialize the collection of selected nodePaths
self.selectedNodePaths = {}
self.lastSelected = None
self.bboxList = []
self.fControl = 0
self.fAlt = 0
self.fShift = 0
""""
def createBBox(self):
bbox = hidden.attachNewNode(NamedNode())
bbox.setName('bbox')
bboxLines = GridLine new: bbox.
bboxLines color: (VBase4 new: 1.0 y: 0.0 z: 0.0 w: 1.0).
bboxLines thickness: 0.5.
"Bottom face"
bboxLines moveTo: 0.0 y: 0.0 z: 0.0.
bboxLines drawTo: 1.0 y: 0.0 z: 0.0.
bboxLines drawTo: 1.0 y: 1.0 z: 0.0.
bboxLines drawTo: 0.0 y: 1.0 z: 0.0.
bboxLines drawTo: 0.0 y: 0.0 z: 0.0.
"Front Edge/Top face"
bboxLines drawTo: 0.0 y: 0.0 z: 1.0.
bboxLines drawTo: 1.0 y: 0.0 z: 1.0.
bboxLines drawTo: 1.0 y: 1.0 z: 1.0.
bboxLines drawTo: 0.0 y: 1.0 z: 1.0.
bboxLines drawTo: 0.0 y: 0.0 z: 1.0.
"Three remaining edges"
bboxLines moveTo: 1.0 y: 0.0 z: 0.0.
bboxLines drawTo: 1.0 y: 0.0 z: 1.0.
bboxLines moveTo: 1.0 y: 1.0 z: 0.0.
bboxLines drawTo: 1.0 y: 1.0 z: 1.0.
bboxLines moveTo: 0.0 y: 1.0 z: 0.0.
bboxLines drawTo: 0.0 y: 1.0 z: 1.0.
bboxLines create: bboxLines lineNode.! !
"""
class Line(LineSegs):
def __init__(self):
LineSegs.__init__(self)

View File

@ -1,3 +1,5 @@
import types
import re
def ifAbsentPut(dict, key, newValue):
"""
@ -19,4 +21,63 @@ def indent(stream, numIndents, str):
indentString = ' '
stream.write(indentString * numIndents + str)
def apropos(obj, str = None, fOverloaded = 0, width = None,
fTruncate = 1, lineWidth = 75):
if type(obj) == types.InstanceType:
print "***************************INSTANCE INFO*****************************"
dict = obj.__dict__
if width:
maxWidth = width
else:
maxWidth = 10
keyWidth = 0
aproposKeys = []
privateKeys = []
overloadedKeys = []
remainingKeys = []
for key in dict.keys():
if not width:
keyWidth = len(key)
if str:
if re.search(str, key, re.I):
aproposKeys.append(key)
if (not width) & (keyWidth > maxWidth):
maxWidth = keyWidth
else:
if key[:2] == '__':
privateKeys.append(key)
if (not width) & (keyWidth > maxWidth):
maxWidth = keyWidth
elif (key[:10] == 'overloaded'):
if fOverloaded:
overloadedKeys.append(key)
if (not width) & (keyWidth > maxWidth):
maxWidth = keyWidth
else:
remainingKeys.append(key)
if (not width) & (keyWidth > maxWidth):
maxWidth = keyWidth
# Sort appropriate keys
if str:
aproposKeys.sort()
else:
privateKeys.sort()
remainingKeys.sort()
overloadedKeys.sort()
# Print out results
keys = aproposKeys + privateKeys + remainingKeys + overloadedKeys
format = '%-' + `maxWidth` + 's'
for key in keys:
value = `dict[key]`
if fTruncate:
# Cut off line (keeping at least 1 char)
value = value[:max(1,lineWidth - maxWidth)]
print (format % key)[:maxWidth] + '\t' + value
if type(obj) == types.InstanceType:
print "*****************************CLASS INFO******************************"
apropos(obj.__class__, str = str )
def aproposAll(obj):
apropos(obj, fOverloaded = 1, fTruncate = 0)

View File

@ -5,6 +5,7 @@ from MessengerGlobal import *
from TaskManagerGlobal import *
from EventManagerGlobal import *
from AudioManagerGlobal import *
from PythonUtil import *
import Task
import EventManager

View File

@ -1,8 +1,8 @@
"""instantiate global ShowBase object"""
import ShowBase
from ShowBase import *
base = ShowBase.ShowBase()
base = ShowBase()
# Make some global aliases for convenience
render2d = base.render2d
@ -10,7 +10,5 @@ render = base.render
hidden = base.hidden
camera = base.camera
loader = base.loader
messenger = base.messenger
taskMgr = base.taskMgr
run = base.run
tkroot = base.tkroot

View File

@ -1,345 +0,0 @@
"DIRECT Animation Control Panel"
# Import Tkinter, Pmw, and the floater code from this directory tree.
from Tkinter import *
from tkSimpleDialog import askfloat
import Pmw
import string
import math
FRAMES = 0
SECONDS = 1
class AnimPanel(Pmw.MegaToplevel):
def __init__(self, parent = None, **kw):
INITOPT = Pmw.INITOPT
optiondefs = (
('title', 'Anim Panel', None),
('actorList', (), None),
('Actor_label_width', 12, None),
)
self.defineoptions(kw, optiondefs)
# Initialize the superclass
Pmw.MegaToplevel.__init__(self, parent)
# Handle to the toplevels hull
hull = self.component('hull')
# A handy little help balloon
balloon = self.balloon = Pmw.Balloon()
# Start with balloon help disabled
self.balloon.configure(state = 'none')
menuFrame = Frame(hull, relief = GROOVE, bd = 2)
menuBar = Pmw.MenuBar(menuFrame, hotkeys = 1, balloon = balloon)
menuBar.pack(side = LEFT, expand = 1, fill = X)
menuBar.addmenu('AnimPanel', 'Anim Panel Operations')
# Actor control status
menuBar.addcascademenu('AnimPanel', 'Control Status',
'Enable/disable actor control panels')
menuBar.addmenuitem('Control Status', 'command',
'Enable all actor controls',
label = 'Enable all',
command = self.enableActorControls)
menuBar.addmenuitem('Control Status', 'command',
'Disable all actor controls',
label = 'Disable all',
command = self.disableActorControls)
# Frame Slider units
menuBar.addcascademenu('AnimPanel', 'Display Units',
'Select display units')
menuBar.addmenuitem('Display Units', 'command',
'Display frame counts', label = 'Frame count',
command = self.displayFrameCounts)
menuBar.addmenuitem('Display Units', 'command',
'Display seconds', label = 'Seconds',
command = self.displaySeconds)
# Reset all actor controls
menuBar.addmenuitem('AnimPanel', 'command',
'Reset Actor controls',
label = 'Reset all',
command = self.resetAll)
# Exit panel
menuBar.addmenuitem('AnimPanel', 'command',
'Exit Anim Panel',
label = 'Exit',
command = self.destroy)
menuBar.addmenu('Help', 'Anim Panel Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menuBar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
menuFrame.pack(fill = X)
# Create a frame to hold all the actor controls
actorFrame = Frame(hull)
# Create a control for each actor
index = 0
self.actorControlList = []
for actor in self['actorList']:
ac = self.createcomponent(
'actorControl%d' % index, (), 'Actor',
ActorControl, (actorFrame,))
ac.pack(expand = 1, fill = X)
self.actorControlList.append(ac)
index = index + 1
# Now pack the actor frame
actorFrame.pack(expand = 1, fill = BOTH)
# Create a frame to hold the playback controls
controlFrame = Frame(hull)
self.playPauseVar = IntVar()
self.playPauseVar.set(0)
self.playPauseButton = self.createcomponent(
'playPause', (), None,
Checkbutton, (controlFrame,),
text = 'Play', width = 8,
variable = self.playPauseVar,
indicatoron = FALSE)
self.playPauseButton.pack(side = LEFT, expand = 1, fill = X)
self.resetButton = self.createcomponent(
'reset', (), None,
Button, (controlFrame,),
text = 'Reset All',
width = 8,
command = self.resetAll)
self.resetButton.pack(side = LEFT, expand = 1, fill = X)
self.loopVar = IntVar()
self.loopVar.set(0)
self.loopButton = self.createcomponent(
'loopButton', (), None,
Checkbutton, (controlFrame,),
text = 'Loop', width = 8,
variable = self.loopVar)
self.loopButton.pack(side = LEFT, expand = 1, fill = X)
controlFrame.pack(fill = X)
# Execute option callbacks
self.initialiseoptions(AnimPanel)
def getActorControlAt(self, index):
return self.actorControlList[index]
def enableActorControlAt(self,index):
self.getActorControlAt(index).enableControl()
def enableActorControls(self):
for actorControl in self.actorControlList:
actorControl.enableControl()
def disableActorControls(self):
for actorControl in self.actorControlList:
actorControl.disableControl()
def disableActorControlAt(self,index):
self.getActorControlAt(index).disableControl()
def displayFrameCounts(self):
for actorControl in self.actorControlList:
actorControl.displayFrameCounts()
def displaySeconds(self):
for actorControl in self.actorControlList:
actorControl.displaySeconds()
def resetAll(self):
for actorControl in self.actorControlList:
actorControl.reset()
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
class ActorControl(Pmw.MegaWidget):
def __init__(self, parent = None, **kw):
INITOPT = Pmw.INITOPT
DEFAULT_FONT = (('MS', 'Sans', 'Serif'), 12, 'bold')
DEFAULT_ANIMS = ('neutral', 'run', 'walk')
optiondefs = (
('text', 'Actor', self._updateLabelText),
('actor', None, None),
('animList', DEFAULT_ANIMS, None),
('sLabel_width', 5, None),
('sLabel_font', DEFAULT_FONT, None),
)
self.defineoptions(kw, optiondefs)
self.addoptions(
(('active', self['animList'][0], None),)
)
# Initialize the superclass
Pmw.MegaWidget.__init__(self, parent)
# Handle to the toplevels hull
interior = self.interior()
interior.configure(relief = RAISED, bd = 2)
# Instance variables
self.offset = 0.0
self.fps = 24.0
self.maxFrame = 120
self.maxSeconds = self.maxFrame / self.fps
# Create component widgets
self._label = self.createcomponent(
'label', (), None,
Menubutton, (interior,),
font=('MSSansSerif', 14, 'bold'),
relief = RAISED, bd = 1,
activebackground = '#909090',
text = self['text'])
# Top level menu
labelMenu = Menu(self._label, tearoff = 0 )
# Menu to select display mode
self.unitsVar = IntVar()
self.unitsVar.set(FRAMES)
displayMenu = Menu(labelMenu, tearoff = 0 )
displayMenu.add_radiobutton(label = 'Frame count',
value = FRAMES,
variable = self.unitsVar,
command = self.updateDisplay)
displayMenu.add_radiobutton(label = 'Seconds',
value = SECONDS,
variable = self.unitsVar,
command = self.updateDisplay)
# Items for top level menu
labelMenu.add_cascade(label = 'Display Units', menu = displayMenu)
labelMenu.add_command(label = 'Set Offset', command = self.setOffset)
labelMenu.add_command(label = 'Reset', command = self.reset)
# Now associate menu with menubutton
self._label['menu'] = labelMenu
self._label.pack(side = LEFT, fill = X)
# Combo box to select current animation
animMenu = self.createcomponent(
'animMenu', (), None,
Pmw.ComboBox, (interior,),
labelpos = W, label_text = 'Anim:',
entry_width = 12, selectioncommand = self.selectAnimNamed,
scrolledlist_items = self['animList'])
animMenu.selectitem(self['active'])
animMenu.pack(side = 'left', padx = 5, expand = 0)
# Combo box to select frame rate
fpsList = (1,2,4,8,12,15,24,30)
fpsMenu = self.createcomponent(
'fpsMenu', (), None,
Pmw.ComboBox, (interior,),
labelpos = W, label_text = 'at:',
entry_width = 4, selectioncommand = self.setFrameRate,
scrolledlist_items = fpsList)
fpsMenu.selectitem('24')
fpsMenu.pack(side = LEFT, padx = 5, expand = 0)
# A label
fpsLabel = Label(interior, text = "fps")
fpsLabel.pack(side = LEFT)
# Scale to control animation
frameFrame = Frame(interior, relief = SUNKEN, bd = 1)
self.minLabel = self.createcomponent(
'minLabel', (), 'sLabel',
Label, (frameFrame,),
text = 0)
self.minLabel.pack(side = LEFT)
self.frameControl = self.createcomponent(
'scale', (), None,
Scale, (frameFrame,),
from_ = 0.0, to = self.maxFrame, resolution = 1.0,
orient = HORIZONTAL, showvalue = 1)
self.frameControl.pack(side = LEFT, expand = 1)
self.maxLabel = self.createcomponent(
'maxLabel', (), 'sLabel',
Label, (frameFrame,),
text = self.maxFrame)
self.maxLabel.pack(side = LEFT)
frameFrame.pack(side = LEFT, expand = 1, fill = X)
# Checkbutton to enable/disable control
self.frameActiveVar = IntVar()
self.frameActiveVar.set(1)
frameActive = self.createcomponent(
'checkbutton', (), None,
Checkbutton, (interior,),
variable = self.frameActiveVar)
frameActive.pack(side = LEFT, expand = 1)
# Execute option callbacks
self.initialiseoptions(ActorControl)
def _updateLabelText(self):
self._label['text'] = self['text']
def updateDisplay(self):
# Switch between showing frame counts and seconds
if self.unitsVar.get() == FRAMES:
newMin = int(math.floor(self.offset * self.fps))
newMax = int(math.ceil(self.offset * self.fps)) + self.maxFrame
self.minLabel['text'] = newMin
self.maxLabel['text'] = newMax
self.frameControl.configure(to = newMax, resolution = 1.0)
else:
newMin = self.offset
newMax = self.offset + self.maxSeconds
self.minLabel['text'] = "%.1f" % newMin
self.maxLabel['text'] = "%.1f" % newMax
print newMin, newMax
self.frameControl.configure(to = newMax, resolution = 0.1)
def selectAnimNamed(self, name):
print 'Selected Anim: ' + name
def setFrameRate(self, rate):
self.fps = string.atof(rate)
self.maxSeconds = self.maxFrame / self.fps
self.updateDisplay()
def setOffset(self):
newOffset = askfloat(title = self['text'],
prompt = 'Start offset (seconds):')
if newOffset:
self.offset = newOffset
self.updateDisplay()
def enableControl(self):
self.frameActiveVar.set(1)
def disableControl(self):
self.frameActiveVar.set(0)
def displayFrameCounts(self):
self.unitsVar.set(FRAMES)
self.updateDisplay()
def displaySeconds(self):
self.unitsVar.set(SECONDS)
self.updateDisplay()
def reset(self):
self.offset = 0.0
self.frameControl.set(0.0)
self.updateDisplay()
######################################################################
# Create demo in root window for testing.
if __name__ == '__main__':
widget = AnimPanel(actorList = (1,2,3))

View File

@ -1,469 +0,0 @@
from Tkinter import *
from tkSimpleDialog import askstring
import Pmw
import math
import operator
DELTA = (5.0 / 360.) * 2.0 * math.pi
class FSMInspector(Pmw.MegaToplevel):
def __init__(self, parent = None, **kw):
# Initialize instance variables
self.stateInspectorDict = {}
#define the megawidget options
INITOPT = Pmw.INITOPT
optiondefs = (
('title', 'FSM Viewer', None),
('currentFSM', (), None),
('gridSize', '0.25i', self._setGridSize),
)
self.defineoptions(kw, optiondefs)
# Initialize the toplevel widget
Pmw.MegaToplevel.__init__(self, parent)
# Create the components
oldInterior = Pmw.MegaToplevel.interior(self)
# The Menu Bar
balloon = self.balloon = Pmw.Balloon()
# Start with balloon help disabled
balloon.configure(state = 'none')
menubar = self._menubar = self.createcomponent('menubar',
(), None,
Pmw.MenuBar, (oldInterior,),
balloon = balloon)
menubar.pack(fill=X)
# FSM Menu
menubar.addmenu('FSM', 'FSM Operations')
menubar.addmenuitem('FSM', 'command',
'Input grid spacing',
label = 'Grid spacing...',
command = self.popupGridDialog)
# Create the checkbutton variable
self._fGridSnap = IntVar()
self._fGridSnap.set(1)
menubar.addmenuitem('FSM', 'checkbutton',
'Enable/disable grid',
label = 'Snap to grid',
variable = self._fGridSnap,
command = self.toggleGridSnap)
menubar.addmenuitem('FSM', 'command',
'Print out FSM layout',
label = 'Print FSM layout',
command = self.printLayout)
menubar.addmenuitem('FSM', 'command',
'Exit the FSM Inspector',
label = 'Exit',
command = self._exit)
# States Menu
menubar.addmenu('States', 'State Inspector Operations')
menubar.addcascademenu('States', 'Font Size',
'Set state label size', tearoff = 1)
for size in (8, 10, 12, 14, 18, 24):
menubar.addmenuitem('Font Size', 'command',
'Set font to: ' + `size` + ' Pts', label = `size` + ' Pts',
command = lambda s = self, sz = size: s.setFontSize(sz))
menubar.addcascademenu('States', 'Marker Size',
'Set state marker size', tearoff = 1)
for size in ('Small', 'Medium', 'Large'):
sizeDict = {'Small': '0.25i', 'Medium': '0.375i', 'Large' : '0.5i'}
menubar.addmenuitem('Marker Size', 'command',
size + ' markers', label = size + ' Markers',
command = lambda s = self, sz = size, d = sizeDict:
s.setMarkerSize(d[sz]))
# The Help menu
menubar.addmenu('Help', 'FSM Panel Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menubar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
# The Scrolled Canvas
self._scrolledCanvas = self.createcomponent('scrolledCanvas',
(), None,
Pmw.ScrolledCanvas, (oldInterior,),
hull_width = 400, hull_height = 400,
usehullsize = 1)
self._canvas = self._scrolledCanvas.component('canvas')
self._canvas['scrollregion'] = ('-2i', '-2i', '2i', '2i')
self._scrolledCanvas.resizescrollregion()
self._scrolledCanvas.pack(padx = 5, pady = 5, expand=1, fill = BOTH)
"""
# The Buttons
buttonBox = Frame(oldInterior)
#Button(buttonBox, text = 'Inspect Target').pack(side=LEFT,expand=1,fill=X)
Button(buttonBox, text = 'Print Layout',
command = self.printLayout).pack(side=LEFT,expand=1,fill=X)
Button(buttonBox, text = 'Quit',
command = self._exit).pack(side=LEFT,expand=1,fill=X)
buttonBox.pack(fill=X)
"""
# Update lines
self._canvas.bind('<B1-Motion>', self.drawConnections)
self._canvas.bind('<ButtonPress-2>', self.mouse2Down)
self._canvas.bind('<B2-Motion>', self.mouse2Motion)
self._canvas.bind('<Configure>',
lambda e, sc = self._scrolledCanvas:
sc.resizescrollregion())
self.createStateInspectors()
self.initialiseoptions(FSMInspector)
def scrolledCanvas(self):
return self._scrolledCanvas
def canvas(self):
return self._canvas
def setFontSize(self, size):
self._canvas.itemconfigure('labels', font = ('MS Sans Serif', size))
def setMarkerSize(self, size):
for key in self.stateInspectorDict.keys():
self.stateInspectorDict[key].setRadius(size)
self.drawConnections()
def drawConnections(self, event = None):
# Get rid of existing arrows
self._canvas.delete('arrow')
for key in self.stateInspectorDict.keys():
si = self.stateInspectorDict[key]
state = si.state
if state.transitionArray:
for name in state.transitionArray:
self.connectStates(si, self.getStateInspector(name))
def connectStates(self, fromState, toState):
endpts = self.computeEndpoints(fromState, toState)
line = self._canvas.create_line(endpts, tags = ('arrow',),
arrow = 'last')
def computeEndpoints(self, fromState, toState):
# Compute angle between two points
fromCenter = fromState.center()
toCenter = toState.center()
angle = self.findAngle(fromCenter, toCenter)
# Compute offset fromState point
newFromPt = map(operator.__add__,
fromCenter,
self.computePoint( fromState.radius,
angle + DELTA))
# Compute offset toState point
newToPt = map(operator.__sub__,
toCenter,
self.computePoint( toState.radius,
angle - DELTA))
return newFromPt + newToPt
def computePoint(self, radius, angle):
x = radius * math.cos(angle)
y = radius * math.sin(angle)
return (x, y)
def findAngle(self, fromPoint, toPoint):
dx = toPoint[0] - fromPoint[0]
dy = toPoint[1] - fromPoint[1]
return math.atan2(dy, dx)
def mouse2Down(self, event):
self._width = 1.0 * self._canvas.winfo_width()
self._height = 1.0 * self._canvas.winfo_height()
xview = self._canvas.xview()
yview = self._canvas.yview()
self._left = xview[0]
self._top = yview[0]
self._dxview = xview[1] - xview[0]
self._dyview = yview[1] - yview[0]
self._2lx = event.x
self._2ly = event.y
def mouse2Motion(self,event):
newx = self._left - ((event.x - self._2lx)/self._width) * self._dxview
self._canvas.xview_moveto(newx)
newy = self._top - ((event.y - self._2ly)/self._height) * self._dyview
self._canvas.yview_moveto(newy)
self._2lx = event.x
self._2ly = event.y
self._left = self._canvas.xview()[0]
self._top = self._canvas.yview()[0]
def createStateInspectors(self):
fsm = self['currentFSM']
# Number of rows/cols needed to fit inspectors in a grid
dim = int(math.ceil(math.sqrt(len(fsm))))
# Separation between nodes
spacing = 2.5 * self._canvas.canvasx('0.375i')
count = 0
for state in self['currentFSM']:
si = self.addState(state)
if state.defaultPosition:
si.setPos(state.defaultPosition[0], state.defaultPosition[1])
else:
row = int(math.floor(count / dim))
col = count % dim
si.setPos(col * spacing, row * spacing +
0.5 * (0, spacing)[col % 2])
count = count + 1
self.drawConnections()
def getStateInspector(self, name):
return self.stateInspectorDict.get(name, None)
def addState(self, state):
si = self.stateInspectorDict[state.name] = StateInspector(self, state)
return si
def enteredState(self, stateName):
si = self.stateInspectorDict.get(stateName,None)
if si:
si.enteredState()
def exitedState(self, stateName):
si = self.stateInspectorDict.get(stateName,None)
if si:
si.exitedState()
def _setGridSize(self):
self._gridSize = self['gridSize']
self.setGridSize(self._gridSize)
def setGridSize(self, size):
for key in self.stateInspectorDict.keys():
self.stateInspectorDict[key].setGridSize(size)
def popupGridDialog(self):
spacing = askstring('FSM Grid Spacing', 'Grid Spacing:')
if spacing:
self.setGridSize(spacing)
self._gridSize = spacing
def toggleGridSnap(self):
if self._fGridSnap.get():
self.setGridSize(self._gridSize)
else:
self.setGridSize(0)
def printLayout(self):
dict = self.stateInspectorDict
keys = dict.keys()
keys.sort
print '{ '
for key in keys[:-1]:
si = dict[key]
center = si.center()
print "'%s' : (%.3f, %.3f)," % \
(si.state.name, center[0], center[1])
for key in keys[-1:]:
si = dict[key]
center = si.center()
print "'%s' : (%.3f, %.3f)," % \
(si.state.name, center[0], center[1])
print '}'
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
def _exit(self):
self.destroy()
class StateInspector(Pmw.MegaArchetype):
def __init__(self, inspector, state, **kw):
# Record state
self.state = state
# Create a unique tag which you can use to move a marker and
# and its corresponding text around together
self.tag = state.name
# Pointers to the inspector's components
self.scrolledCanvas = inspector.component('scrolledCanvas')
self._canvas = self.scrolledCanvas.component('canvas')
#define the megawidget options
optiondefs = (
('radius', '0.375i', self._setRadius),
('gridSize', '0.25i', self._setGridSize),
)
self.defineoptions(kw, optiondefs)
# Initialize the parent class
Pmw.MegaArchetype.__init__(self)
# Draw the oval
self.x = 0
self.y = 0
half = self._canvas.winfo_fpixels(self['radius'])
self.marker = self._canvas.create_oval((self.x - half),
(self.y - half),
(self.x + half),
(self.y + half),
fill = 'CornflowerBlue',
tags = (self.tag,'markers'))
self.text = self._canvas.create_text(0, 0, text = state.name,
justify = CENTER,
tags = (self.tag,'labels'))
# Is this state contain a sub machine?
if state.fsmArray:
# reduce half by sqrt of 2.0
half = half * 0.707106
self.rect = self._canvas.create_rectangle((- half), (- half),
half, half,
tags = (self.tag,))
# The Popup State Menu
self._popupMenu = Menu(self._canvas, tearoff = 0)
self._popupMenu.add_command(label = 'Request transistion to ' +
state.name,
command = self.transitionTo)
if state.fsmArray:
self._popupMenu.add_command(label = 'Inspect ' + state.name +
' submachine',
command = self.inspectSubMachine)
self.scrolledCanvas.resizescrollregion()
# Add bindings
self._canvas.tag_bind(self.tag, '<Enter>', self.mouseEnter)
self._canvas.tag_bind(self.tag, '<Leave>', self.mouseLeave)
self._canvas.tag_bind(self.tag, '<ButtonPress-1>', self.mouseDown)
self._canvas.tag_bind(self.tag, '<B1-Motion>', self.mouseMotion)
self._canvas.tag_bind(self.tag, '<ButtonRelease-1>', self.mouseRelease)
self._canvas.tag_bind(self.tag, '<ButtonPress-3>', self.popupStateMenu)
self.initialiseoptions(StateInspector)
# Utility methods
def _setRadius(self):
self.setRadius(self['radius'])
def setRadius(self, size):
half = self.radius = self._canvas.winfo_fpixels(size)
c = self.center()
self._canvas.coords(self.marker,
c[0] - half, c[1] - half, c[0] + half, c[1] + half)
if self.state.fsmArray:
half = self.radius * 0.707106
self._canvas.coords(self.rect,
c[0] - half, c[1] - half, c[0] + half, c[1] + half)
def _setGridSize(self):
self.setGridSize(self['gridSize'])
def setGridSize(self, size):
self.gridSize = self._canvas.winfo_fpixels(size)
if self.gridSize == 0:
self.fGridSnap = 0
else:
self.fGridSnap = 1
def setText(self, text = None):
self._canvas.itemconfigure(self.text, text = text)
def setPos(self, x, y, snapToGrid = 0):
if self.fGridSnap:
self.x = round(x / self.gridSize) * self.gridSize
self.y = round(y / self.gridSize) * self.gridSize
else:
self.x = x
self.y = y
# How far do we have to move?
cx, cy = self.center()
self._canvas.move(self.tag, self.x - cx, self.y - cy)
def center(self):
c = self._canvas.coords(self.marker)
return (c[0] + c[2])/2.0, (c[1] + c[3])/2.0
# Event Handlers
def mouseEnter(self, event):
self._canvas.itemconfig(self.marker, width = 2)
def mouseLeave(self, event):
self._canvas.itemconfig(self.marker, width = 1)
def mouseDown(self, event):
self._canvas.lift(self.tag)
self.startx, self.starty = self.center()
self.lastx = self._canvas.canvasx(event.x)
self.lasty = self._canvas.canvasy(event.y)
def mouseMotion(self, event):
dx = self._canvas.canvasx(event.x) - self.lastx
dy = self._canvas.canvasy(event.y) - self.lasty
newx, newy = map(operator.__add__,(self.startx, self.starty), (dx, dy))
self.setPos(newx, newy)
def mouseRelease(self,event):
self.scrolledCanvas.resizescrollregion()
def popupStateMenu(self, event):
self._popupMenu.post(event.widget.winfo_pointerx(),
event.widget.winfo_pointery())
def transitionTo(self):
print 'transition to ' + self.tag
def inspectSubMachine(self):
print 'inspect ' + self.tag + ' subMachine'
def enteredState(self):
self._canvas.itemconfigure(self.marker, fill = 'Red')
def exitedState(self):
self._canvas.itemconfigure(self.marker, fill = 'CornflowerBlue')
class dummyState:
def __init__(self, name = None, transitionArray = None, fsmArray = 0):
self.name = name
self.transitionArray = transitionArray
self.fsmArray = fsmArray
self.defaultPosition = None
def hasChildFSMs(self):
return fsmArray
class dummyFSM:
def __init__(self, stateCollection = (), layout = {}):
self.stateCollection = stateCollection
if layout:
for state in self.stateCollection:
pos = layout.get(state.name, None)
if pos:
state.defaultPosition= pos
def __getitem__(self, item):
return self.stateCollection[item]
def __len__(self):
return len(self.stateCollection)
if __name__ == '__main__':
s0 = dummyState('state-0', ('state-1',))
s1 = dummyState('state-1', ('state-2', 'state-3'))
s2 = dummyState('state-2', ('state-0', 'state-4', 'state-5'), fsmArray = 1)
s3 = dummyState('state-3', ('state-6',))
s4 = dummyState('state-4', ('state-2','state-0'))
s5 = dummyState('state-5', ('state-0',), fsmArray = 1)
s6 = dummyState('state-6', ('state-3', 'state-0'))
fsm = dummyFSM((s0, s1, s2, s3, s4, s5, s6),
layout = {'state-0' : (167.83, 0.0),
'state-1' : (95.91, 143.86),
'state-2' : (167.83, 287.72),
'state-3' : (23.98, 263.74),
'state-4' : (335.67, 143.86),
'state-5' : (239.76, 143.86),
'state-6' : (23.98, 71.93)})
fsmi = FSMInspector(title = 'My Little Viewer', currentFSM = fsm)
mainloop()

View File

@ -1,350 +0,0 @@
"PANDA3D Particle Panel"
# Import Tkinter, Pmw, and the floater code from this directory tree.
from Tkinter import *
import Pmw
import dial
import floater
import vectorWidgets
class ParticlePanel(Pmw.MegaToplevel):
def __init__(self, parent = None, **kw):
INITOPT = Pmw.INITOPT
optiondefs = (
('title', 'Particle Panel', None),
)
self.defineoptions(kw, optiondefs)
Pmw.MegaToplevel.__init__(self, parent, title = self['title'])
# Handle to the toplevels hull
hull = self.component('hull')
balloon = self.balloon = Pmw.Balloon(hull)
# Start with balloon help disabled
self.balloon.configure(state = 'none')
menuFrame = Frame(hull, relief = GROOVE, bd = 2)
menuFrame.pack(fill = X, expand = 1)
menuBar = Pmw.MenuBar(menuFrame, hotkeys = 1, balloon = balloon)
menuBar.pack(side = LEFT, expand = 1, fill = X)
menuBar.addmenu('Particles', 'Particle Panel Operations')
menuBar.addmenuitem('Particles', 'command',
'Exit Particles Panel',
label = 'Exit',
command = self.destroy)
menuBar.addmenu('Help', 'Particle Panel Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menuBar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
self.systemSelector = Pmw.ComboBox(menuFrame,
labelpos = W,
label_text = 'Particle System:',
entry_width = 16,
selectioncommand = self.selectSystemNamed,
scrolledlist_items = ('system 0',))
self.systemSelector.selectitem('system 0')
self.systemSelector.pack(side = 'left', expand = 0)
# Create the notebook pages
notebook = Pmw.NoteBook(hull)
notebook.pack(fill = BOTH, expand = 1)
systemPage = notebook.add('System')
factoryPage = notebook.add('Factory')
emitterPage = notebook.add('Emitter')
rendererPage = notebook.add('Renderer')
# System page
systemWidgets = (
('Pool size', 'Size of particle pool', 0.0, 1.0),
('Birth rate', 'Seconds between particle births', 0.0, None),
('Litter size', 'Number of particle created at each birth', 1.0, 1.0),
('Litter spread', 'Variation in litter size', 0.0, 1.0),
('System lifespan', 'Age in seconds at which system should die', 0.0, None)
)
self.createFloaters(systemPage, systemWidgets)
Checkbutton(systemPage, text = 'Local velocity',anchor = W).pack(
fill = X)
Checkbutton(systemPage, text = 'System grows older',anchor = W).pack(
fill = X)
pos = self.createVector3Entry(systemPage, 'Pos',
'Particle system position')
pos.addMenuItem('Popup 3DoF Panel')
hpr = self.createVector3Entry(systemPage, 'Hpr',
'Particle system orientation',
floaterGroup_labels = ('H', 'P', 'R'))
hpr.addMenuItem('Popup 3DoF Panel')
# FACTORY PAGE
self.createOptionMenu(factoryPage, 'Factory type:',
'Select type of particle factory',
('Point', 'Z Spin', 'Oriented'),
self.selectFactoryType)
factoryWidgets = (
('Life span', 'Average lifespan in seconds', 0.0, None),
('Life span spread', 'Variation in lifespan', 0.0, None),
('Mass', 'Average particle mass', 0.0, None),
('Mass spread', 'Variation in particle mass', 0.0, None),
('Terminal velocity', 'Average particle terminal velocity', 0.0, None),
('Terminal vel. spread', 'Variation in terminal velocity', 0.0, None))
self.createFloaters(factoryPage, factoryWidgets)
self.factoryNotebook = Pmw.NoteBook(factoryPage, tabpos = None)
pointPage = self.factoryNotebook.add('Point')
zSpinPage = self.factoryNotebook.add('Z Spin')
self.createAngleDial(zSpinPage, 'Initial angle',
'Starting angle in degrees')
self.createAngleDial(zSpinPage, 'Final angle',
'Final angle in degrees')
self.createAngleDial(zSpinPage, 'Angle spread',
'Spread of the final angle')
orientedPage = self.factoryNotebook.add('Oriented')
Label(orientedPage, text = 'Not implemented').pack(expand = 1,
fill = BOTH)
self.factoryNotebook.pack(expand = 1, fill = BOTH)
# EMITTER PAGE
self.createOptionMenu(emitterPage, 'Emitter type:',
'Select type of particle emitter',
('Box', 'Disc', 'Line', 'Point', 'Rectangle',
'Ring', 'Sphere Surface', 'Sphere Volume',
'Tangent Ring'),
self.selectEmitterType)
self.emitterNotebook = Pmw.NoteBook(emitterPage, tabpos = None)
pointPage = self.emitterNotebook.add('Box')
self.createVector3Entry(pointPage, 'Point 1',
'Point defining emitter box')
self.createVector3Entry(pointPage, 'Point 2',
'Point defining emitter box',
initialValue = (1.0, 1.0, 1.0))
self.createVector3Entry(pointPage, 'Launch vector',
'Initial particle velocity vector')
discPage = self.emitterNotebook.add('Disc')
self.createFloater(discPage, 'Radius', 'Radius of disc')
self.createAngleDial(discPage, 'Inner angle',
'Particle launch angle at center of disc')
self.createFloater(discPage, 'Inner magnitude',
'Launch velocity multiplier at center of disc')
self.createAngleDial(discPage, 'Outer angle',
'Particle launch angle at outer edge of disc')
self.createFloater(discPage, 'Outer magnitude',
'Launch velocity multiplier at edge of disc')
Checkbutton(discPage, text = 'Cubic Lerping').pack(
side = LEFT, expand = 1, fill = X)
linePage = self.emitterNotebook.add('Line')
self.createVector3Entry(linePage, 'Point 1',
'Point defining emitter line')
self.createVector3Entry(linePage, 'Point 2',
'Point defining emitter line',
initialValue = (1.0, 0.0, 0.0))
self.createVector3Entry(linePage, 'Launch Vector',
'Initial particle velocity vector',
initialValue = (0.0, 0.0, 1.0))
pointPage = self.emitterNotebook.add('Point')
self.createVector3Entry(pointPage, 'Location',
'Location of emitter point')
self.createVector3Entry(pointPage, 'Launch vector',
'Initial particle velocity vector',
initialValue = (0.0, 0.0, 1.0))
rectanglePage = self.emitterNotebook.add('Rectangle')
self.createVector3Entry(rectanglePage, 'Point 1',
'Point defining rectangle')
self.createVector3Entry(rectanglePage, 'Point 2',
'Point defining rectangle')
self.createVector3Entry(rectanglePage, 'Launch vector',
'Initial particle velocity vector',
initialValue = (0.0, 0.0, 1.0))
ringPage = self.emitterNotebook.add('Ring')
self.createFloater(ringPage, 'Radius', 'Radius of ring')
self.createAngleDial(ringPage, 'Angle', 'Particle launch angle')
self.createFloater(ringPage, 'Magnitude',
'Launch velocity multiplier at outer edge of ring')
sphereSurfacePage = self.emitterNotebook.add('Sphere Surface')
self.createFloater(sphereSurfacePage, 'Radius',
'Radius of sphere')
sphereVolumePage = self.emitterNotebook.add('Sphere Volume')
self.createFloater(sphereVolumePage, 'Radius',
'Radius of sphere')
tangentRingPage = self.emitterNotebook.add('Tangent Ring')
self.createFloater(tangentRingPage, 'Radius',
'Radius of ring')
self.emitterNotebook.pack(fill = X)
# RENDERER PAGE
self.createOptionMenu(rendererPage, 'Renderer type:',
'Select type of particle renderer',
('Geom', 'Point', 'Sparkle', 'Sprite'),
self.selectRendererType)
self.rendererNotebook = Pmw.NoteBook(rendererPage, tabpos = None)
geomPage = self.rendererNotebook.add('Geom')
f = Frame(geomPage)
f.pack(fill = X)
Label(f, width = 12, text = 'Geom node:').pack(side = LEFT)
Entry(f, width = 12).pack(side = LEFT, expand = 1, fill = X)
pointPage = self.rendererNotebook.add('Point')
self.createFloater(pointPage, 'Point size',
'Width and height of points in pixels')
self.createColorEntry(pointPage, 'Start color',
'Starting color of point')
self.createColorEntry(pointPage, 'End color',
'Ending color of point')
self.createOptionMenu(pointPage, 'Blend type:',
'Type of color blending used for particle',
('ONE_COLOR', 'BLEND_LIFE', 'BLEND_VEL'),
self.selectBlendType)
self.createOptionMenu(pointPage, 'Blend method:',
'Interpolation method between colors',
('LINEAR', 'CUBIC'),
self.selectBlendMethod)
sparklePage = self.rendererNotebook.add('Sparkle')
self.createColorEntry(sparklePage, 'Center color',
'Color of sparkle center')
self.createColorEntry(sparklePage, 'Edge color',
'Color of sparkle line endpoints')
self.createFloater(sparklePage, 'Birth radius',
'Initial sparkle radius')
self.createFloater(sparklePage, 'Death radius',
'Final sparkle radius')
self.createOptionMenu(pointPage, 'Life scale:',
'Does particle scale over its lifetime?',
('NO_SCALE', 'SCALE'),
self.selectBlendMethod)
spritePage = self.rendererNotebook.add('Sprite')
f = Frame(spritePage)
f.pack(fill = X)
Label(f, width = 12, text = 'Texture:').pack(side = LEFT)
Entry(f, width = 12).pack(side = LEFT, expand = 1, fill = X)
Checkbutton(spritePage, text = 'xScale',anchor = W).pack(fill = X)
Checkbutton(spritePage, text = 'yScale',anchor = W).pack(fill = X)
Checkbutton(spritePage, text = 'animAngle',anchor = W).pack(fill = X)
self.createFloater(spritePage, 'Initial X Scale',
'Initial X scaling factor')
self.createFloater(spritePage, 'Final X Scale',
'Final X scaling factor')
self.createFloater(spritePage, 'Initial Y Scale',
'Initial Y scaling factor')
self.createFloater(spritePage, 'Final Y Scale',
'Final Y scaling factor')
self.createAngleDial(spritePage, 'Non Animated Theta',
'Counter clockwise Z rotation of all sprites')
self.createOptionMenu(spritePage, 'Blend Type',
'Interpolation blend type for X and Y scaling',
('LINEAR', 'CUBIC'),
self.selectBlendMethod)
Checkbutton(spritePage, text = 'alphaDisable',anchor = W).pack(fill = X)
self.rendererNotebook.pack(fill = X)
self.factoryNotebook.setnaturalsize()
self.emitterNotebook.setnaturalsize()
self.rendererNotebook.setnaturalsize()
notebook.setnaturalsize()
# Make sure input variables processed
self.initialiseoptions(ParticlePanel)
def createFloaters(self, parent, widgetDefinitions):
for label, balloonHelp, min, resolution in widgetDefinitions:
self.createFloater(parent, label, balloonHelp, min, resolution)
def createFloater(self, parent, text, balloonHelp,
min = 0.0, resolution = None, **kw):
kw['text'] = text
kw['min'] = min
kw['initialValue'] = min
kw['resolution'] = resolution
widget = apply(floater.Floater, (parent,), kw)
widget.pack(fill = X)
self.balloon.bind(widget, balloonHelp)
return widget
def createAngleDial(self, parent, text, balloonHelp, **kw):
kw['text'] = text
widget = apply(dial.AngleDial,(parent,), kw)
widget.pack(fill = X)
self.balloon.bind(widget, balloonHelp)
return widget
def createVector3Entry(self, parent, text, balloonHelp, **kw):
# Set label's text
kw['text'] = text
widget = apply(vectorWidgets.Vector3Entry, (parent,), kw)
widget.pack(fill = X)
self.balloon.bind(widget, balloonHelp)
return widget
def createColorEntry(self, parent, text, balloonHelp, **kw):
# Set label's text
kw['text'] = text
widget = apply(vectorWidgets.ColorEntry, (parent,) ,kw)
widget.pack(fill = X)
self.balloon.bind(widget, balloonHelp)
return widget
def createOptionMenu(self, parent, text, balloonHelp, items, command):
optionVar = StringVar()
optionVar.set(items[0])
widget = Pmw.OptionMenu(parent, labelpos = W, label_text = text,
label_width = 12, menu_tearoff = 1,
menubutton_textvariable = optionVar,
items = items,
command = command)
widget.pack(fill = X)
self.balloon.bind(widget.component('menubutton'), balloonHelp)
return optionVar
def selectFactoryType(self, type):
self.factoryNotebook.selectpage(type)
def selectEmitterType(self, type):
self.emitterNotebook.selectpage(type)
def selectRendererType(self, type):
self.rendererNotebook.selectpage(type)
def selectBlendType(self, type):
print type
def selectBlendMethod(self, method):
print method
def selectSystemNamed(self, name):
print name
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
######################################################################
# Create demo in root window for testing.
if __name__ == '__main__':
root = Pmw.initialise()
pp = ParticlePanel()
#ve = VectorEntry(Toplevel(), relief = GROOVE)
#ve.pack()

View File

@ -1,389 +0,0 @@
"DIRECT Nine DoF Placer demonstration"
# Import Tkinter, Pmw, and the floater code from this directory tree.
from Tkinter import *
import Pmw
import floater
import dial
class Placer(Pmw.MegaToplevel):
def __init__(self, parent = None, **kw):
INITOPT = Pmw.INITOPT
optiondefs = (
('title', 'Placer Panel', None),
('nodePath', None, None),
)
self.defineoptions(kw, optiondefs)
# Initialize the superclass
Pmw.MegaToplevel.__init__(self, parent)
# Handle to the toplevels hull
hull = self.component('hull')
menuFrame = Frame(hull, relief = GROOVE, bd = 2)
menuFrame.pack(fill = X, expand = 1)
balloon = self.balloon = Pmw.Balloon()
# Start with balloon help disabled
self.balloon.configure(state = 'none')
menuBar = Pmw.MenuBar(menuFrame, hotkeys = 1, balloon = balloon)
menuBar.pack(side = LEFT, expand = 1, fill = X)
menuBar.addmenu('Placer', 'Placer Panel Operations')
menuBar.addcascademenu('Placer', 'Axis',
'Control axis visibility',
tearoff = 1)
self.axisViz = StringVar()
self.axisViz.set('Show Axis')
menuBar.component('Axis-menu').add_radiobutton(
label = 'Show Axis',
variable = self.axisViz,
value = 'Show Axis',
command = lambda s = self: s._updateAxisViz())
menuBar.component('Axis-menu').add_radiobutton(
label = 'Hide Axis',
variable = self.axisViz,
value = 'Hide Axis',
command = lambda s = self: s._updateAxisViz())
menuBar.component('Axis-menu').add_radiobutton(
label = 'Auto Axis',
variable = self.axisViz,
value = 'Auto Axis',
command = lambda s = self: s._updateAxisViz())
menuBar.addmenuitem('Placer', 'command',
'Exit Placer Panel',
label = 'Exit',
command = self.destroy)
menuBar.addmenu('NodePath', 'Node Path Operations')
menuBar.addmenuitem('NodePath', 'command',
'Undo Pos/Hpr/Scale',
label = 'Undo All',
command = self._undoAll)
menuBar.addmenuitem('NodePath', 'command',
'Redo Pos/Hpr/Scale',
label = 'Redo All',
command = self._redoAll)
menuBar.addmenuitem('NodePath', 'command',
'Reset Node Path',
label = 'Reset All',
command = self._resetAll)
menuBar.addmenuitem('NodePath', 'command',
'Print Node Path Info',
label = 'Print Info',
command = self.printNodePathInfo)
menuBar.addmenu('Help', 'Placer Panel Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menuBar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
nodePathMenu = Pmw.ComboBox(menuFrame,
labelpos = W,
label_text = 'Node Path:',
entry_width = 12,
selectioncommand = self.selectNodePathNamed,
scrolledlist_items = ('selected',
'hot point',
'camera'))
nodePathMenu.selectitem('selected')
nodePathMenu.pack(side = 'left', expand = 0)
mode = StringVar()
mode.set('Drive')
modeMenu = Pmw.OptionMenu(menuFrame,
menubutton_textvariable=mode,
items = ('Drive', 'Orbit',
'Absolute', 'Relative'),
command = self._updateFloaterLabels,
menubutton_width = 8)
modeMenu.pack(side = 'left', expand = 0)
self.wrtMenu = Pmw.ComboBox(menuFrame,
labelpos = W,
label_text = 'WRT:',
entry_width = 12,
selectioncommand = self.selectNodePathNamed,
scrolledlist_items = ('render',
'selected',
'camera'))
self.wrtMenu.selectitem('render')
self.wrtMenu.pack(side = 'left', expand = 0)
# The master frame for the dials
dialFrame = Frame(hull)
dialFrame.pack(fill = 'both', expand = 1)
# Create and pack the Pos Controls
posGroup = Pmw.Group(dialFrame,
tag_pyclass = Menubutton,
tag_text = 'Position',
tag_font=('MSSansSerif', 14, 'bold'),
tag_activebackground = '#909090',
ring_relief = 'raised')
posMenubutton = posGroup.component('tag')
posMenu = Menu(posMenubutton)
posMenu.add_command(label = 'Undo', command = self._undoPos)
posMenu.add_command(label = 'Redo', command = self._redoPos)
posMenu.add_command(label = 'Set to zero', command = self._zeroPos)
posMenu.add_command(label = 'Restore initial', command = self._resetPos)
posMenubutton['menu'] = posMenu
posGroup.pack(side='left',fill = 'both', expand = 1)
posInterior = posGroup.interior()
# Create the floaters
self.posX = self.createcomponent('posX', (), None,
dial.Dial, (posInterior,),
text = 'X',
label_foreground = 'Red')
self.posX['command'] = self.printCommand
self.posX.pack(expand=1,fill='x')
self.posY = self.createcomponent('posY', (), None,
dial.Dial, (posInterior,),
text = 'Y',
label_foreground = '#00A000')
self.posY['command'] = self.printCommand
self.posY.pack(expand=1,fill='x')
self.posZ = self.createcomponent('posZ', (), None,
dial.Dial, (posInterior,),
text = 'Z',
label_foreground = 'Blue')
self.posZ['command'] = self.printCommand
self.posZ.pack(expand=1,fill='x')
# Create and pack the Hpr Controls
hprGroup = Pmw.Group(dialFrame,
tag_pyclass = Menubutton,
tag_text = 'Orientation',
tag_font=('MSSansSerif', 14, 'bold'),
tag_activebackground = '#909090',
ring_relief = 'raised')
hprMenubutton = hprGroup.component('tag')
hprMenu = Menu(hprMenubutton)
hprMenu.add_command(label = 'Undo', command = self._undoHpr)
hprMenu.add_command(label = 'Redo', command = self._redoHpr)
hprMenu.add_command(label = 'Set to zero', command = self._zeroHpr)
hprMenu.add_command(label = 'Restore initial', command = self._resetHpr)
hprMenubutton['menu'] = hprMenu
hprGroup.pack(side='left',fill = 'both', expand = 1)
hprInterior = hprGroup.interior()
# Create the floaters
self.hprH = self.createcomponent('hprH', (), None,
dial.Dial, (hprInterior,),
text = 'H', fRollover = 0,
max = 360.0, numTicks = 12,
label_foreground = 'blue')
self.hprH['command'] = self.printCommand
self.hprH.pack(expand=1,fill='x')
self.hprP = self.createcomponent('hprP', (), None,
dial.Dial, (hprInterior,),
text = 'P', fRollover = 0,
max = 360.0, numTicks = 12,
label_foreground = 'red')
self.hprP['command'] = self.printCommand
self.hprP.pack(expand=1,fill='x')
self.hprR = self.createcomponent('hprR', (), None,
dial.Dial, (hprInterior,),
text = 'R', fRollover = 0,
max = 360.0, numTicks = 12,
label_foreground = '#00A000')
self.hprR['command'] = self.printCommand
self.hprR.pack(expand=1,fill='x')
# Create and pack the Scale Controls
scaleGroup = Pmw.Group(dialFrame,
tag_text = 'Scale',
tag_pyclass = Menubutton,
tag_font=('MSSansSerif', 14, 'bold'),
tag_activebackground = '#909090',
ring_relief = 'raised')
scaleMenubutton = scaleGroup.component('tag')
scaleMenu = Menu(scaleMenubutton)
scaleModeMenu = Menu(scaleMenu)
# The available scaling modes
self.scalingMode = StringVar()
self.scalingMode.set('Free')
scaleModeMenu.add_radiobutton(label = 'Free',
variable = self.scalingMode)
scaleModeMenu.add_radiobutton(label = 'Uniform',
variable = self.scalingMode)
scaleModeMenu.add_radiobutton(label = 'Proportional',
variable = self.scalingMode)
# First level scaling menu
scaleMenu.add_command(label = 'Undo', command = self._undoScale)
scaleMenu.add_command(label = 'Redo', command = self._redoScale)
scaleMenu.add_command(label = 'Set to unity',
command = self._unitScale)
scaleMenu.add_command(label = 'Restore initial',
command = self._resetScale)
scaleMenu.add_cascade(label = 'Scaling mode...',
menu = scaleModeMenu)
scaleMenubutton['menu'] = scaleMenu
scaleGroup.pack(side='left',fill = 'both', expand = 1)
scaleInterior = scaleGroup.interior()
# Create the floaters
self.scaleX = self.createcomponent('scaleX', (), None,
dial.Dial, (scaleInterior,),
text = 'X Scale',
initialValue = 1.0,
label_foreground = 'Red')
self.scaleX['command'] = self.printCommand
self.scaleX.pack(expand=1,fill='x')
self.scaleY = self.createcomponent('scaleY', (), None,
dial.Dial, (scaleInterior,),
text = 'Y Scale',
initialValue = 1.0,
label_foreground = '#00A000')
self.scaleY['command'] = self.printCommand
self.scaleY.pack(expand=1,fill='x')
self.scaleZ = self.createcomponent('scaleZ', (), None,
dial.Dial, (scaleInterior,),
text = 'Z Scale',
initialValue = 1.0,
label_foreground = 'Blue')
self.scaleZ['command'] = self.printCommand
self.scaleZ.pack(expand=1,fill='x')
# Make sure appropriate labels are showing
self._updateFloaterLabels('Drive')
# Make sure input variables processed
self.initialiseoptions(Placer)
def printCommand(self, val):
print 'Current value: %s' % val
def selectNodePathNamed(self, name):
print 'Selected Node Path: ' + name
def printNodePathInfo(self):
print 'Print Node Path info here'
def _updateAxisViz(self):
self.updateAxisViz(self.axisViz.get())
def updateAxisViz(self, mode):
print mode
def _undoPos(self):
print 'undo pos'
def _redoPos(self):
print 'redo pos'
def _resetPos(self):
self.posX.reset()
self.posY.reset()
self.posZ.reset()
def _zeroPos(self):
self.posX.set(0.0)
self.posY.set(0.0)
self.posZ.set(0.0)
def _undoHpr(self):
print 'undo hpr'
def _redoHpr(self):
print 'redo hpr'
def _resetHpr(self):
self.hprH.reset()
self.hprP.reset()
self.hprR.reset()
def _zeroHpr(self):
self.hprH.set(0.0)
self.hprP.set(0.0)
self.hprR.set(0.0)
def _resetScale(self):
self.scaleX.reset()
self.scaleY.reset()
self.scaleZ.reset()
def _undoScale(self):
print 'undo scale'
def _redoScale(self):
print 'redo scale'
def _unitScale(self):
self.scaleX.set(1.0)
self.scaleY.set(1.0)
self.scaleZ.set(1.0)
def _undoAll(self):
self._undoPos()
self._undoHpr()
self._undoScale()
def _redoAll(self):
self._redoPos()
self._redoHpr()
self._redoScale()
def _resetAll(self):
self._resetPos()
self._resetHpr()
self._resetScale()
def _updateFloaterLabels(self, movementMode):
namePrefix = ''
self.movementMode = movementMode
if (movementMode == 'Drive'):
namePrefix = 'Drive delta '
elif (movementMode == 'Orbit'):
namePrefix = 'Orbit '
elif (movementMode == 'Absolute'):
namePrefix = 'Absolute '
elif (movementMode == 'Relative'):
namePrefix = 'Relative '
if(movementMode == 'Relative'):
self.wrtMenu.configure(entry_foreground = 'Black')
self.wrtMenu.configure(entry_background = 'SystemWindow')
else:
self.wrtMenu.configure(entry_foreground = 'gray50')
self.wrtMenu.configure(entry_background = '#E0E0E0')
self.posX['text'] = namePrefix + 'X'
self.posY['text'] = namePrefix + 'Y'
self.posZ['text'] = namePrefix + 'Z'
if (movementMode == 'Orbit'):
namePrefix = 'Orbit delta '
self.hprH['text'] = namePrefix + 'H'
self.hprP['text'] = namePrefix + 'P'
self.hprR['text'] = namePrefix + 'R'
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
######################################################################
# Create demo in root window for testing.
if __name__ == '__main__':
root = Pmw.initialise()
widget = Placer()

View File

@ -1,458 +0,0 @@
from Tkinter import *
from tkSimpleDialog import askfloat
import Pmw
import math
import string
import operator
# TODO:
# More standardized use of 'max' and 'min'
# Better floater style action
# New option? 'delta'? 'repeatVal'? 'modulus'
TWO_PI = 2.0 * math.pi
ONEPOINTFIVE_PI = 1.5 * math.pi
POINTFIVE_PI = 0.5 * math.pi
INNER_SF = 0.175
MAX_EXP = 5
class Dial(Pmw.MegaWidget):
def __init__(self, parent = None, **kw):
#define the megawidget options
INITOPT = Pmw.INITOPT
optiondefs = (
# Widget relief
('relief', GROOVE, INITOPT),
# Widget borderwidth
('borderwidth', 2, INITOPT),
# Relief of dial inset
('canvas_relief', GROOVE, INITOPT),
# Borderwidth of dial inset
('canvas_bd', 2, INITOPT),
# Size of edge of dial inset
('edgeLength', 50, INITOPT),
('initialValue', 0.0, INITOPT),
# Snap to angle on/off
('fSnap', 0, None),
# Do values rollover (i.e. accumulate) with multiple revolutions
('fRollover', 1, None),
('command', None, None),
('text', 'Dial Widget', self.updateLabel),
('numTicks', 10, self.createTicks),
('numDigits', 2, self.updateEntryFormat),
('min', 0.0, self.setScaleFactor),
('max', 1.0, self.setScaleFactor),
)
self.defineoptions(kw, optiondefs)
# Initialize the superclass
Pmw.MegaWidget.__init__(self, parent)
# Set up some local and instance variables
dim = self['edgeLength']
self.sfGridDelta = dim / 10
half = self.half = int(dim/2.0)
radius = self.radius = half - 2
# Running total which increments/decrements every time around dial
self.baseVal = 0.0
# Determines value of one dial revolution
self.scaleFactor = 1.0
self.dialAngle = None
# Current value
self.value = self['initialValue']
# Create the components
interior = self.interior()
interior.configure(relief = self['relief'], bd = self['borderwidth'])
# The canvas
self._canvas = self.createcomponent('canvas', (), None,
Canvas, (interior,),
width = dim + 12, height = dim,
scrollregion = ((- half),(- half),
half, half))
self._canvas.grid(rowspan = 2, columnspan = 2)
# The dial face
self._canvas.create_oval(-radius, -radius, radius, radius,
fill = 'white', tags = ('dial',))
self.createTicks()
# The velocity knob
self._canvas.create_oval(-radius * INNER_SF, -radius * INNER_SF,
radius * INNER_SF, radius * INNER_SF,
fill = '#909090', tags = ('velocityKnob',))
# The indicator
self._canvas.create_line(0, 0, 0, (- radius), width = 2,
tags = ('indicator', 'dial'))
# The Scale Factor marker
self._canvas.create_polygon( half + 4, - 4, half + 12, 0,
half + 4, + 4, fill = '#A0A0A0',
tags = ('sfMarker',))
self.sfy = 0
# The Dial's label
self._label = self.createcomponent('label', (), None,
Label, (interior,),
text = self['text'],
font = ('MS Sans Serif', 12, 'bold'),
anchor = CENTER)
self._label.grid(row = 0, col = 2, sticky = EW)
# The entry
self._entryVal = StringVar()
self._entry = self.createcomponent('entry', (), None,
Entry, (interior,),
justify = RIGHT,
textvariable = self._entryVal)
self._entry.grid(row = 1, col = 2, sticky = EW)
self._entry.bind('<Return>', self.validateEntryInput)
self._entryBackground = self._entry.cget('background')
interior.columnconfigure(2, weight = 1)
# The popup menu
self._popupMenu = Menu(interior, tearoff = 0)
self._fAngleSnap = IntVar()
self._fAngleSnap.set(self['fSnap'])
self._popupMenu.add_checkbutton(label = 'Angle snap',
variable = self._fAngleSnap,
command = self.setAngleSnap)
self._fRollover = IntVar()
self._fRollover.set(self['fRollover'])
self._popupMenu.add_checkbutton(label = 'Rollover',
variable = self._fRollover,
command = self.setRollover)
sfMenu = Menu(interior, tearoff = 1)
self.expVar = DoubleVar()
self.expVar.set(0)
for exp in range (MAX_EXP, -(MAX_EXP + 1), -1):
sf = "%g" % math.pow(10, exp)
sfMenu.add_radiobutton(label = sf, value = exp,
variable = self.expVar,
command = self.setScaleFactor)
sfMenu.add_command(label = 'Scale Factor...',
command = self.getScaleFactor)
self._popupMenu.add_cascade(label = 'Scale Factor',
menu = sfMenu)
self._popupMenu.add_command(label = 'Reset Dial',
command = self.reset)
# Add event bindings
self._canvas.tag_bind('dial', '<ButtonPress-1>', self.mouseDown)
self._canvas.tag_bind('dial', '<B1-Motion>', self.mouseMotion)
self._canvas.tag_bind('dial', '<Shift-B1-Motion>', self.shiftMouseMotion)
self._canvas.tag_bind('sfMarker', '<Enter>', self.highlightSFMarker)
self._canvas.tag_bind('sfMarker', '<Leave>', self.restoreSFMarker)
self._canvas.tag_bind('velocityKnob', '<Enter>', self.highlightKnob)
self._canvas.tag_bind('velocityKnob', '<Leave>', self.restoreKnob)
self._canvas.tag_bind('sfMarker', '<ButtonPress-1>', self.sfMouseDown)
self._canvas.tag_bind('sfMarker', '<B1-Motion>', self.sfMouseMotion)
self._canvas.tag_bind('sfMarker', '<ButtonRelease-1>', self.sfMouseUp)
self._canvas.tag_bind('velocityKnob', '<ButtonPress-1>', self.knobMouseDown)
self._canvas.tag_bind('velocityKnob', '<B1-Motion>', self.knobMouseMotion)
self._canvas.tag_bind('velocityKnob', '<ButtonRelease-1>', self.knobMouseUp)
self._canvas.bind('<ButtonPress-3>', self.popupDialMenu)
self._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
self._canvas.bind('<Up>', self.expUp)
self._canvas.bind('<Down>', self.expDown)
# Make sure input variables processed
self.initialiseoptions(Dial)
def updateLabel(self):
self._label['text'] = self['text']
def createTicks(self):
self._canvas.delete('ticks')
# Based upon input snap angle, how many ticks
numTicks = self['numTicks']
# Compute snapAngle (radians)
self.snapAngle = snapAngle = TWO_PI / numTicks
# Create the ticks at the snap angles
for ticknum in range(numTicks):
angle = snapAngle * ticknum
# convert to canvas coords
angle = angle - POINTFIVE_PI
# Compute tick endpoints
startx = math.cos(angle) * self.radius
starty = math.sin(angle) * self.radius
# Elongate ticks at 90 degree points
if (angle % POINTFIVE_PI) == 0.0:
sf = 0.6
else:
sf = 0.8
endx = startx * sf
endy = starty * sf
self._canvas.create_line(startx, starty, endx, endy,
tags = ('ticks','dial'))
def mouseDown(self,event):
self.lastAngle = dialAngle = self.computeDialAngle(event)
self.computeValueFromAngle(dialAngle)
def shiftMouseMotion(self,event):
self.mouseMotion(event, 1)
def mouseMotion(self, event, fShift = 0):
dialAngle = self.computeDialAngle(event, fShift)
self.computeValueFromAngle(dialAngle)
def computeDialAngle(self,event, fShift = 0):
x = self._canvas.canvasx(event.x)
y = self._canvas.canvasy(event.y)
rawAngle = math.atan2(y,x)
# Snap to grid
# Convert to dial coords to do snapping
dialAngle = rawAngle + POINTFIVE_PI
if operator.xor(self['fSnap'], fShift):
dialAngle = round(dialAngle / self.snapAngle) * self.snapAngle
return dialAngle
def computeValueFromAngle(self, dialAngle):
delta = self.delta
dialAngle = dialAngle % TWO_PI
# Check for rollover, if necessary
if (self.lastAngle > ONEPOINTFIVE_PI) & (dialAngle < POINTFIVE_PI):
self.baseVal = self.baseVal + delta
elif (self.lastAngle < POINTFIVE_PI) & (dialAngle > ONEPOINTFIVE_PI):
self.baseVal = self.baseVal - delta
self.lastAngle = dialAngle
# Update value and entry
newValue = self['min'] + self.baseVal + delta * (dialAngle / TWO_PI)
self.dialAngle = dialAngle
self.set(newValue)
def get(self):
return self.value
def set(self, value):
if not self['fRollover']:
if value > self['max']:
self.baseVal = 0.0
value = ((value - self['min']) %
(self['max'] - self['min'])) + self['min']
self.updateEntry(value)
if self.dialAngle:
self.updateIndicatorRadians(self.dialAngle)
self.dialAngle = None
else:
self.updateIndicator(value)
if self['command']:
self['command'](value)
def updateIndicator(self, value):
# compute new indicator angle
delta = self.delta
factors = divmod(value - self['min'], delta)
self.baseVal = factors[0] * delta
self.updateIndicatorRadians( (factors[1]/delta) * TWO_PI )
def updateIndicatorDegrees(self, degAngle):
self.updateIndicatorRadians(degAngle * (math.pi/180.0))
def updateIndicatorRadians(self,dialAngle):
rawAngle = dialAngle - POINTFIVE_PI
# Compute end points
endx = math.cos(rawAngle) * self.radius
endy = math.sin(rawAngle) * self.radius
# Draw new indicator
self._canvas.coords('indicator', endx * INNER_SF, endy * INNER_SF,
endx, endy)
def updateEntry(self, value):
self._entryVal.set(self.entryFormat % value)
def updateEntryFormat(self):
self.entryFormat = "%." + "%df" % self['numDigits']
self.updateEntry(self.value)
def validateEntryInput(self, event):
input = self._entryVal.get()
try:
newValue = string.atof(input)
self.set(newValue)
self._entry.configure(background = self._entryBackground)
except ValueError:
self._entry.configure(background = 'Pink')
def sfMouseDown(self, event):
# Record marker starting position
self.starty = self.sfy
# Record mouse starting position (convert to canvas coords)
self.lasty = self._canvas.canvasy(event.y)
def sfMouseMotion(self, event):
# How far did the mouse move?
dy = self._canvas.canvasy(event.y) - self.lasty
# Apply this delta to the marker
newy = self.starty + dy
# Compute new exponent based upon current position
exp = self.sfComputeExp(newy)
# Set resulting scale factor
self.setScaleFactorExp(exp)
def sfMouseUp(self, event):
self._canvas.delete('sfText')
# Compute exponent based on current marker position
def sfComputeExp(self, y, fSnap = 1):
# Force marker to stay visible
newy = max( -self.half, min( self.half, y ) )
# Snap it
gridDelta = self.sfGridDelta
if fSnap:
newy = round( newy / gridDelta ) * gridDelta
# Compute resulting exponent
return (-(newy / gridDelta))
def setScaleFactorExp(self, exp, showText = 1, fUpdateIndicator = 1):
self.exp = exp
# Update popup scale factor menu to nearest exponent
self.expVar.set(int(round(exp)))
# Compute new scale factor
self.scaleFactor = math.pow(10, exp)
# Compute resulting delta
self.delta = self.scaleFactor * (self['max'] - self['min'])
# Update indicator to reflect new scale factor
if fUpdateIndicator:
self.updateIndicator(self.value)
# Move marker to correct position
self.updateScaleFactorMarker(-exp*self.sfGridDelta, showText)
def expUp(self,event):
self.setScaleFactorExp(min(MAX_EXP, self.exp + 1), 0)
def expDown(self,event):
self.setScaleFactorExp(max(-MAX_EXP, self.exp - 1), 0)
def knobMouseDown(self,event):
self.lasty = self._canvas.canvasy(event.y)
self.updateIndicatorRadians(0.0)
self.velocityTask = self.after(100, self.computeVelocity)
def knobMouseMotion(self, event):
# How far is the mouse from the origin?
dx = self._canvas.canvasx(event.x)
self.lasty = self._canvas.canvasy(event.y)
exp = -5 + dx/20.0
exp = max( -5, min( 5, exp ) )
# Set resulting scale factor
self.setScaleFactorExp(exp, 0, fUpdateIndicator = 0)
def knobMouseUp(self, event):
self.after_cancel(self.velocityTask)
# reset indicator
self.updateIndicator(self.value)
def computeVelocity(self):
if self.lasty < 0:
sign = -1.0
else:
sign = 1.0
lasty = abs(self.lasty)
if lasty > 5:
lasty = lasty - 5
sf = min(100, lasty)/100.0
sf = pow(sf, 3.0)
newVal = self.value - sign * sf * self.delta
self.dialAngle = - sign * sf * POINTFIVE_PI
self.set(newVal)
self.velocityTask = self.after(100, self.computeVelocity)
def updateScaleFactorMarker(self, newy, showText = 1):
# Move marker
self._canvas.move('sfMarker', 0, newy - self.sfy)
self.sfy = newy
# Show current scaling factor
if showText:
sfText = '%g' % (self.delta / 10.0,)
self._canvas.delete('sfText')
self._canvas.create_rectangle( self.half - 40, newy - 6,
self.half, newy + 7,
fill = 'white',
tags = ('sfText',))
self._canvas.create_text( self.half, newy,
justify = RIGHT,
anchor = E,
text = sfText,
fill = 'Red',
tags = ('sfText',))
# The following routines are used to handle the popup menu
def popupDialMenu(self,event):
self._popupMenu.post(event.widget.winfo_pointerx(),
event.widget.winfo_pointery())
# This is called by the scale factor popup menu and when the user
# changes the dial 'delta' value
def setScaleFactor(self):
exp = self.expVar.get()
self.setScaleFactorExp(exp, showText = 0)
# This handles the popup scale factor dialog
def getScaleFactor(self):
sf = askfloat('Dial Scale Factor', 'Scale Factor:',
parent = self.interior())
if sf:
self.setScaleFactorExp(math.log10(sf), showText = 0)
# Turn angle snap on/off
def setAngleSnap(self):
self['fSnap'] = self._fAngleSnap.get()
# Turn rollover (accumulation of a sum) on/off
def setRollover(self):
self['fRollover'] = self._fRollover.get()
def highlightSFMarker(self, event):
self._canvas.itemconfigure('sfMarker', fill = '#252525')
def restoreSFMarker(self, event):
self._canvas.itemconfigure('sfMarker', fill = '#A0A0A0')
def highlightKnob(self, event):
self._canvas.itemconfigure('velocityKnob', fill = '#252525')
def restoreKnob(self, event):
self._canvas.itemconfigure('velocityKnob', fill = '#A0A0A0')
# Reset dial to zero
def mouseReset(self,event):
if not self._canvas.find_withtag(CURRENT):
self.reset()
def reset(self):
self.set(self['initialValue'])
# Should we do this?
self.setScaleFactorExp(0, showText = 0)
class AngleDial(Dial):
def __init__(self, parent = None, **kw):
# Set the typical defaults for a 360 degree angle dial
optiondefs = (
('fRollover', 0, None),
('numTicks', 12, None),
('max', 360.0, None),
)
self.defineoptions(kw, optiondefs)
# Initialize the superclass
Dial.__init__(self, parent)
# Needed because this method checks if self.__class__ is myClass
# where myClass is the argument passed into inialiseoptions
self.initialiseoptions(AngleDial)
if __name__ == '__main__':
tl = Toplevel()
d = Dial(tl)
d2 = Dial(tl, numTicks = 12, max = 360, fRollover = 0, initialValue = 180)
d3 = Dial(tl, numTicks = 12, max = 90, min = -90, fRollover = 0)
d4 = Dial(tl, numTicks = 16, max = 256, fRollover = 0)
d.pack(expand = 1, fill = X)
d2.pack(expand = 1, fill = X)
d3.pack(expand = 1, fill = X)
d4.pack(expand = 1, fill = X)

View File

@ -1,344 +0,0 @@
"""
Floater Class: Velocity style controller for floating point values with
a label, entry (validated), and scale
"""
from Tkinter import *
import Pmw
import string
class Floater(Pmw.MegaWidget):
"Velocity style floating point controller"
def __init__(self, parent = None, **kw):
# Define the megawidget options.
optiondefs = (
('initialValue', 0.0, Pmw.INITOPT),
('resolution', None, None),
('command', None, None),
('maxVelocity', 100.0, None),
('min', None, self._updateValidate),
('max', None, self._updateValidate),
('text', 'Floater', self._updateLabelText),
('significantDigits', 2, self._setSigDigits),
)
self.defineoptions(kw, optiondefs)
# Initialise superclass
Pmw.MegaWidget.__init__(self, parent)
# Initialize some class variables
self.value = self['initialValue']
self.velocity = 0.0
self.entryFormat = '%.2f'
# Create the components.
# Setup up container
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 12 bold")
self.label.pack(side='left', expand = 1, fill = 'x')
# Now pack the frame
self.labelFrame.pack(expand = 1, fill = 'both')
# 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)
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']
def _updateValidate(self):
self.configure(entryField_validate = {
'validator' : 'real',
'min' : self['min'],
'max' : self['max'],
'minstrict' : 0,
'maxstrict' : 0})
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)
def _startFloaterTask(self,event):
self._fFloaterTask = 1
self._floaterTask()
def _floaterTask(self):
if self.velocity != 0.0:
self.set( self.value + self.velocity )
if self._fFloaterTask:
self.after(50, self._floaterTask)
def _floaterReset(self, event):
self._fFloaterTask = 0
self.velocity = 0.0
self.scale.set(0.0)
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() )
self.set( val )
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):
# Clamp value
if self['min'] is not None:
if newVal < self['min']:
newVal = self['min']
if self['max'] is not None:
if newVal > self['max']:
newVal = 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 & (self['command'] is not None):
self['command']( newVal )
class FloaterGroup(Pmw.MegaToplevel):
def __init__(self, parent = None, **kw):
# Default group size
DEFAULT_DIM = 1
# Default value depends on *actual* group size, test for user input
DEFAULT_VALUE = [0.0] * kw.get('dim', DEFAULT_DIM)
DEFAULT_LABELS = map(lambda x: 'v[%d]' % x,
range(kw.get('dim', DEFAULT_DIM)))
#define the megawidget options
INITOPT = Pmw.INITOPT
optiondefs = (
('dim', DEFAULT_DIM, INITOPT),
('side', TOP, INITOPT),
('title', 'Floater Group', None),
# A tuple of initial values, one for each floater
('initialValue', DEFAULT_VALUE, INITOPT),
# The command to be executed any time one of the floaters is updated
('command', None, None),
# A tuple of labels, one for each floater
('labels', DEFAULT_LABELS, self._updateLabels),
)
self.defineoptions(kw, optiondefs)
# Initialize the toplevel widget
Pmw.MegaToplevel.__init__(self, parent)
# Create the components
interior = self.interior()
# Get a copy of the initial value (making sure its a list)
self._value = list(self['initialValue'])
# The Menu Bar
self.balloon = Pmw.Balloon()
menubar = self.createcomponent('menubar',(), None,
Pmw.MenuBar, (interior,),
balloon = self.balloon)
menubar.pack(fill=X)
# FloaterGroup Menu
menubar.addmenu('Floater Group', 'Floater Group Operations')
menubar.addmenuitem(
'Floater Group', 'command', 'Reset the Floater Group panel',
label = 'Reset',
command = lambda s = self: s.reset())
menubar.addmenuitem(
'Floater Group', 'command', 'Dismiss Floater Group panel',
label = 'Dismiss', command = self.withdraw)
menubar.addmenu('Help', 'Floater Group Help Operations')
self.toggleBalloonVar = IntVar()
self.toggleBalloonVar.set(0)
menubar.addmenuitem('Help', 'checkbutton',
'Toggle balloon help',
label = 'Balloon Help',
variable = self.toggleBalloonVar,
command = self.toggleBalloon)
self.floaterList = []
for index in range(self['dim']):
# Add a group alias so you can configure the floaters via:
# fg.configure(Floater_XXX = YYY)
f = self.createcomponent(
'floater%d' % index, (), 'Floater', Floater,
(interior,), initialValue = self._value[index],
text = self['labels'][index])
# Do this separately so command doesn't get executed during construction
f['command'] = lambda val, s=self, i=index: s._floaterSetAt(i, val)
f.pack(side = self['side'], expand = 1, fill = X)
self.floaterList.append(f)
# Make sure floaters are initialized
self.set(self['initialValue'])
# Make sure input variables processed
self.initialiseoptions(FloaterGroup)
def _updateLabels(self):
if self['labels']:
for index in range(self['dim']):
self.floaterList[index]['text'] = self['labels'][index]
def toggleBalloon(self):
if self.toggleBalloonVar.get():
self.balloon.configure(state = 'balloon')
else:
self.balloon.configure(state = 'none')
def get(self):
return self._value
def getAt(self,index):
return self._value[index]
# This is the command is used to set the groups value
def set(self, value, fCommand = 1):
for i in range(self['dim']):
self._value[i] = value[i]
# Update floater, but don't execute its command
self.floaterList[i].set(value[i], 0)
if fCommand & (self['command'] is not None):
self['command'](self._value)
def setAt(self, index, value):
# Update floater and execute its command
self.floaterList[index].set(value)
# This is the command used by the floater
def _floaterSetAt(self, index, value):
self._value[index] = value
if self['command']:
self['command'](self._value)
def reset(self):
self.set(self['initialValue'])
## SAMPLE CODE
if __name__ == '__main__':
# Initialise Tkinter and Pmw.
root = Toplevel()
root.title('Pmw Floater demonstration')
# Dummy command
def printVal(val):
print val
# Create and pack a Floater megawidget.
mega1 = Floater(root, command = printVal)
mega1.pack(side = 'left', expand = 1, fill = 'x')
"""
# These are things you can set/configure
# Starting value for floater
mega1['initialValue'] = 123.456
mega1['text'] = 'Drive delta X'
mega1['min'] = 0.0
mega1['max'] = 1000.0
mega1['resolution'] = 1.0
# To change the color of the label:
mega1.label['foreground'] = 'Red'
# Max change/update, default is 100
# 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
"""
# To create a floater group to set an RGBA value:
group1 = FloaterGroup(root, dim = 4,
title = 'Simple RGBA Panel',
labels = ('R', 'G', 'B', 'A'),
Floater_min = 0.0,
Floater_max = 255.0,
Floater_resolution = 1.0,
command = printVal)
# Uncomment this if you aren't running in IDLE
#root.mainloop()

View File

@ -1,286 +0,0 @@
from Tkinter import *
import Pmw
import floater
import string
import tkColorChooser
class VectorEntry(Pmw.MegaWidget):
def __init__(self, parent = None, **kw):
# Default vector size
DEFAULT_DIM = 3
# Default value depends on *actual* vector size, test for user input
DEFAULT_VALUE = [0.0] * kw.get('dim', DEFAULT_DIM)
DEFAULT_LABELS = map(lambda x: 'v[%d]' % x,
range(kw.get('dim', DEFAULT_DIM)))
# Process options
INITOPT = Pmw.INITOPT
optiondefs = (
('dim', DEFAULT_DIM, INITOPT),
('initialValue', DEFAULT_VALUE, INITOPT),
('label_width', 12, None),
('command', None, None),
('entryWidth', 8, self._updateEntryWidth),
('relief', GROOVE, self._updateRelief),
('bd', 2, self._updateBorderWidth),
('text', 'Vector:', self._updateText),
('min', None, self._updateValidate),
('max', None, self._updateValidate),
('significantDigits', 2, self._setSigDigits),
)
self.defineoptions(kw, optiondefs)
# Initialize superclass
Pmw.MegaWidget.__init__(self, parent)
# Initialize value
# Make sure its a list (and as a byproduct, make a distinct copy)
self._value = list(self['initialValue'])
self._floaters = None
self.entryFormat = '%.2f'
# Get a handle on the parent container
interior = self.interior()
# This does double duty as a menu button
self._label = self.createcomponent('label', (), None,
Menubutton, (interior,),
text = self['text'],
activebackground = '#909090')
self.menu = self._label['menu'] = Menu(self._label)
self.menu.add_command(label = 'Reset', command = self.reset)
self.menu.add_command(label = 'Popup sliders', command = self.popupSliders)
self._label.pack(side = LEFT, fill = X, ipadx = 2)
self.variableList = []
self.entryList = []
for index in range(self['dim']):
var = StringVar()
self.variableList.append(var)
# To set the configuration of all entrys in a vector use:
# ve.configure(Entry_XXX = YYY)
# To configure an individual entryfield's entry use:
# ve.configure(entry0_XXX = YYY)
entry = self.createcomponent(
'entryField%d' % index,
(('entry%d' % index,
'entryField%d_entry' % index),),
'Entry',
Pmw.EntryField, (interior,),
entry_justify = RIGHT,
entry_textvariable = var,
command = lambda s = self, i = index: s._entryUpdateAt(i))
entry.pack(side = LEFT, expand = 1, fill = X)
self.entryList.append(entry)
# To configure the floaterGroup use:
# ve.configure(floaterGroup_XXX = YYY)
# ve.configure(fGroup_XXX = YYY) or
# To set the configuration all floaters in a group use:
# ve.configure(Floater_XXX = YYY)
# To configure an individual floater in a group use:
# ve.configure(floaterGroup_floater0_XXX = YYY) or
# ve.configure(fGroup_floater0_XXX = YYY)
self._floaters = self.createcomponent(
'floaterGroup',
(('fGroup', 'floaterGroup'),
('Floater', 'floaterGroup_Floater'),), None,
floater.FloaterGroup, (self.interior(),),
dim = self['dim'], title = self['text'],
command = self.set)
# Note: This means the 'X' on the menu bar doesn't really destroy
# the panel, just withdraws it. This is to avoid problems which occur
# if the user kills the floaterGroup and then tries to pop it open again
self._floaters.userdeletefunc(self._floaters.withdraw)
self._floaters.withdraw()
# Make sure entries are updated
self.set(self['initialValue'])
# Make sure input variables processed
self.initialiseoptions(VectorEntry)
def menu(self):
return self.menu
def label(self):
return self._label
def entry(self, index):
return self.entryList[index]
def entryList(self):
return self.entryList
def floaters(self):
return self._floaters
def _clearFloaters(self):
self._floaters.withdraw()
def _updateText(self):
self._label['text'] = self['text']
def _updateRelief(self):
self.interior()['relief'] = self['relief']
def _updateBorderWidth(self):
self.interior()['bd'] = self['bd']
def _updateEntryWidth(self):
self['Entry_entry_width'] = self['entryWidth']
def _setSigDigits(self):
sd = self['significantDigits']
self.entryFormat = '%.' + '%d' % sd + 'f'
self.configure(Floater_significantDigits = sd)
# And refresh value to reflect change
for index in range(self['dim']):
self._refreshEntry(index)
def _updateValidate(self):
# Update entry field to respect new limits
self.configure(Entry_validate = {
'validator' : 'real',
'min' : self['min'],
'max' : self['max'],
'minstrict' : 0,
'maxstrict' : 0})
# Reflect changes in floaters
self.configure(Floater_min = self['min'],
Floater_max = self['max'])
def get(self):
return self._value
def getAt(self,index):
return self._value[index]
def set(self, value):
for i in range(self['dim']):
self._value[i] = value[i]
self.variableList[i].set(self.entryFormat % value[i])
self.action()
def setAt(self, index, value):
self.variableList[index].set(self.entryFormat % value)
self._value[index] = value
self.action()
def _entryUpdateAt(self, index):
entryVar = self.variableList[index]
# Did we get a valid float?
try:
newVal = string.atof(entryVar.get())
except ValueError:
return
# Clamp value
if self['min'] is not None:
if newVal < self['min']:
newVal = self['min']
if self['max'] is not None:
if newVal > self['max']:
newVal = self['max']
# Update vector's value
self._value[index] = newVal
# refresh entry to reflect formatted value
self._refreshEntry(index)
# Update the floaters and call the command
self.action()
def _refreshEntry(self,index):
self.variableList[index].set( self.entryFormat % self._value[index] )
self.entryList[index].checkentry()
def _refreshFloaters(self):
if self._floaters:
self._floaters.set(self._value, 0)
def action(self):
self._refreshFloaters()
if self['command']:
self['command'](self._value)
def reset(self):
self.set(self['initialValue'])
def addMenuItem(self, label = '', command = None):
self.menu.add_command(label = label, command = command)
def popupSliders(self):
self._floaters.set(self.get()[:])
self._floaters.show()
class Vector3Entry(VectorEntry):
def __init__(self, parent = None, **kw):
# Initialize options for the class
optiondefs = (
('dim', 3, Pmw.INITOPT),
('fGroup_labels', ('X','Y','Z'), None),
)
self.defineoptions(kw, optiondefs)
# Initialize the superclass, make sure dim makes it to superclass
VectorEntry.__init__(self, parent, dim = self['dim'])
# Needed because this method checks if self.__class__ is myClass
# where myClass is the argument passed into inialiseoptions
self.initialiseoptions(Vector3Entry)
class Vector4Entry(VectorEntry):
def __init__(self, parent = None, **kw):
# Initialize options for the class
optiondefs = (
('dim', 4, Pmw.INITOPT),
('fGroup_labels', ('X','Y','Z','W'), None),
)
self.defineoptions(kw, optiondefs)
# Initialize the superclass, make sure dim makes it to superclass
VectorEntry.__init__(self, parent, dim = self['dim'])
# Needed because this method checks if self.__class__ is myClass
# where myClass is the argument passed into inialiseoptions
self.initialiseoptions(Vector4Entry)
class ColorEntry(VectorEntry):
def __init__(self, parent = None, **kw):
# Initialize options for the class (overriding some superclass options)
optiondefs = (
('dim', 4, Pmw.INITOPT),
('fGroup_labels', ('R','G','B','A'), None),
('min', 0.0, None),
('max', 255.0, None),
('significantDigits', 0, None),
('Floater_resolution', 1.0, None),
)
self.defineoptions(kw, optiondefs)
# Initialize the superclass, make sure dim makes it to superclass
VectorEntry.__init__(self, parent, dim = self['dim'])
# Add menu item to popup color picker
self.addMenuItem(
'Popup color picker',
command = lambda s = self: s.popupColorPicker())
# Needed because this method checks if self.__class__ is myClass
# where myClass is the argument passed into inialiseoptions
self.initialiseoptions(ColorEntry)
def popupColorPicker(self):
# Can pass in current color with: color = (255, 0, 0)
color = tkColorChooser.askcolor(
parent = self.interior(),
# Initialize it to current color
initialcolor = tuple(self.get()[:3]))[0]
if color:
self.set((color[0], color[1], color[2], self.getAt(3)))
if __name__ == '__main__':
root = Toplevel()
root.title('Vector Widget demo')
ve = VectorEntry(root); ve.pack()
v3e = Vector3Entry(root); v3e.pack()
v4e = Vector4Entry(root); v4e.pack()
ce = ColorEntry(root); ce.pack()