Added [WIP] ProtoPalette

This commit is contained in:
Gyedo Jeon 2010-01-22 00:11:18 +00:00
parent cb35e4d8f9
commit 821656be00
10 changed files with 234 additions and 15 deletions

View File

@ -14,6 +14,7 @@ base = ShowBase(False)
from ObjectMgr import *
from FileMgr import *
from ProtoPalette import *
class LevelEditorBase(DirectObject):
""" Base Class for Panda3D LevelEditor """
@ -23,6 +24,7 @@ class LevelEditorBase(DirectObject):
self.actionEvents = []
self.objectMgr = ObjectMgr(self)
self.fileMgr = FileMgr(self)
self.protoPalette = ProtoPalette()
# define your own config file in inherited class
self.settingsFile = None

View File

@ -11,6 +11,7 @@ from ObjectPropertyUI import *
from SceneGraphUI import *
from LayerEditorUI import *
from HotKeyUI import *
from ProtoPaletteUI import *
class PandaTextDropTarget(wx.TextDropTarget):
def __init__(self, editor):
@ -95,12 +96,15 @@ class LevelEditorUI(WxAppShell):
self.perspView = Viewport.makePerspective(self.viewFrame)
self.viewFrame.AppendWindow(self.perspView)
self.leftBarUpPane = wx.Panel(self.leftFrame)
self.leftBarUpFrame = wx.SplitterWindow(self.leftFrame, wx.SP_3D | wx.SP_BORDER)
self.leftBarUpPane = wx.Panel(self.leftBarUpFrame)
self.leftBarMidPane = wx.Panel(self.leftBarUpFrame)
self.leftBarDownPane = wx.Panel(self.leftFrame)
self.rightBarUpPane = wx.Panel(self.rightFrame)
self.rightBarDownPane = wx.Panel(self.rightFrame)
self.leftFrame.SplitHorizontally(self.leftBarUpPane, self.leftBarDownPane)
self.leftFrame.SplitHorizontally(self.leftBarUpFrame, self.leftBarDownPane)
self.leftBarUpFrame.SplitHorizontally(self.leftBarUpPane, self.leftBarMidPane)
self.rightFrame.SplitHorizontally(self.rightBarUpPane, self.rightBarDownPane)
self.mainFrame.SplitVertically(self.leftFrame, self.baseFrame, 200)
self.baseFrame.SplitVertically(self.viewFrame, self.rightFrame, 600)
@ -108,6 +112,7 @@ class LevelEditorUI(WxAppShell):
self.viewFrame.SetDropTarget(PandaTextDropTarget(self.editor))
self.leftFrame.SetSashGravity(0.5)
self.leftBarUpFrame.SetSashGravity(0.5)
self.rightFrame.SetSashGravity(0.5)
self.baseFrame.SetSashGravity(1.0)
@ -116,6 +121,7 @@ class LevelEditorUI(WxAppShell):
self.SetSizer(sizer); self.Layout()
self.objectPaletteUI = ObjectPaletteUI(self.leftBarUpPane, self.editor)
self.protoPaletteUI = ProtoPaletteUI(self.leftBarMidPane, self.editor)
self.objectPropertyUI = ObjectPropertyUI(self.rightBarUpPane, self.editor)
self.sceneGraphUI = SceneGraphUI(self.leftBarDownPane, self.editor)
self.layerEditorUI = LayerEditorUI(self.rightBarDownPane, self.editor)
@ -190,6 +196,7 @@ class LevelEditorUI(WxAppShell):
self.sceneGraphUI.showPandaObjectChildren()
def onDestroy(self, evt):
self.editor.protoPalette.saveToFile()
self.editor.saveSettings()
def updateGrids(self, newSize, newSpacing):

View File

@ -7,7 +7,8 @@ OBJ_UID = 0
OBJ_NP = 1
OBJ_DEF = 2
OBJ_MODEL = 3
OBJ_PROP = 4
OBJ_ANIM = 4
OBJ_PROP = 5
# supported UI types
PROP_UI_ENTRY = '_PropUIEntry'

View File

@ -68,8 +68,8 @@ class ObjectHandler:
class PandaActor(Actor.Actor):
def __init__(self):
Actor.Actor.__init__(self, "models/panda-model.egg",{"walk":"models/panda-walk4.egg"})
Actor.Actor.__init__(self, "models/panda-model.egg")
self.setScale(0.005)
self.loop("walk")

View File

@ -5,6 +5,7 @@ Defines ObjectMgr
import os, time, wx
from direct.task import Task
from direct.actor.Actor import Actor
from pandac.PandaModules import *
import ObjectGlobals as OG
@ -63,6 +64,8 @@ class ObjectMgr:
parent = render
objDef = self.editor.objectPalette.findItem(typeName)
if objDef is None:
objDef = self.editor.protoPalette.findItem(typeName)
newobj = None
if objDef and type(objDef) != dict:
if objDef.createFunction:
@ -78,12 +81,29 @@ class ObjectMgr:
# create new obj using function and keyword arguments defined in ObjectPalette
newobj = func(**funcArgs)
elif objDef.actor:
if model is None:
model = objDef.model
try:
newobj = Actor(model)
except:
newobj = Actor(Filename.fromOsSpecific(model).getFullpath())
elif objDef.model is not None:
# since this obj is simple model let's load the model
if model is None:
model = objDef.model
newobj = loader.loadModel(model)
try:
newobj = loader.loadModel(model)
except:
newobj = loader.loadModel(Filename.fromOsSpecific(model).getFullpath())
anim = ''
if len(objDef.anims) > 0:
anim = objDef.anims[0]
# load new anim
animName = os.path.basename(anim)
newAnim = newobj.loadAnims({animName:anim})
newobj.loop(animName)
if newobj is None:
return None
@ -102,7 +122,7 @@ class ObjectMgr:
properties[key] = objDef.properties[key][OG.PROP_DEFAULT]
# insert obj data to main repository
self.objects[uid] = [uid, newobj, objDef, model, properties]
self.objects[uid] = [uid, newobj, objDef, model, anim, properties]
self.npIndex[NodePath(newobj)] = uid
if fSelectObject:
@ -269,7 +289,20 @@ class ObjectMgr:
if fSelectObject:
base.direct.select(newobj)
def updateObjectAnim(self, anim, obj, fSelectObject=True):
""" replace object's anim """
if obj[OG.OBJ_ANIM] != anim:
base.direct.deselectAll()
objNP = obj[OG.OBJ_NP]
# load new anim
animName = os.path.basename(anim)
newAnim = objNP.loadAnims({animName:anim})
objNP.loop(animName)
obj[OG.OBJ_ANIM] = anim
if fSelectObject:
base.direct.select(objNP)
def updateObjectModelFromUI(self, event, obj):
""" replace object's model with one selected from UI """
@ -277,6 +310,12 @@ class ObjectMgr:
if model is not None:
self.updateObjectModel(model, obj)
def updateObjectAnimFromUI(self, event, obj):
""" replace object's anim with one selected from UI """
anim = event.GetString()
if anim is not None:
self.updateObjectAnim(anim, obj)
def updateObjectProperty(self, event, obj, propName):
"""
When an obj's property is updated in UI,

View File

@ -101,6 +101,7 @@ class ObjectPalette(ObjectPaletteBase):
self.add('Animal')
self.add(ObjectBase(name='Panda',
createFunction = ('.createPanda', {}),
anims = ['models/panda-walk4.egg',],
properties = {}),
'Animal')

View File

@ -1,16 +1,19 @@
import copy
import ObjectGlobals as OG
class ObjectBase:
""" Base class for obj definitions """
def __init__(self, name='', createFunction = None, model = None, models= [], properties={},
movable = True):
def __init__(self, name='', createFunction = None, model = None, models= [], anims = [], properties={},
movable = True, actor = False):
self.name = name
self.createFunction = createFunction
self.model = model
self.models = models
self.properties = properties
self.models = models[:]
self.anims = anims[:]
self.properties = copy.deepcopy(properties)
self.movable = movable
self.actor = actor
class ObjectPaletteBase:
"""

View File

@ -2,13 +2,40 @@
UI for object property control
"""
import wx
import os
from wx.lib.scrolledpanel import ScrolledPanel
from direct.wxwidgets.WxSlider import *
from pandac.PandaModules import *
import ObjectGlobals as OG
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 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,
@ -124,6 +151,8 @@ class ObjectPropertyUI(ScrolledPanel):
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:
@ -175,6 +204,14 @@ class ObjectPropertyUI(ScrolledPanel):
self.editor.objectMgr.onLeaveObjectPropUI,
lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectModelFromUI(p0, p1))
if len(objDef.anims) > 0:
propUI = ObjectPropUICombo(self.propPane, 'anim', obj[OG.OBJ_ANIM], objDef.anims)
sizer.Add(propUI)
propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
self.editor.objectMgr.onLeaveObjectPropUI,
lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectAnimFromUI(p0, p1))
for key in objDef.properties.keys():
propDef = objDef.properties[key]
propType = propDef[OG.PROP_TYPE]

View File

@ -0,0 +1,58 @@
"""
Palette for Prototyping
"""
import os
import imp
import types
from ObjectPaletteBase import *
class ProtoPalette(ObjectPaletteBase):
def __init__(self):
ObjectPaletteBase.__init__(self)
def addItems(self, protoData, parent=None):
if type(protoData) == types.DictType:
for key in protoData.keys():
if type(protoData[key]) == types.DictType:
self.add(key, parent)
self.addItems(protoData[key], key)
else:
self.add(protoData[key], parent)
def populate(self):
dirname = os.path.dirname(__file__)
moduleName = 'protoPaletteData'
try:
file, pathname, description = imp.find_module(moduleName, [dirname])
module = imp.load_module(moduleName, file, pathname, description)
except:
print "protoPaletteData doesn't exist"
return
self.addItems(module.protoData)
def saveProtoData(self, f, protoData, depth):
tab = ' '*4*depth
if not f:
return
for key in protoData.keys():
f.write("%s'%s' : "%(tab, key))
if type(protoData[key]) == types.DictType:
f.write("{\n")
self.saveProtoData(f, protoData[key], depth + 1)
f.write("%s},\n"%tab)
else:
f.write("ObjectBase(name='%s', model='%s', anims=%s, actor=True),\n"%(protoData[key].name, protoData[key].model, protoData[key].anims))
def saveToFile(self):
try:
f = open(os.path.dirname(__file__) + '/protoPaletteData.py', 'w')
f.write("from direct.leveleditor.ObjectPaletteBase import *\n\n")
f.write("protoData = {\n")
self.saveProtoData(f, self.data, 1)
f.write("}\n")
f.close()
except:
pass

View File

@ -0,0 +1,71 @@
"""
Defines ProtoPalette tree UI
"""
import wx
import os
import cPickle as pickl
from pandac.PandaModules import *
from ObjectPaletteBase import *
class FileDrop(wx.FileDropTarget):
def __init__(self, editor):
wx.FileDropTarget.__init__(self)
self.editor = editor
def OnDropFiles(self, x, y, filenames):
for filename in filenames:
name = os.path.basename(filename)
modelname = Filename.fromOsSpecific(filename).getFullpath()
itemData = ObjectBase(name=name, model=modelname, actor=True)
base.le.protoPalette.add(itemData)
newItem = self.editor.ui.protoPaletteUI.tree.AppendItem(self.editor.ui.protoPaletteUI.root, name)
self.editor.ui.protoPaletteUI.tree.SetItemPyData(newItem, itemData)
self.editor.ui.protoPaletteUI.tree.ScrollTo(newItem)
class ProtoPaletteUI(wx.Panel):
def __init__(self, parent, editor):
wx.Panel.__init__(self, parent)
self.editor = editor
self.palette = self.editor.protoPalette
self.tree = wx.TreeCtrl(self)
self.root = self.tree.AddRoot('Proto Objects')
self.addTreeNodes(self.root, self.palette.data)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.tree, 1, wx.EXPAND, 0)
self.SetSizer(sizer); self.Layout()
parentSizer = wx.BoxSizer(wx.VERTICAL)
parentSizer.Add(self, 1, wx.EXPAND, 0)
parent.SetSizer(parentSizer); parent.Layout()
self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.onSelected)
self.tree.Bind(wx.EVT_TREE_BEGIN_DRAG, self.onBeginDrag)
self.SetDropTarget(FileDrop(self.editor))
def addTreeNodes(self, parentItem, items):
for key in items.keys():
newItem = self.tree.AppendItem(parentItem, key)
if type(items[key]) == dict:
self.addTreeNodes(newItem, items[key])
else:
self.tree.SetItemPyData(newItem, items[key])
def onSelected(self, event):
data = self.tree.GetItemPyData(event.GetItem())
if data:
print data.properties
def onBeginDrag(self, event):
item = event.GetItem()
if item != self.tree.GetRootItem(): # prevent dragging root item
text = self.tree.GetItemText(item)
print "Starting drag'n'drop with %s..." % repr(text)
tdo = wx.TextDataObject(text)
tds = wx.DropSource(self.tree)
tds.SetData(tdo)
tds.DoDragDrop(True)