| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- """Undocumented Module"""
- __all__ = ['VectorEntry', 'Vector2Entry', 'Vector3Entry', 'Vector4Entry', 'ColorEntry']
- from . import Valuator
- import Pmw
- import tkinter as tk
- from tkinter.colorchooser import askcolor
- 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', tk.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,
- tk.Menubutton, (interior,),
- text = self['text'],
- activebackground = '#909090')
- self.menu = self._label['menu'] = tk.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 = tk.LEFT, fill = tk.X, ipadx = self['labelIpadx'])
- self.variableList = []
- self.entryList = []
- for index in range(self['dim']):
- var = tk.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 = tk.RIGHT,
- entry_textvariable = var,
- command = lambda s = self, i = index: s._entryUpdateAt(i))
- entry.pack(side = tk.LEFT, expand = 1, fill = tk.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 label(self):
- return self._label
- def entry(self, index):
- return self.entryList[index]
- 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 (float, int):
- 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 = float(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'] is not 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 = 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)))
|