761 lines
28 KiB
Python
761 lines
28 KiB
Python
"""Undocumented Module"""
|
|
|
|
__all__ = ['Valuator', 'ValuatorGroup', 'ValuatorGroupPanel']
|
|
|
|
from direct.showbase.DirectObject import *
|
|
from direct.showbase.TkGlobal import *
|
|
from . import WidgetPropertiesDialog
|
|
import Pmw
|
|
from direct.directtools.DirectUtil import getTkColorString
|
|
from panda3d.core import Vec4
|
|
|
|
if sys.version_info >= (3, 0):
|
|
from tkinter.colorchooser import askcolor
|
|
else:
|
|
from tkColorChooser import askcolor
|
|
|
|
VALUATOR_MINI = 'mini'
|
|
VALUATOR_FULL = 'full'
|
|
|
|
class Valuator(Pmw.MegaWidget):
|
|
sfBase = 3.0
|
|
sfDist = 7
|
|
deadband = 5
|
|
""" Base class for widgets used to interactively adjust numeric values """
|
|
def __init__(self, parent = None, **kw):
|
|
#define the megawidget options
|
|
INITOPT = Pmw.INITOPT
|
|
optiondefs = (
|
|
('state', NORMAL, self.setState),
|
|
# Widget appearance
|
|
('relief', GROOVE, None),
|
|
('borderwidth', 2, None),
|
|
('text', 'Valuator', self.setLabel),
|
|
# Initial and reset values
|
|
('value', 0.0, INITOPT),
|
|
('resetValue', 0.0, None),
|
|
# Behavior
|
|
('min', None, None),
|
|
('max', None, None),
|
|
('resolution', None, None),
|
|
('numDigits', 2, self.setEntryFormat),
|
|
# Enable/disable popup menu
|
|
('fAdjustable', 1, None),
|
|
# Actions
|
|
('command', None, None),
|
|
('commandData', [], None),
|
|
('fCommandOnInit', 0, INITOPT),
|
|
# Callbacks to execute when updating widget's value
|
|
('preCallback', None, None),
|
|
('postCallback', None, None),
|
|
# Extra data to be passed to callback function, needs to be a list
|
|
('callbackData', [], None),
|
|
)
|
|
self.defineoptions(kw, optiondefs)
|
|
|
|
# Initialize the superclass
|
|
Pmw.MegaWidget.__init__(self, parent)
|
|
|
|
# Current adjusted (for min/max/resolution) value
|
|
self.adjustedValue = self['value']
|
|
|
|
# Create the components
|
|
interior = self.interior()
|
|
interior.configure(relief = self['relief'], bd = self['borderwidth'])
|
|
|
|
# The Valuator
|
|
self.createValuator()
|
|
# Set valuator callbacks for mouse start/stop
|
|
self._valuator['preCallback'] = self._mouseDown
|
|
self._valuator['postCallback'] = self._mouseUp
|
|
|
|
# The Label
|
|
if self['text'] is not None:
|
|
self._label = self.createcomponent('label', (), None,
|
|
Label, (interior,),
|
|
text = self['text'],
|
|
font = ('MS Sans Serif', 12),
|
|
anchor = CENTER)
|
|
else:
|
|
self._label = None
|
|
|
|
# The entry
|
|
self._entryVal = StringVar()
|
|
self._entry = self.createcomponent('entry', (), None,
|
|
Entry, (interior,),
|
|
justify = RIGHT,
|
|
width = 12,
|
|
textvariable = self._entryVal)
|
|
self._entry.bind('<Return>', self.validateEntryInput)
|
|
self._entryBackground = self._entry.cget('background')
|
|
|
|
# Pack Valuator Widget
|
|
self.packValuator()
|
|
|
|
# Set reset value if none specified
|
|
if 'resetValue' not in kw:
|
|
self['resetValue'] = self['value']
|
|
|
|
if self['fAdjustable']:
|
|
# The popup menu
|
|
self._popupMenu = Menu(interior, tearoff = 0)
|
|
self.addValuatorMenuEntries()
|
|
self._popupMenu.add_command(label = 'Reset',
|
|
command = self.reset)
|
|
self._popupMenu.add_command(label = 'Set to Zero',
|
|
command = self.zero)
|
|
self._popupMenu.add_command(
|
|
label = 'Properties...',
|
|
command = self._popupPropertiesDialog)
|
|
# Add key bindings
|
|
if self._label:
|
|
self._label.bind(
|
|
'<ButtonPress-3>', self._popupValuatorMenu)
|
|
self._entry.bind(
|
|
'<ButtonPress-3>', self._popupValuatorMenu)
|
|
self._valuator._widget.bind(
|
|
'<ButtonPress-3>', self._popupValuatorMenu)
|
|
|
|
# A Dictionary of dictionaries for the popup property dialog
|
|
self.propertyDict = {
|
|
'state':
|
|
{'widget': self,
|
|
'type': 'string',
|
|
'help': 'Enter state: normal or disabled.'
|
|
},
|
|
|
|
'text':
|
|
{'widget': self,
|
|
'type': 'string',
|
|
'help': 'Enter label text.'
|
|
},
|
|
|
|
'min':
|
|
{ 'widget': self,
|
|
'type': 'real',
|
|
'fNone': 1,
|
|
'help': 'Minimum allowable value. Enter None for no minimum.'},
|
|
'max':
|
|
{ 'widget': self,
|
|
'type': 'real',
|
|
'fNone': 1,
|
|
'help': 'Maximum allowable value. Enter None for no maximum.'},
|
|
'numDigits':
|
|
{'widget': self,
|
|
'type': 'integer',
|
|
'help': 'Number of digits after decimal point.'
|
|
},
|
|
|
|
'resolution':
|
|
{'widget': self,
|
|
'type': 'real',
|
|
'fNone': 1,
|
|
'help':'Widget resolution. Enter None for no resolution .'
|
|
},
|
|
|
|
'resetValue':
|
|
{ 'widget': self,
|
|
'type': 'real',
|
|
'help': 'Enter value to set widget to on reset.'}
|
|
}
|
|
# Property list defines the display order of the properties
|
|
self.propertyList = [
|
|
'state', 'text', 'min', 'max', 'numDigits',
|
|
'resolution', 'resetValue']
|
|
# Add any valuator specific properties
|
|
self.addValuatorPropertiesToDialog()
|
|
|
|
# Make sure input variables processed
|
|
self.fInit = self['fCommandOnInit']
|
|
self.initialiseoptions(Valuator)
|
|
|
|
def set(self, value, fCommand = 1):
|
|
"""
|
|
Update widget's value by setting valuator, which will in
|
|
turn update the entry. fCommand flag (which is passed to the
|
|
valuator as commandData, which is then passed in turn to
|
|
self.setEntry) controls command execution.
|
|
"""
|
|
self._valuator['commandData'] = [fCommand]
|
|
self._valuator.set(value)
|
|
# Restore commandData to 1 so that interaction via valuator widget
|
|
# will result in command being executed, otherwise a set with
|
|
# commandData == 0 will stick and commands will not be executed
|
|
self._valuator['commandData'] = [1]
|
|
|
|
def get(self):
|
|
""" Return current widget value """
|
|
return self.adjustedValue
|
|
|
|
def setEntry(self, value, fCommand = 1):
|
|
"""
|
|
Update value displayed in entry, fCommand flag controls
|
|
command execution
|
|
"""
|
|
# Clamp value
|
|
if self['min'] is not None:
|
|
if value < self['min']:
|
|
value = self['min']
|
|
if self['max'] is not None:
|
|
if value > self['max']:
|
|
value = self['max']
|
|
# Round by resolution
|
|
if self['resolution'] is not None:
|
|
value = round(value / self['resolution']) * self['resolution']
|
|
# Format value and use it to set entry
|
|
self._entryVal.set(self.entryFormat % value)
|
|
# Update indicator (if any) to reflect new adjusted value
|
|
self._valuator.updateIndicator(value)
|
|
# Execute command if required
|
|
if fCommand and self.fInit and (self['command'] is not None):
|
|
self['command'](*[value] + self['commandData'])
|
|
# Record adjusted value
|
|
self.adjustedValue = value
|
|
# Once initialization is finished, allow commands to execute
|
|
self.fInit = 1
|
|
|
|
def setEntryFormat(self):
|
|
"""
|
|
Change the number of significant digits in entry
|
|
"""
|
|
# Create new format string
|
|
self.entryFormat = "%." + "%df" % self['numDigits']
|
|
# Update entry to reflect new format
|
|
self.setEntry(self.get())
|
|
# Pass info down to valuator to adjust valuator sensitivity
|
|
self._valuator['numDigits'] = self['numDigits']
|
|
|
|
def validateEntryInput(self, event):
|
|
""" Check validity of entry and if valid pass along to valuator """
|
|
input = self._entryVal.get()
|
|
try:
|
|
# Reset background
|
|
self._entry.configure(background = self._entryBackground)
|
|
# Get new value and check validity
|
|
newValue = float(input)
|
|
# If OK, execute preCallback if one defined
|
|
self._preCallback()
|
|
# Call set to update valuator
|
|
self.set(newValue)
|
|
# Execute callback
|
|
self._postCallback()
|
|
# Update valuator to reflect adjusted value
|
|
# Don't execute command
|
|
self._valuator.set(self.adjustedValue, 0)
|
|
except ValueError:
|
|
# Invalid entry, flash background
|
|
self._entry.configure(background = 'Pink')
|
|
|
|
# Callbacks executed on mouse down/up
|
|
def _mouseDown(self):
|
|
""" Function to execute at start of mouse interaction """
|
|
# Execute pre interaction callback
|
|
self._preCallback()
|
|
|
|
def _mouseUp(self):
|
|
""" Function to execute at end of mouse interaction """
|
|
# Execute post interaction callback
|
|
self._postCallback()
|
|
# Update valuator to reflect adjusted value
|
|
# Don't execute command
|
|
self._valuator.set(self.adjustedValue, 0)
|
|
|
|
# Callback functions
|
|
def _preCallback(self):
|
|
if self['preCallback']:
|
|
self['preCallback'](*self['callbackData'])
|
|
|
|
def _postCallback(self):
|
|
# Exectute post callback if one defined
|
|
if self['postCallback']:
|
|
self['postCallback'](*self['callbackData'])
|
|
|
|
def setState(self):
|
|
""" Enable/disable widget """
|
|
if self['state'] == NORMAL:
|
|
self._entry['state'] = NORMAL
|
|
self._entry['background'] = self._entryBackground
|
|
self._valuator._widget['state'] = NORMAL
|
|
elif self['state'] == DISABLED:
|
|
self._entry['background'] = 'grey75'
|
|
self._entry['state'] = DISABLED
|
|
self._valuator._widget['state'] = DISABLED
|
|
|
|
def setLabel(self):
|
|
""" Update label's text """
|
|
if self._label:
|
|
self._label['text'] = self['text']
|
|
|
|
def zero(self):
|
|
"""
|
|
self.zero()
|
|
Set valuator to zero
|
|
"""
|
|
self.set(0.0)
|
|
|
|
def reset(self):
|
|
"""
|
|
self.reset()
|
|
Reset valuator to reset value
|
|
"""
|
|
self.set(self['resetValue'])
|
|
|
|
def mouseReset(self, event):
|
|
"""
|
|
Reset valuator to resetValue
|
|
"""
|
|
# If not over any canvas item
|
|
#if not self._widget.find_withtag(CURRENT):
|
|
self.reset()
|
|
|
|
# Popup dialog to adjust widget properties
|
|
def _popupValuatorMenu(self, event):
|
|
self._popupMenu.post(event.widget.winfo_pointerx(),
|
|
event.widget.winfo_pointery())
|
|
|
|
|
|
def _popupPropertiesDialog(self):
|
|
WidgetPropertiesDialog.WidgetPropertiesDialog(
|
|
self.propertyDict,
|
|
propertyList = self.propertyList,
|
|
title = 'Widget Properties',
|
|
parent = self.interior())
|
|
|
|
def addPropertyToDialog(self, property, pDict):
|
|
self.propertyDict[property] = pDict
|
|
self.propertyList.append(property)
|
|
|
|
# Virtual functions to be redefined by subclass
|
|
def createValuator(self):
|
|
""" Function used by subclass to create valuator geometry """
|
|
pass
|
|
|
|
def packValuator(self):
|
|
""" Function used by subclass to pack widget """
|
|
pass
|
|
|
|
def addValuatorMenuEntries(self):
|
|
""" Function used by subclass to add menu entries to popup menu """
|
|
pass
|
|
|
|
def addValuatorPropertiesToDialog(self):
|
|
""" Function used by subclass to add properties to property dialog """
|
|
pass
|
|
|
|
|
|
FLOATER = 'floater'
|
|
DIAL = 'dial'
|
|
ANGLEDIAL = 'angledial'
|
|
SLIDER = 'slider'
|
|
|
|
class ValuatorGroup(Pmw.MegaWidget):
|
|
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 = ['v[%d]' % x for x in range(kw.get('dim', DEFAULT_DIM))]
|
|
|
|
#define the megawidget options
|
|
INITOPT = Pmw.INITOPT
|
|
optiondefs = (
|
|
('type', FLOATER, INITOPT),
|
|
('dim', DEFAULT_DIM, INITOPT),
|
|
('side', TOP, INITOPT),
|
|
# A list of initial values, one for each valuator
|
|
('value', DEFAULT_VALUE, INITOPT),
|
|
('min', None, INITOPT),
|
|
('max', None, INITOPT),
|
|
('resolution', None, INITOPT),
|
|
('numDigits', 2, self._setNumDigits),
|
|
# A tuple of labels, one for each valuator
|
|
('labels', DEFAULT_LABELS, self._updateLabels),
|
|
# The command to be executed when one of the valuators is updated
|
|
('command', None, None),
|
|
# Callbacks to execute when updating widget's value
|
|
('preCallback', None, None),
|
|
('postCallback', None, None),
|
|
# Extra data to be passed to callback function, needs to be a list
|
|
('callbackData', [], None),
|
|
)
|
|
self.defineoptions(kw, optiondefs)
|
|
|
|
# Initialize the toplevel widget
|
|
Pmw.MegaWidget.__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['value'])
|
|
|
|
# Create the valuators
|
|
self._valuatorList = []
|
|
for index in range(self['dim']):
|
|
# Add a group alias so you can configure the valuators via:
|
|
# fg.configure(Valuator_XXX = YYY)
|
|
if self['type'] == DIAL:
|
|
from . import Dial
|
|
valuatorType = Dial.Dial
|
|
elif self['type'] == ANGLEDIAL:
|
|
from . import Dial
|
|
valuatorType = Dial.AngleDial
|
|
elif self['type'] == SLIDER:
|
|
from . import Slider
|
|
valuatorType = Slider.Slider
|
|
else:
|
|
from . import Floater
|
|
valuatorType = Floater.Floater
|
|
f = self.createcomponent(
|
|
'valuator%d' % index, (), 'valuator', valuatorType,
|
|
(interior,), value = self._value[index],
|
|
min = self['min'], max = self['max'],
|
|
resolution = self['resolution'],
|
|
text = self['labels'][index],
|
|
command = lambda val, i = index: self._valuatorSetAt(i, val),
|
|
preCallback = self._preCallback,
|
|
postCallback = self._postCallback,
|
|
callbackData = [self],
|
|
)
|
|
f.pack(side = self['side'], expand = 1, fill = X)
|
|
self._valuatorList.append(f)
|
|
|
|
# Make sure valuators are initialized
|
|
self.set(self['value'], fCommand = 0)
|
|
|
|
# Make sure input variables processed
|
|
self.initialiseoptions(ValuatorGroup)
|
|
|
|
# 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 valuator, but don't execute its command
|
|
self._valuatorList[i].set(value[i], 0)
|
|
if fCommand and (self['command'] is not None):
|
|
self['command'](self._value)
|
|
|
|
def setAt(self, index, value):
|
|
# Update valuator and execute its command
|
|
self._valuatorList[index].set(value)
|
|
|
|
# This is the command used by the valuator
|
|
def _valuatorSetAt(self, index, value):
|
|
self._value[index] = value
|
|
if self['command']:
|
|
self['command'](self._value)
|
|
|
|
def get(self):
|
|
return self._value
|
|
|
|
def getAt(self, index):
|
|
return self._value[index]
|
|
|
|
def _setNumDigits(self):
|
|
self['valuator_numDigits'] = self['numDigits']
|
|
self.formatString = '%0.' + '%df' % self['numDigits']
|
|
|
|
def _updateLabels(self):
|
|
if self['labels']:
|
|
for index in range(self['dim']):
|
|
self._valuatorList[index]['text'] = self['labels'][index]
|
|
|
|
def _preCallback(self, valGroup):
|
|
# Execute pre callback
|
|
if self['preCallback']:
|
|
self['preCallback'](*valGroup.get())
|
|
|
|
def _postCallback(self, valGroup):
|
|
# Execute post callback
|
|
if self['postCallback']:
|
|
self['postCallback'](*valGroup.get())
|
|
|
|
def __len__(self):
|
|
return self['dim']
|
|
|
|
def __repr__(self):
|
|
str = '[' + self.formatString % self._value[0]
|
|
for val in self._value[1:]:
|
|
str += ', ' + self.formatString % val
|
|
str += ']'
|
|
return str
|
|
|
|
|
|
|
|
class ValuatorGroupPanel(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 = ['v[%d]' % x for x in range(kw.get('dim', DEFAULT_DIM))]
|
|
|
|
#define the megawidget options
|
|
INITOPT = Pmw.INITOPT
|
|
optiondefs = (
|
|
('type', FLOATER, INITOPT),
|
|
('dim', DEFAULT_DIM, INITOPT),
|
|
('side', TOP, INITOPT),
|
|
('title', 'Valuator Group', None),
|
|
# A list of initial values, one for each floater
|
|
('value', DEFAULT_VALUE, INITOPT),
|
|
('min', None, INITOPT),
|
|
('max', None, INITOPT),
|
|
('resolution', None, INITOPT),
|
|
# A tuple of labels, one for each floater
|
|
('labels', DEFAULT_LABELS, self._updateLabels),
|
|
('numDigits', 2, self._setNumDigits),
|
|
# The command to be executed when one of the floaters is updated
|
|
('command', None, self._setCommand),
|
|
# Callbacks to execute when updating widget's value
|
|
('preCallback', None, self._setPreCallback),
|
|
('postCallback', None, self._setPostCallback),
|
|
# Extra data to be passed to callback function, needs to be a list
|
|
('callbackData', [], self._setCallbackData),
|
|
# Destroy or withdraw
|
|
('fDestroy', 0, INITOPT)
|
|
)
|
|
self.defineoptions(kw, optiondefs)
|
|
|
|
# Initialize the toplevel widget
|
|
Pmw.MegaToplevel.__init__(self, parent)
|
|
|
|
# Create the components
|
|
interior = self.interior()
|
|
|
|
# The Menu Bar
|
|
self.balloon = Pmw.Balloon()
|
|
menubar = self.createcomponent('menubar', (), None,
|
|
Pmw.MenuBar, (interior,),
|
|
balloon = self.balloon)
|
|
menubar.pack(fill=X)
|
|
|
|
# ValuatorGroup Menu
|
|
menubar.addmenu('Valuator Group', 'Valuator Group Operations')
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command', 'Reset the Valuator Group panel',
|
|
label = 'Reset',
|
|
command = lambda s = self: s.reset())
|
|
|
|
if self['fDestroy']:
|
|
dismissCommand = self.destroy
|
|
else:
|
|
dismissCommand = self.withdraw
|
|
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command', 'Dismiss Valuator Group panel',
|
|
label = 'Dismiss', command = dismissCommand)
|
|
|
|
menubar.addmenu('Help', 'Valuator 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)
|
|
|
|
# Create the valuator group
|
|
self.valuatorGroup = self.createcomponent(
|
|
'valuatorGroup',
|
|
(('valuator', 'valuatorGroup_valuator'),),
|
|
None, ValuatorGroup,
|
|
(interior,),
|
|
type = self['type'],
|
|
dim = self['dim'],
|
|
value = self['value'],
|
|
min = self['min'],
|
|
max = self['max'],
|
|
resolution = self['resolution'],
|
|
labels = self['labels'],
|
|
command = self['command'])
|
|
self.valuatorGroup.pack(expand = 1, fill = X)
|
|
|
|
# Make sure input variables processed
|
|
self.initialiseoptions(ValuatorGroupPanel)
|
|
|
|
def toggleBalloon(self):
|
|
if self.toggleBalloonVar.get():
|
|
self.balloon.configure(state = 'balloon')
|
|
else:
|
|
self.balloon.configure(state = 'none')
|
|
|
|
def _updateLabels(self):
|
|
self.valuatorGroup['labels'] = self['labels']
|
|
|
|
def _setNumDigits(self):
|
|
self.valuatorGroup['numDigits'] = self['numDigits']
|
|
|
|
def _setCommand(self):
|
|
self.valuatorGroup['command'] = self['command']
|
|
|
|
def _setPreCallback(self):
|
|
self.valuatorGroup['preCallback'] = self['preCallback']
|
|
|
|
def _setPostCallback(self):
|
|
self.valuatorGroup['postCallback'] = self['postCallback']
|
|
|
|
def _setCallbackData(self):
|
|
self.valuatorGroup['callbackData'] = self['callbackData']
|
|
|
|
def reset(self):
|
|
self.set(self['value'])
|
|
|
|
Pmw.forwardmethods(ValuatorGroupPanel, ValuatorGroup, 'valuatorGroup')
|
|
|
|
|
|
def rgbPanel(nodePath, callback = None, style = 'mini'):
|
|
def onRelease(r, g, b, a, nodePath = nodePath):
|
|
messenger.send('RGBPanel_setColor', [nodePath, r, g, b, a])
|
|
|
|
def popupColorPicker():
|
|
# Can pass in current color with: color = (255, 0, 0)
|
|
color = askcolor(
|
|
parent = vgp.interior(),
|
|
# Initialize it to current color
|
|
initialcolor = tuple(vgp.get()[:3]))[0]
|
|
if color:
|
|
vgp.set((color[0], color[1], color[2], vgp.getAt(3)))
|
|
|
|
def printToLog():
|
|
c=nodePath.getColor()
|
|
print("Vec4(%.3f, %.3f, %.3f, %.3f)"%(c[0], c[1], c[2], c[3]))
|
|
|
|
# Check init color
|
|
if nodePath.hasColor():
|
|
initColor = nodePath.getColor() * 255.0
|
|
else:
|
|
initColor = Vec4(255)
|
|
# Create entry scale group
|
|
vgp = ValuatorGroupPanel(title = 'RGBA Panel: ' + nodePath.getName(),
|
|
dim = 4,
|
|
labels = ['R','G','B','A'],
|
|
value = [int(initColor[0]),
|
|
int(initColor[1]),
|
|
int(initColor[2]),
|
|
int(initColor[3])],
|
|
type = 'slider',
|
|
valuator_style = style,
|
|
valuator_min = 0,
|
|
valuator_max = 255,
|
|
valuator_resolution = 1,
|
|
# Destroy not withdraw panel on dismiss
|
|
fDestroy = 1)
|
|
# Update menu button
|
|
vgp.component('menubar').component('Valuator Group-button')['text'] = (
|
|
'RGBA Panel')
|
|
|
|
# Set callback
|
|
vgp['postCallback'] = onRelease
|
|
|
|
# Add a print button which will also serve as a color tile
|
|
pButton = Button(vgp.interior(), text = 'Print to Log',
|
|
bg = getTkColorString(initColor),
|
|
command = printToLog)
|
|
pButton.pack(expand = 1, fill = BOTH)
|
|
|
|
# Update menu
|
|
menubar = vgp.component('menubar')
|
|
menubar.deletemenuitems('Valuator Group', 1, 1)
|
|
|
|
# Some helper functions
|
|
# Clear color
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command',
|
|
label='Clear Color', command=lambda: nodePath.clearColor())
|
|
# Set Clear Transparency
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command',
|
|
label='Set Transparency', command=lambda: nodePath.setTransparency(1))
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command',
|
|
label='Clear Transparency', command=lambda: nodePath.clearTransparency())
|
|
|
|
|
|
# System color picker
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command',
|
|
label='Popup Color Picker', command=popupColorPicker)
|
|
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command',
|
|
label='Print to log', command=printToLog)
|
|
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command', 'Dismiss Valuator Group panel',
|
|
label='Dismiss', command=vgp.destroy)
|
|
|
|
def setNodePathColor(color):
|
|
nodePath.setColor(color[0]/255.0, color[1]/255.0,
|
|
color[2]/255.0, color[3]/255.0)
|
|
# Update color chip button
|
|
pButton['bg'] = getTkColorString(color)
|
|
# Execute callback to pass along color info
|
|
if callback:
|
|
callback(color)
|
|
vgp['command'] = setNodePathColor
|
|
|
|
return vgp
|
|
|
|
|
|
def lightRGBPanel(light, style = 'mini'):
|
|
# Color picker for lights
|
|
def popupColorPicker():
|
|
# Can pass in current color with: color = (255, 0, 0)
|
|
color = askcolor(
|
|
parent = vgp.interior(),
|
|
# Initialize it to current color
|
|
initialcolor = tuple(vgp.get()[:3]))[0]
|
|
if color:
|
|
vgp.set((color[0], color[1], color[2], vgp.getAt(3)))
|
|
def printToLog():
|
|
n = light.getName()
|
|
c=light.getColor()
|
|
print(n + (".setColor(Vec4(%.3f, %.3f, %.3f, %.3f))" %
|
|
(c[0], c[1], c[2], c[3])))
|
|
# Check init color
|
|
initColor = light.getColor() * 255.0
|
|
# Create entry scale group
|
|
vgp = ValuatorGroupPanel(title = 'RGBA Panel: ' + light.getName(),
|
|
dim = 4,
|
|
labels = ['R','G','B','A'],
|
|
value = [int(initColor[0]),
|
|
int(initColor[1]),
|
|
int(initColor[2]),
|
|
int(initColor[3])],
|
|
type = 'slider',
|
|
valuator_style = style,
|
|
valuator_min = 0,
|
|
valuator_max = 255,
|
|
valuator_resolution = 1,
|
|
# Destroy not withdraw panel on dismiss
|
|
fDestroy = 1)
|
|
# Update menu button
|
|
vgp.component('menubar').component('Valuator Group-button')['text'] = (
|
|
'Light Control Panel')
|
|
|
|
# Add a print button which will also serve as a color tile
|
|
pButton = Button(vgp.interior(), text = 'Print to Log',
|
|
bg = getTkColorString(initColor),
|
|
command = printToLog)
|
|
pButton.pack(expand = 1, fill = BOTH)
|
|
|
|
# Update menu
|
|
menubar = vgp.component('menubar')
|
|
# System color picker
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command',
|
|
label='Popup Color Picker', command=popupColorPicker)
|
|
menubar.addmenuitem(
|
|
'Valuator Group', 'command',
|
|
label='Print to log', command=printToLog)
|
|
|
|
def setLightColor(color):
|
|
light.setColor(Vec4(color[0]/255.0, color[1]/255.0,
|
|
color[2]/255.0, color[3]/255.0))
|
|
# Update color chip button
|
|
pButton['bg'] = getTkColorString(color)
|
|
vgp['command'] = setLightColor
|
|
return vgp
|
|
|