mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
Added [WIP] ProtoPalette
This commit is contained in:
parent
cb35e4d8f9
commit
821656be00
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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'
|
||||
|
@ -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")
|
||||
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -101,6 +101,7 @@ class ObjectPalette(ObjectPaletteBase):
|
||||
self.add('Animal')
|
||||
self.add(ObjectBase(name='Panda',
|
||||
createFunction = ('.createPanda', {}),
|
||||
anims = ['models/panda-walk4.egg',],
|
||||
properties = {}),
|
||||
'Animal')
|
||||
|
||||
|
@ -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:
|
||||
"""
|
||||
|
@ -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]
|
||||
|
58
direct/src/leveleditor/ProtoPalette.py
Executable file
58
direct/src/leveleditor/ProtoPalette.py
Executable 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
|
71
direct/src/leveleditor/ProtoPaletteUI.py
Executable file
71
direct/src/leveleditor/ProtoPaletteUI.py
Executable 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)
|
Loading…
x
Reference in New Issue
Block a user