mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 00:06:44 -04:00
*** empty log message ***
This commit is contained in:
parent
0067eb1d46
commit
f16d63d6ea
@ -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
|
||||
|
103
direct/src/directutil/DirectSession.py
Normal file
103
direct/src/directutil/DirectSession.py
Normal 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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ from MessengerGlobal import *
|
||||
from TaskManagerGlobal import *
|
||||
from EventManagerGlobal import *
|
||||
from AudioManagerGlobal import *
|
||||
from PythonUtil import *
|
||||
import Task
|
||||
import EventManager
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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()
|
@ -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()
|
@ -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()
|
||||
|
@ -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)
|
@ -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()
|
@ -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()
|
Loading…
x
Reference in New Issue
Block a user