panda3d/direct/src/tkwidgets/VectorWidgets.py
2001-01-20 02:03:27 +00:00

295 lines
11 KiB
Python

from Tkinter import *
import Pmw
import Floater
import EntryScale
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)))
VALUATOR = kw.get('valuatorType', Floater.FloaterGroup)
# Process options
INITOPT = Pmw.INITOPT
optiondefs = (
('dim', DEFAULT_DIM, INITOPT),
('initialValue', DEFAULT_VALUE, INITOPT),
('resetValue', DEFAULT_VALUE, None),
('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),
('valuatorType', VALUATOR, None)
)
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['resetValue'] = 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(Valuator_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'),
('Valuator', 'floaterGroup_Valuator'),), None,
self['valuatorType'], (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(Valuator_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(Valuator_min = self['min'],
Valuator_max = self['max'])
def get(self):
return self._value
def getAt(self,index):
return self._value[index]
def set(self, value, fCommand = 0):
for i in range(self['dim']):
self._value[i] = value[i]
self.variableList[i].set(self.entryFormat % value[i])
self.action(fCommand)
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, fCommand = 0):
self._refreshFloaters()
if fCommand & (self['command'] != None):
self['command'](self._value)
def reset(self):
self.set(self['resetValue'])
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),
('Valuator_resolution', 1.0, None),
)
self.defineoptions(kw, optiondefs)
#kw['valuatorType'] = EntryScale.EntryScaleGroup
#kw['dim'] = self['dim']
# Initialize the superclass, make sure dim makes it to superclass
VectorEntry.__init__(self, parent, dim = self['dim'],
valuatorType = EntryScale.EntryScaleGroup)
# 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()