mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-11-01 01:07:54 +00:00
347 lines
13 KiB
Python
347 lines
13 KiB
Python
"""Undocumented Module"""
|
|
|
|
__all__ = ['VectorEntry', 'Vector2Entry', 'Vector3Entry', 'Vector4Entry', 'ColorEntry']
|
|
|
|
from direct.showbase.TkGlobal import *
|
|
from Tkinter import *
|
|
import Valuator
|
|
import Floater
|
|
import Slider
|
|
import string
|
|
import tkColorChooser
|
|
import types
|
|
import Pmw
|
|
|
|
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 = ['v[%d]' % x for x in range(kw.get('dim', DEFAULT_DIM))]
|
|
|
|
# Process options
|
|
INITOPT = Pmw.INITOPT
|
|
optiondefs = (
|
|
('dim', DEFAULT_DIM, INITOPT),
|
|
('value', DEFAULT_VALUE, INITOPT),
|
|
('resetValue', DEFAULT_VALUE, None),
|
|
('label_width', 12, None),
|
|
('labelIpadx', 2, 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),
|
|
('numDigits', 2, self._setSigDigits),
|
|
('type', 'floater', None),
|
|
('state', 'normal', self._setState),
|
|
)
|
|
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['value'])
|
|
self['resetValue'] = self['value']
|
|
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 = self['labelIpadx'])
|
|
|
|
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,
|
|
Valuator.ValuatorGroupPanel, (self.interior(),),
|
|
dim = self['dim'],
|
|
#title = self['text'],
|
|
type = self['type'],
|
|
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['value'])
|
|
|
|
# Record entry color
|
|
self.entryBackground = self.cget('Entry_entry_background')
|
|
|
|
# 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['numDigits']
|
|
self.entryFormat = '%.' + '%d' % sd + 'f'
|
|
self.configure(valuator_numDigits = 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 = 1):
|
|
if type(value) in (types.FloatType, types.IntType, types.LongType):
|
|
value = [value] * self['dim']
|
|
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, fCommand = 1):
|
|
self.variableList[index].set(self.entryFormat % value)
|
|
self._value[index] = value
|
|
self.action(fCommand)
|
|
|
|
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 = 1):
|
|
self._refreshFloaters()
|
|
if fCommand and (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()
|
|
|
|
def _setState(self):
|
|
if self['state'] == 'disabled':
|
|
# Disable entry
|
|
self.configure(Entry_entry_state = 'disabled')
|
|
self.configure(Entry_entry_background = '#C0C0C0')
|
|
# Disable floater Group scale
|
|
self.component('fGroup').configure(
|
|
valuator_state = 'disabled')
|
|
# Disable floater group entry
|
|
self.component('fGroup').configure(
|
|
valuator_entry_state = 'disabled')
|
|
self.component('fGroup').configure(
|
|
valuator_entry_background = '#C0C0C0')
|
|
else:
|
|
# Disable entry
|
|
self.configure(Entry_entry_state = 'normal')
|
|
self.configure(Entry_entry_background = self.entryBackground)
|
|
# Disable floater Group scale
|
|
self.component('fGroup').configure(
|
|
valuator_state = 'normal')
|
|
# Disable floater group entry
|
|
self.component('fGroup').configure(
|
|
valuator_entry_state = 'normal')
|
|
self.component('fGroup').configure(
|
|
valuator_entry_background = self.entryBackground)
|
|
|
|
class Vector2Entry(VectorEntry):
|
|
def __init__(self, parent = None, **kw):
|
|
# Initialize options for the class
|
|
optiondefs = (
|
|
('dim', 2, 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(Vector2Entry)
|
|
|
|
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),
|
|
('type', 'slider', Pmw.INITOPT),
|
|
('fGroup_labels', ('R','G','B','A'), None),
|
|
('min', 0.0, None),
|
|
('max', 255.0, None),
|
|
('nuDigits', 0, None),
|
|
('valuator_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()
|