mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-11-01 01:07:54 +00:00
651 lines
25 KiB
Python
651 lines
25 KiB
Python
"""
|
|
UI for object property control
|
|
"""
|
|
import wx
|
|
import os
|
|
import math
|
|
|
|
from wx.lib.embeddedimage import PyEmbeddedImage
|
|
from wx.lib.scrolledpanel import ScrolledPanel
|
|
from wx.lib.agw.cubecolourdialog import *
|
|
from direct.wxwidgets.WxSlider import *
|
|
from pandac.PandaModules import *
|
|
import ObjectGlobals as OG
|
|
import AnimGlobals as AG
|
|
|
|
#----------------------------------------------------------------------
|
|
Key = PyEmbeddedImage(
|
|
"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAIAAACQKrqGAAAAA3NCSVQICAjb4U/gAAABIElE"
|
|
"QVQokZWSMW7CQBBFZ2Z3sQ02Ni4sOS6QiLgO5yBXIMcJ1KENje8QLESH7F3FVFQIIS3eTWGJ"
|
|
"VE7Iq6Z4+tL8GVRSwmPQg94fKiIOBoNer2et/U1FRER8X6+LonBdFwB4l+p53mq1qqRUUsZx"
|
|
"nKYpBwDOuRACEQGgaRoAYETn8/l4PL4uFkqp/X6fZRlnjO12u7KqENEa43keADDGvuo6Go0A"
|
|
"wPd9YkxrzY0x4/FYKlXX9eVymc1mjIiIgiD43G4BwFprmgYRubU2DMPnySTw/ev1+pSmRISI"
|
|
"SZJ8bDan06ksSyLiQmDXCfr9fp7nb8vldDp9mc9d1/1R27XaClscxzkcDlEUhcOhvt06U1uE"
|
|
"EMaYtpbOXlu01vf5Hz/wDRuDdIDl5WtQAAAAAElFTkSuQmCC")
|
|
#----------------------------------------------------------------------
|
|
|
|
class AnimFileDrop(wx.FileDropTarget):
|
|
def __init__(self, editor):
|
|
wx.FileDropTarget.__init__(self)
|
|
self.editor = editor
|
|
|
|
def OnDropFiles(self, x, y, filenames):
|
|
obj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
|
|
if obj is None:
|
|
return
|
|
|
|
objDef = obj[OG.OBJ_DEF]
|
|
if not objDef.actor:
|
|
return
|
|
|
|
objNP = obj[OG.OBJ_NP]
|
|
|
|
for filename in filenames:
|
|
name = os.path.basename(filename)
|
|
animName = Filename.fromOsSpecific(filename).getFullpath()
|
|
if name.endswith('.mb') or\
|
|
name.endswith('.ma'):
|
|
self.editor.convertMaya(animName, self.editor.ui.protoPaletteUI.addNewItem, obj, isAnim=True)
|
|
return
|
|
|
|
if animName not in objDef.anims:
|
|
objDef.anims.append(animName)
|
|
|
|
objNP.loadAnims({name:animName})
|
|
objNP.loop(name)
|
|
obj[OG.OBJ_ANIM] = animName
|
|
self.editor.ui.objectPropertyUI.updateProps(obj)
|
|
|
|
class ObjectPropUI(wx.Panel):
|
|
"""
|
|
Base class for ObjectPropUIs,
|
|
It consists of label area and ui area.
|
|
"""
|
|
def __init__(self, parent, label):
|
|
wx.Panel.__init__(self, parent)
|
|
self.parent = parent
|
|
self.labelPane = wx.Panel(self)
|
|
self.label = wx.StaticText(self.labelPane, label=label)
|
|
self.labelSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
self.labelSizer.Add(self.label)
|
|
bmpKey = Key.GetBitmap()
|
|
self.setKeyButton = wx.BitmapButton(self.labelPane, -1, bmpKey, size = (15,15),style = wx.BU_AUTODRAW)
|
|
self.labelSizer.Add(self.setKeyButton)
|
|
self.labelPane.SetSizer(self.labelSizer)
|
|
self.uiPane = wx.Panel(self)
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
sizer.Add(self.labelPane)
|
|
sizer.Add(self.uiPane, 1, wx.EXPAND, 0)
|
|
self.SetSizer(sizer)
|
|
|
|
self.setKeyButton.Bind(wx.EVT_BUTTON, self.onKey)
|
|
|
|
def onKey(self,evt):
|
|
self.parent = wx.GetTopLevelParent(self)
|
|
if self.parent.editor.mode == self.parent.editor.ANIM_MODE:
|
|
obj= self.parent.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
|
|
|
|
objUID = obj[OG.OBJ_UID]
|
|
propertyName = self.label.GetLabelText()
|
|
|
|
value = self.getValue()
|
|
frame = self.parent.editor.ui.animUI.curFrame
|
|
|
|
if (objUID, propertyName) in self.parent.editor.animMgr.keyFramesInfo:
|
|
for i in range(len(self.parent.editor.animMgr.keyFramesInfo[(objUID,propertyName)])):
|
|
if self.parent.editor.animMgr.keyFramesInfo[(objUID,propertyName)][i][AG.FRAME] == frame:
|
|
del self.parent.editor.animMgr.keyFramesInfo[(objUID,propertyName)][i]
|
|
self.parent.editor.animMgr.keyFramesInfo[(objUID,propertyName)].append([frame, value, [], []])
|
|
#sort keyFrameInfo list by the order of frame number
|
|
sortKeyList = self.parent.editor.animMgr.keyFramesInfo[(objUID,propertyName)]
|
|
for i in range(0, len(sortKeyList)-1):
|
|
for j in range(i+1, len(sortKeyList)):
|
|
if sortKeyList[i][AG.FRAME]>sortKeyList[j][AG.FRAME]:
|
|
temp = sortKeyList[i]
|
|
sortKeyList[i] = sortKeyList[j]
|
|
sortKeyList[j] = temp
|
|
|
|
self.parent.editor.animMgr.generateSlope(self.parent.editor.animMgr.keyFramesInfo[(objUID,propertyName)])
|
|
else:
|
|
self.parent.editor.animMgr.keyFramesInfo[(objUID,propertyName)] = [[frame, value, [], []]]
|
|
|
|
exist = False
|
|
for keyFrame in self.parent.editor.animMgr.keyFrames:
|
|
if frame == keyFrame:
|
|
exist = True
|
|
break
|
|
|
|
if exist == False:
|
|
self.parent.editor.animMgr.keyFrames.append(frame)
|
|
self.parent.editor.ui.animUI.OnPropKey()
|
|
|
|
else:
|
|
self.parent.editor.ui.animUI.OnPropKey()
|
|
|
|
else:
|
|
evt.Skip()
|
|
|
|
def setValue(self, value):
|
|
self.ui.SetValue(value)
|
|
|
|
def getValue(self):
|
|
return self.ui.GetValue()
|
|
|
|
def bindFunc(self, inFunc, outFunc, valFunc = None):
|
|
self.ui.Bind(wx.EVT_ENTER_WINDOW, inFunc)
|
|
self.ui.Bind(wx.EVT_LEAVE_WINDOW, outFunc)
|
|
if valFunc:
|
|
self.ui.Bind(self.eventType, valFunc)
|
|
|
|
class ObjectPropUIEntry(ObjectPropUI):
|
|
""" UI for string value properties """
|
|
def __init__(self, parent, label):
|
|
ObjectPropUI.__init__(self, parent, label)
|
|
self.ui = wx.TextCtrl(self.uiPane, -1)
|
|
self.eventType = wx.EVT_TEXT_ENTER
|
|
self.Layout()
|
|
|
|
def setValue(self, value):
|
|
self.ui.SetValue(str(value))
|
|
|
|
class ObjectPropUISlider(ObjectPropUI):
|
|
""" UI for float value properties """
|
|
def __init__(self, parent, label, value, minValue, maxValue):
|
|
ObjectPropUI.__init__(self, parent, label)
|
|
self.ui = WxSlider(self.uiPane, -1, value, minValue, maxValue,
|
|
pos = (0,0), size=(140, -1),
|
|
style=wx.SL_HORIZONTAL | wx.SL_LABELS)
|
|
self.ui.Enable()
|
|
self.Layout()
|
|
|
|
def bindFunc(self, inFunc, outFunc, valFunc = None):
|
|
self.ui.Bind(wx.EVT_ENTER_WINDOW, inFunc)
|
|
self.ui.Bind(wx.EVT_LEAVE_WINDOW, outFunc)
|
|
self.ui.textValue.Bind(wx.EVT_ENTER_WINDOW, inFunc)
|
|
self.ui.textValue.Bind(wx.EVT_LEAVE_WINDOW, outFunc)
|
|
|
|
if valFunc:
|
|
self.ui.bindFunc(valFunc)
|
|
|
|
|
|
class ObjectPropUISpinner(ObjectPropUI):
|
|
""" UI for int value properties """
|
|
def __init__(self, parent, label, value, minValue, maxValue):
|
|
ObjectPropUI.__init__(self, parent, label)
|
|
self.ui = wx.SpinCtrl(self.uiPane, -1, "", min=minValue, max=maxValue, initial=value)
|
|
self.eventType = wx.EVT_SPIN
|
|
self.Layout()
|
|
|
|
|
|
class ObjectPropUICheck(ObjectPropUI):
|
|
def __init__(self, parent, label, value):
|
|
ObjectPropUI.__init__(self, parent, label)
|
|
self.ui = wx.CheckBox(self.uiPane, -1, "", size=(50, 30))
|
|
self.setValue(value)
|
|
self.eventType = wx.EVT_CHECKBOX
|
|
self.Layout()
|
|
|
|
|
|
class ObjectPropUIRadio(ObjectPropUI):
|
|
def __init__(self, parent, label, value, valueList):
|
|
ObjectPropUI.__init__(self, parent, label)
|
|
self.ui = wx.RadioBox(self.uiPane, -1, "", choices=valueList, majorDimension=1, style=wx.RA_SPECIFY_COLS)
|
|
self.setValue(value)
|
|
self.eventType = wx.EVT_RADIOBOX
|
|
self.Layout()
|
|
|
|
def setValue(self, value):
|
|
self.ui.SetStringSelection(value)
|
|
|
|
def getValue(self):
|
|
return self.ui.GetStringSelection()
|
|
|
|
|
|
class ObjectPropUICombo(ObjectPropUI):
|
|
def __init__(self, parent, label, value, valueList, obj=None, callBack=None):
|
|
ObjectPropUI.__init__(self, parent, label)
|
|
self.ui = wx.Choice(self.uiPane, -1, choices=valueList)
|
|
if callBack is not None:
|
|
button = wx.Button(self.labelPane, -1, 'Update', size = (100, 18))
|
|
button.Bind(wx.EVT_BUTTON, lambda p0=None, p1=obj, p2=self: callBack(p0, p1, p2))
|
|
self.labelSizer.Add(button)
|
|
self.setValue(value)
|
|
self.eventType = wx.EVT_CHOICE
|
|
self.Layout()
|
|
|
|
def setValue(self, value):
|
|
self.ui.SetStringSelection(value)
|
|
|
|
def getValue(self):
|
|
return self.ui.GetStringSelection()
|
|
|
|
def setItems(self, valueList):
|
|
self.ui.SetItems(valueList)
|
|
|
|
class ObjectPropUITime(wx.Panel):
|
|
def __init__(self, parent, label, value):
|
|
wx.Panel.__init__(self, parent)
|
|
self.parent = parent
|
|
self.labelPane = wx.Panel(self)
|
|
self.label = wx.StaticText(self.labelPane, label=label)
|
|
self.labelSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
self.labelSizer.Add(self.label)
|
|
self.labelPane.SetSizer(self.labelSizer)
|
|
self.uiPane = wx.Panel(self)
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
sizer.Add(self.labelPane)
|
|
sizer.Add(self.uiPane, 1, wx.EXPAND, 0)
|
|
self.SetSizer(sizer)
|
|
|
|
hSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
self.uiAmPm = wx.Choice(self.uiPane, -1, choices=['AM', 'PM'])
|
|
self.uiHour = wx.Choice(self.uiPane, -1, choices=[str(x) for x in range(1, 13)])
|
|
self.uiMin = wx.Choice(self.uiPane, -1, choices=[str(x) for x in range(0, 60, 15)])
|
|
|
|
hSizer.Add(self.uiAmPm)
|
|
hSizer.Add(self.uiHour)
|
|
hSizer.Add(self.uiMin)
|
|
self.uiPane.SetSizer(hSizer)
|
|
|
|
self.setValue(value)
|
|
self.eventType = wx.EVT_CHOICE
|
|
self.Layout()
|
|
|
|
def setValue(self, value):
|
|
hourVal = int(math.floor(value))
|
|
minVal = [0, 15, 30, 45][int((value - hourVal) * 4)]
|
|
|
|
if hourVal > 11:
|
|
ampmStr = 'PM'
|
|
hourVal = hourVal - 12
|
|
else:
|
|
ampmStr = 'AM'
|
|
|
|
if hourVal == 0:
|
|
hourVal = 12
|
|
|
|
self.uiAmPm.SetStringSelection(ampmStr)
|
|
self.uiHour.SetStringSelection(str(hourVal))
|
|
self.uiMin.SetStringSelection(str(minVal))
|
|
|
|
def getValue(self):
|
|
ampmStr = self.uiAmPm.GetStringSelection()
|
|
hourVal = int(self.uiHour.GetStringSelection())
|
|
if hourVal == 12:
|
|
hourVal = 0
|
|
if ampmStr == 'PM':
|
|
hourVal += 12
|
|
|
|
minVal = float(self.uiMin.GetStringSelection())
|
|
value = float(hourVal) + minVal / 60.0
|
|
return value
|
|
|
|
def bindFunc(self, inFunc, outFunc, valFunc = None):
|
|
self.uiAmPm.Bind(wx.EVT_ENTER_WINDOW, inFunc)
|
|
self.uiAmPm.Bind(wx.EVT_LEAVE_WINDOW, outFunc)
|
|
self.uiHour.Bind(wx.EVT_ENTER_WINDOW, inFunc)
|
|
self.uiHour.Bind(wx.EVT_LEAVE_WINDOW, outFunc)
|
|
self.uiMin.Bind(wx.EVT_ENTER_WINDOW, inFunc)
|
|
self.uiMin.Bind(wx.EVT_LEAVE_WINDOW, outFunc)
|
|
if valFunc:
|
|
self.uiAmPm.Bind(self.eventType, valFunc)
|
|
self.uiHour.Bind(self.eventType, valFunc)
|
|
self.uiMin.Bind(self.eventType, valFunc)
|
|
|
|
class ColorPicker(CubeColourDialog):
|
|
def __init__(self, parent, colourData=None, style=CCD_SHOW_ALPHA, alpha = 255, updateCB=None, exitCB=None):
|
|
self.updateCB=updateCB
|
|
CubeColourDialog.__init__(self, parent, colourData, style)
|
|
self.okButton.Hide()
|
|
self.cancelButton.Hide()
|
|
self._colour.alpha = alpha
|
|
self.alphaSpin.SetValue(self._colour.alpha)
|
|
self.DrawAlpha()
|
|
if exitCB:
|
|
self.Bind(wx.EVT_CLOSE, exitCB)
|
|
|
|
def SetPanelColours(self):
|
|
self.oldColourPanel.RefreshColour(self._oldColour)
|
|
self.newColourPanel.RefreshColour(self._colour)
|
|
if self.updateCB:
|
|
self.updateCB(self._colour.r, self._colour.g, self._colour.b, self._colour.alpha)
|
|
|
|
class ObjectPropertyUI(ScrolledPanel):
|
|
def __init__(self, parent, editor):
|
|
self.editor = editor
|
|
self.colorPicker = None
|
|
self.lastColorPickerPos = None
|
|
self.lastPropTab = None
|
|
ScrolledPanel.__init__(self, parent)
|
|
|
|
parentSizer = wx.BoxSizer(wx.VERTICAL)
|
|
parentSizer.Add(self, 1, wx.EXPAND, 0)
|
|
parent.SetSizer(parentSizer); parent.Layout()
|
|
|
|
self.SetDropTarget(AnimFileDrop(self.editor))
|
|
|
|
def clearPropUI(self):
|
|
sizer = self.GetSizer()
|
|
if sizer is not None:
|
|
self.lastPropTab = self.nb.GetCurrentPage().GetName()
|
|
sizer.Remove(self.propPane)
|
|
self.propPane.Destroy()
|
|
self.SetSizer(None)
|
|
self.Layout()
|
|
self.SetupScrolling(self, scroll_y = True, rate_y = 20)
|
|
|
|
def colorPickerExitCB(self, evt=None):
|
|
self.lastColorPickerPos = self.colorPicker.GetPosition()
|
|
self.colorPicker.Destroy()
|
|
self.colorPicker = None
|
|
|
|
def colorPickerUpdateCB(self, rr, gg, bb, aa):
|
|
r = rr / 255.0
|
|
g = gg / 255.0
|
|
b = bb / 255.0
|
|
a = aa / 255.0
|
|
self.propCR.setValue(r)
|
|
self.propCG.setValue(g)
|
|
self.propCB.setValue(b)
|
|
self.propCA.setValue(a)
|
|
|
|
self.editor.objectMgr.updateObjectColor(r, g, b, a)
|
|
|
|
def onColorSlider(self, evt):
|
|
r = float(self.editor.ui.objectPropertyUI.propCR.getValue())
|
|
g = float(self.editor.ui.objectPropertyUI.propCG.getValue())
|
|
b = float(self.editor.ui.objectPropertyUI.propCB.getValue())
|
|
a = float(self.editor.ui.objectPropertyUI.propCA.getValue())
|
|
|
|
if self.colorPicker:
|
|
evtObj = evt.GetEventObject()
|
|
if evtObj == self.propCR.ui or\
|
|
evtObj == self.propCR.ui.textValue:
|
|
self.colorPicker.redSpin.SetValue(r * 255)
|
|
self.colorPicker.AssignColourValue('r', r * 255, 255, 0)
|
|
elif evtObj == self.propCG.ui or\
|
|
evtObj == self.propCG.ui.textValue:
|
|
self.colorPicker.greenSpin.SetValue(g * 255)
|
|
self.colorPicker.AssignColourValue('g', g * 255, 255, 0)
|
|
elif evtObj == self.propCB.ui or\
|
|
evtObj == self.propCB.ui.textValue:
|
|
self.colorPicker.blueSpin.SetValue(b * 255)
|
|
self.colorPicker.AssignColourValue('b', b * 255, 255, 0)
|
|
else:
|
|
self.colorPicker._colour.alpha = a * 255
|
|
self.colorPicker.alphaSpin.SetValue(self.colorPicker._colour.alpha)
|
|
self.colorPicker.DrawAlpha()
|
|
|
|
self.editor.objectMgr.updateObjectColor(r, g, b, a)
|
|
|
|
def openColorPicker(self, evt, colourData, alpha):
|
|
if self.colorPicker:
|
|
self.lastColorPickerPos = self.colorPicker.GetPosition()
|
|
self.colorPicker.Destroy()
|
|
|
|
self.colorPicker = ColorPicker(self, colourData, alpha=alpha, updateCB=self.colorPickerUpdateCB, exitCB=self.colorPickerExitCB)
|
|
self.colorPicker.GetColourData().SetChooseFull(True)
|
|
self.colorPicker.Show()
|
|
if self.lastColorPickerPos:
|
|
self.colorPicker.SetPosition(self.lastColorPickerPos)
|
|
|
|
def updateProps(self, obj, movable=True):
|
|
self.clearPropUI()
|
|
|
|
self.propPane = wx.Panel(self)
|
|
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
|
mainSizer.Add(self.propPane, 1, wx.EXPAND, 0)
|
|
self.SetSizer(mainSizer)
|
|
|
|
self.nb = wx.Notebook(self.propPane, style=wx.NB_BOTTOM)
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
sizer.Add(self.nb, 1, wx.EXPAND)
|
|
self.propPane.SetSizer(sizer)
|
|
|
|
self.transformPane = wx.Panel(self.nb, -1, name='Transform')
|
|
self.nb.AddPage(self.transformPane, 'Transform')
|
|
|
|
self.propX = ObjectPropUIEntry(self.transformPane, 'X')
|
|
self.propY = ObjectPropUIEntry(self.transformPane, 'Y')
|
|
self.propZ = ObjectPropUIEntry(self.transformPane, 'Z')
|
|
|
|
self.propH = ObjectPropUISlider(self.transformPane, 'H', 0, 0, 360)
|
|
self.propP = ObjectPropUISlider(self.transformPane, 'P', 0, 0, 360)
|
|
self.propR = ObjectPropUISlider(self.transformPane, 'R', 0, 0, 360)
|
|
|
|
self.propSX = ObjectPropUIEntry(self.transformPane, 'SX')
|
|
self.propSY = ObjectPropUIEntry(self.transformPane, 'SY')
|
|
self.propSZ = ObjectPropUIEntry(self.transformPane, 'SZ')
|
|
|
|
transformProps = [self.propX, self.propY, self.propZ, self.propH, self.propP, self.propR,
|
|
self.propSX, self.propSY, self.propSZ]
|
|
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
sizer.AddMany(transformProps)
|
|
self.transformPane.SetSizer(sizer)
|
|
for transformProp in transformProps:
|
|
transformProp.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
|
|
self.editor.objectMgr.onLeaveObjectPropUI,
|
|
self.editor.objectMgr.updateObjectTransform)
|
|
|
|
if not movable:
|
|
for transformProp in transformProps:
|
|
transformProp.ui.Disable()
|
|
|
|
self.lookPane = wx.Panel(self.nb, -1, name='Look')
|
|
self.nb.AddPage(self.lookPane, 'Look')
|
|
|
|
objNP = obj[OG.OBJ_NP]
|
|
objRGBA = obj[OG.OBJ_RGBA]
|
|
self.propCR = ObjectPropUISlider(self.lookPane, 'CR', objRGBA[0], 0, 1)
|
|
self.propCG = ObjectPropUISlider(self.lookPane, 'CG', objRGBA[1], 0, 1)
|
|
self.propCB = ObjectPropUISlider(self.lookPane, 'CB', objRGBA[2], 0, 1)
|
|
self.propCA = ObjectPropUISlider(self.lookPane, 'CA', objRGBA[3], 0, 1)
|
|
colorProps = [self.propCR, self.propCG, self.propCB, self.propCA]
|
|
|
|
for colorProp in colorProps:
|
|
colorProp.ui.bindFunc(self.onColorSlider)
|
|
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
sizer.AddMany(colorProps)
|
|
button = wx.Button(self.lookPane, -1, 'Color Picker', (0,0), (140, 20))
|
|
_colourData = wx.ColourData()
|
|
_colourData.SetColour(wx.Colour(objRGBA[0] * 255, objRGBA[1] * 255, objRGBA[2] * 255))
|
|
button.Bind(wx.EVT_BUTTON, lambda p0=None, p1=_colourData, p2=objRGBA[3] * 255: self.openColorPicker(p0, p1, p2))
|
|
|
|
sizer.Add(button)
|
|
|
|
if self.colorPicker:
|
|
self.openColorPicker(None, _colourData, objRGBA[3] * 255)
|
|
|
|
objDef = obj[OG.OBJ_DEF]
|
|
|
|
if objDef.updateModelFunction is not None or (objDef.model is not None and len(objDef.models) > 0):
|
|
defaultModel = obj[OG.OBJ_MODEL]
|
|
if defaultModel is None:
|
|
defaultModel = ''
|
|
|
|
if len(objDef.models) == 0:
|
|
modelList = ''
|
|
else:
|
|
modelList = objDef.models
|
|
propUI = ObjectPropUICombo(self.lookPane, 'model', defaultModel, modelList, obj, callBack=objDef.updateModelFunction)
|
|
sizer.Add(propUI)
|
|
|
|
propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
|
|
self.editor.objectMgr.onLeaveObjectPropUI,
|
|
lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectModelFromUI(p0, p1))
|
|
|
|
animList = objDef.animDict.get(obj[OG.OBJ_MODEL])
|
|
if len(objDef.anims) > 0 or animList:
|
|
if animList is None:
|
|
animList = objDef.anims
|
|
|
|
propUI = ObjectPropUICombo(self.lookPane, 'anim', obj[OG.OBJ_ANIM], animList)
|
|
sizer.Add(propUI)
|
|
|
|
propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
|
|
self.editor.objectMgr.onLeaveObjectPropUI,
|
|
lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectAnimFromUI(p0, p1))
|
|
|
|
self.lookPane.SetSizer(sizer)
|
|
|
|
self.propsPane = wx.Panel(self.nb, -1, name='Properties')
|
|
self.nb.AddPage(self.propsPane, 'Properties')
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
propNames = objDef.orderedProperties[:]
|
|
for key in objDef.properties.keys():
|
|
if key not in propNames:
|
|
propNames.append(key)
|
|
|
|
for key in propNames:
|
|
# handling properties mask
|
|
propMask = BitMask32()
|
|
for modeKey in objDef.propertiesMask.keys():
|
|
if key in objDef.propertiesMask[modeKey]:
|
|
propMask |= modeKey
|
|
|
|
if not propMask.isZero():
|
|
if (self.editor.mode & propMask).isZero():
|
|
continue
|
|
|
|
propDef = objDef.properties[key]
|
|
propType = propDef[OG.PROP_TYPE]
|
|
propDataType = propDef[OG.PROP_DATATYPE]
|
|
value = obj[OG.OBJ_PROP].get(key)
|
|
|
|
if propType == OG.PROP_UI_ENTRY:
|
|
propUI = ObjectPropUIEntry(self.propsPane, key)
|
|
propUI.setValue(value)
|
|
sizer.Add(propUI)
|
|
|
|
elif propType == OG.PROP_UI_SLIDE:
|
|
if len(propDef) <= OG.PROP_RANGE:
|
|
continue
|
|
propRange = propDef[OG.PROP_RANGE]
|
|
|
|
if value is None:
|
|
continue
|
|
|
|
if propDataType != OG.PROP_FLOAT:
|
|
value = float(value)
|
|
|
|
propUI = ObjectPropUISlider(self.propsPane, key, value, propRange[OG.RANGE_MIN], propRange[OG.RANGE_MAX])
|
|
sizer.Add(propUI)
|
|
|
|
elif propType == OG.PROP_UI_SPIN:
|
|
if len(propDef) <= OG.PROP_RANGE:
|
|
continue
|
|
propRange = propDef[OG.PROP_RANGE]
|
|
|
|
if value is None:
|
|
continue
|
|
|
|
propUI = ObjectPropUISpinner(self.propsPane, key, value, propRange[OG.RANGE_MIN], propRange[OG.RANGE_MAX])
|
|
sizer.Add(propUI)
|
|
|
|
elif propType == OG.PROP_UI_CHECK:
|
|
if value is None:
|
|
continue
|
|
|
|
propUI = ObjectPropUICheck(self.propsPane, key, value)
|
|
sizer.Add(propUI)
|
|
|
|
elif propType == OG.PROP_UI_RADIO:
|
|
if len(propDef) <= OG.PROP_RANGE:
|
|
continue
|
|
propRange = propDef[OG.PROP_RANGE]
|
|
|
|
if value is None:
|
|
continue
|
|
|
|
if propDataType != OG.PROP_STR:
|
|
for i in range(len(propRange)):
|
|
propRange[i] = str(propRange[i])
|
|
|
|
value = str(value)
|
|
|
|
propUI = ObjectPropUIRadio(self.propsPane, key, value, propRange)
|
|
sizer.Add(propUI)
|
|
|
|
elif propType == OG.PROP_UI_COMBO:
|
|
if len(propDef) <= OG.PROP_RANGE:
|
|
continue
|
|
propRange = propDef[OG.PROP_RANGE]
|
|
|
|
if value is None:
|
|
continue
|
|
|
|
if propDataType != OG.PROP_STR:
|
|
for i in range(len(propRange)):
|
|
propRange[i] = str(propRange[i])
|
|
|
|
value = str(value)
|
|
|
|
propUI = ObjectPropUICombo(self.propsPane, key, value, propRange)
|
|
sizer.Add(propUI)
|
|
|
|
elif propType == OG.PROP_UI_COMBO_DYNAMIC:
|
|
if len(propDef) <= OG.PROP_DYNAMIC_KEY:
|
|
continue
|
|
|
|
propDynamicKey = propDef[OG.PROP_DYNAMIC_KEY]
|
|
if propDynamicKey == OG.PROP_MODEL:
|
|
dynamicRangeKey = obj[OG.OBJ_MODEL]
|
|
else:
|
|
dynamicRangeKey = obj[OG.OBJ_PROP].get(propDynamicKey)
|
|
|
|
if dynamicRangeKey is None:
|
|
self.editor.objectMgr.updateObjectPropValue(obj, key, propDef[OG.PROP_DEFAULT], fUndo=False)
|
|
continue
|
|
|
|
propRange = propDef[OG.PROP_RANGE].get(dynamicRangeKey)
|
|
|
|
if propRange is None:
|
|
self.editor.objectMgr.updateObjectPropValue(obj, key, propDef[OG.PROP_DEFAULT], fUndo=False)
|
|
continue
|
|
|
|
if value is None:
|
|
continue
|
|
|
|
if propDataType != OG.PROP_STR:
|
|
for i in range(len(propRange)):
|
|
propRange[i] = str(propRange[i])
|
|
|
|
value = str(value)
|
|
|
|
if value not in propRange:
|
|
value = propRange[0]
|
|
self.editor.objectMgr.updateObjectPropValue(obj, key, value, fUndo=False)
|
|
|
|
propUI = ObjectPropUICombo(self.propsPane, key, value, propRange)
|
|
sizer.Add(propUI)
|
|
|
|
elif propType == OG.PROP_UI_TIME:
|
|
|
|
if value is None:
|
|
continue
|
|
|
|
propUI = ObjectPropUITime(self.propsPane, key, value)
|
|
sizer.Add(propUI)
|
|
|
|
else:
|
|
# unspported property type
|
|
continue
|
|
|
|
propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
|
|
self.editor.objectMgr.onLeaveObjectPropUI,
|
|
lambda p0=None, p1=obj, p2=key: self.editor.objectMgr.updateObjectProperty(p0, p1, p2))
|
|
|
|
|
|
self.propsPane.SetSizer(sizer);
|
|
self.Layout()
|
|
self.SetupScrolling(self, scroll_y = True, rate_y = 20)
|
|
if self.lastPropTab == 'Transform':
|
|
self.nb.SetSelection(0)
|
|
elif self.lastPropTab == 'Look':
|
|
self.nb.SetSelection(1)
|
|
elif self.lastPropTab == 'Properties':
|
|
self.nb.SetSelection(2)
|
|
|