integrated selected obj parenting option

This commit is contained in:
Arkady Trestman 2010-05-05 22:35:30 +00:00
parent 64083938fa
commit 129f164f16
4 changed files with 374 additions and 355 deletions

View File

@ -1,349 +1,359 @@
"""
Base class for Level Editor
You should write your own LevelEditor class inheriting this.
Refer LevelEditor.py for example.
"""
from direct.showbase.DirectObject import *
from direct.directtools.DirectUtil import *
from direct.gui.DirectGui import *
from FileMgr import *
from ActionMgr import *
from MayaConverter import *
class LevelEditorBase(DirectObject):
""" Base Class for Panda3D LevelEditor """
def __init__(self):
#loadPrcFileData('startup', 'window-type none')
self.currentFile = None
self.fNeedToSave = False
self.actionEvents = []
#self.objectMgr = ObjectMgr(self)
self.fileMgr = FileMgr(self)
self.actionMgr = ActionMgr()
self.NPParent = render
# define your own config file in inherited class
self.settingsFile = None
# you can show/hide specific properties by using propertiesMask and this mode
self.mode = BitMask32()
def initialize(self):
""" You should call this in your __init__ method of inherited LevelEditor class """
# specifiy what obj can be 'selected' as objects
base.direct.selected.addTag('OBJRoot')
self.actionEvents.extend([
# Node path events
('DIRECT-select', self.select),
('DIRECT-delete', self.handleDelete),
('DIRECT-preDeselectAll', self.deselectAll),
('DIRECT_deselectAll', self.deselectAllCB),
('preRemoveNodePath', self.removeNodePathHook),
('DIRECT_deselectedNodePath', self.deselectAllCB),
('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', self.selectedNodePathHook),
('DIRECT_deselectAll', self.deselectAll),
('LE-Undo', self.actionMgr.undo),
('LE-Redo', self.actionMgr.redo),
('LE-Duplicate', self.objectMgr.duplicateSelected),
('DIRECT_manipulateObjectCleanup', self.cleanUpManipulating),
('LE-MakeLive', self.objectMgr.makeSelectedLive),
('LE-NewScene', self.ui.onNew),
('LE-SaveScene', self.ui.onSave),
('LE-OpenScene', self.ui.onOpen),
('LE-Quit', self.ui.quit),
('DIRECT-mouse3', self.handleMouse3),
('DIRECT-toggleWidgetVis', self.toggleWidget),
])
# Add all the action events
for event in self.actionEvents:
if len(event) == 3:
self.accept(event[0], event[1], event[2])
else:
self.accept(event[0], event[1])
# editor state text display such as edit mode
self.statusReadout = OnscreenText(
pos = (-1.2, 0.9), bg=Vec4(1,1,1,1),
scale = 0.05, align = TextNode.ALeft,
mayChange = 1, font = TextNode.getDefaultFont())
self.statusReadout.setText("")
# Make sure readout is never lit or drawn in wireframe
useDirectRenderStyle(self.statusReadout)
self.statusReadout.reparentTo(hidden)
self.statusLines = []
taskMgr.doMethodLater(5, self.updateStatusReadoutTimeouts, 'updateStatus')
self.loadSettings()
self.reset()
def setTitleWithFilename(self, filename=""):
title = self.ui.appname
if filename != "":
filenameshort = os.path.basename(filename)
title = title + " (%s)"%filenameshort
self.ui.SetLabel(title)
def removeNodePathHook(self, nodePath):
if nodePath is None:
return
base.direct.deselect(nodePath)
self.objectMgr.removeObjectByNodePath(nodePath)
if (base.direct.selected.last != None and nodePath.compareTo(base.direct.selected.last)==0):
# if base.direct.selected.last is refering to this
# removed obj, clear the reference
if (hasattr(__builtins__,'last')):
__builtins__.last = None
else:
__builtins__['last'] = None
base.direct.selected.last = None
def toggleWidget(self):
if self.objectMgr.currNodePath:
obj = self.objectMgr.findObjectByNodePath(self.objectMgr.currNodePath)
if obj and not obj[OG.OBJ_DEF].movable:
return
base.direct.toggleWidgetVis()
def handleMouse3(self, modifiers):
if base.direct.fAlt or modifiers == 4:
return
self.ui.onRightDown()
def handleDelete(self):
oldSelectedNPs = base.direct.selected.getSelectedAsList()
oldUIDs = []
for oldNP in oldSelectedNPs:
obj = self.objectMgr.findObjectByNodePath(oldNP)
if obj:
oldUIDs.append(obj[OG.OBJ_UID])
action = ActionDeleteObj(self)
self.actionMgr.push(action)
action()
for uid in oldUIDs:
self.ui.sceneGraphUI.delete(uid)
## reply = wx.MessageBox("Do you want to delete selected?", "Delete?",
## wx.YES_NO | wx.ICON_QUESTION)
## if reply == wx.YES:
## base.direct.removeAllSelected()
## else:
## # need to reset COA
## dnp = base.direct.selected.last
## # Update camera controls coa to this point
## # Coa2Camera = Coa2Dnp * Dnp2Camera
## mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.direct.camera)
## row = mCoa2Camera.getRow(3)
## coa = Vec3(row[0], row[1], row[2])
## base.direct.cameraControl.updateCoa(coa)
def cleanUpManipulating(self, selectedNPs):
for np in selectedNPs:
obj = self.objectMgr.findObjectByNodePath(np)
if obj:
action = ActionTransformObj(self, obj[OG.OBJ_UID], Mat4(np.getMat()))
self.actionMgr.push(action)
action()
def select(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1, fLEPane=0, fUndo=1):
if fUndo:
# Select tagged object if present
if fSelectTag:
for tag in base.direct.selected.tagList:
if nodePath.hasNetTag(tag):
nodePath = nodePath.findNetTag(tag)
break
action = ActionSelectObj(self, nodePath, fMultiSelect)
self.actionMgr.push(action)
action()
else:
base.direct.selectCB(nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo)
def selectedNodePathHook(self, nodePath, fMultiSelect = 0, fSelectTag = 1, fLEPane = 0):
# handle unpickable nodepath
if nodePath.getName() in base.direct.iRay.unpickable:
base.direct.deselect(nodePath)
return
if fMultiSelect == 0 and fLEPane == 0:
oldSelectedNPs = base.direct.selected.getSelectedAsList()
for oldNP in oldSelectedNPs:
obj = self.objectMgr.findObjectByNodePath(oldNP)
if obj:
self.ui.sceneGraphUI.deSelect(obj[OG.OBJ_UID])
self.objectMgr.selectObject(nodePath, fLEPane)
self.ui.buildContextMenu(nodePath)
def deselectAll(self, np=None):
if len(base.direct.selected.getSelectedAsList()) ==0:
return
action = ActionDeselectAll(self)
self.actionMgr.push(action)
action()
def deselectAllCB(self, dnp=None):
self.objectMgr.deselectAll()
def reset(self):
if self.fNeedToSave:
reply = wx.MessageBox("Do you want to save current scene?", "Save?",
wx.YES_NO | wx.ICON_QUESTION)
if reply == wx.YES:
result = self.ui.onSave()
if result == False:
return
base.direct.deselectAll()
self.ui.reset()
self.objectMgr.reset()
self.actionMgr.reset()
self.ui.perspView.camera.setPos(-19, -19, 19)
self.ui.perspView.camera.lookAt(Point3(0, 0, 0))
self.ui.leftView.camera.setPos(600, 0, 0)
self.ui.frontView.camera.setPos(0, -600, 0)
self.ui.topView.camera.setPos(0, 0, 600)
self.resetOrthoCam(self.ui.topView)
self.resetOrthoCam(self.ui.frontView)
self.resetOrthoCam(self.ui.leftView)
self.fNeedToSave = False
self.setTitleWithFilename()
def resetOrthoCam(self, view):
base.direct.drList[base.camList.index(NodePath(view.camNode))].orthoFactor = 0.1
x = view.ClientSize.GetWidth() * 0.1
y = view.ClientSize.GetHeight() * 0.1
view.camLens.setFilmSize(x, y)
def save(self):
if self.currentFile:
self.fileMgr.saveToFile(self.currentFile)
def saveAs(self, fileName):
self.fileMgr.saveToFile(fileName)
self.currentFile = fileName
def load(self, fileName):
self.reset()
self.fileMgr.loadFromFile(fileName)
self.currentFile = fileName
def saveSettings(self):
if self.settingsFile is None:
return
try:
f = open(self.settingsFile, 'w')
f.write('gridSize\n%f\n'%self.ui.perspView.grid.gridSize)
f.write('gridSpacing\n%f\n'%self.ui.perspView.grid.gridSpacing)
f.write('hotKey\n%s\n'%base.direct.hotKeyMap)
f.close()
except:
pass
def loadSettings(self):
if self.settingsFile is None:
return
try:
f = open(self.settingsFile, 'r')
configLines = f.readlines()
f.close()
gridSize = 100.0
gridSpacing = 5.0
for i in range(0, len(configLines)):
line = configLines[i]
i = i + 1
if line.startswith('gridSize'):
gridSize = float(configLines[i])
elif line.startswith('gridSpacing'):
gridSpacing = float(configLines[i])
elif line.startswith('hotKey'):
customHotKeyMap = eval(configLines[i])
customHotKeyDict = {}
for hotKey in customHotKeyMap.keys():
desc = customHotKeyMap[hotKey]
customHotKeyDict[desc[1]] = hotKey
overriddenKeys = []
for key in base.direct.hotKeyMap.keys():
desc = base.direct.hotKeyMap[key]
if desc[1] in customHotKeyDict.keys():
overriddenKeys.append(key)
for key in overriddenKeys:
del base.direct.hotKeyMap[key]
base.direct.hotKeyMap.update(customHotKeyMap)
self.ui.updateGrids(gridSize, gridSpacing)
self.ui.updateMenu()
except:
pass
def convertMaya(self, modelname, callBack, obj=None, isAnim=False):
if obj and isAnim:
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, obj, isAnim)
else:
reply = wx.MessageBox("Is it an animation file?", "Animation?",
wx.YES_NO | wx.ICON_QUESTION)
if reply == wx.YES:
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, True)
else:
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
mayaConverter.Show()
def convertFromMaya(self, modelname, callBack):
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
mayaConverter.Show()
def updateStatusReadout(self, status, color=None):
if status:
# add new status line, first check to see if it already exists
alreadyExists = False
for currLine in self.statusLines:
if (status == currLine[1]):
alreadyExists = True
break
if (alreadyExists == False):
time = globalClock.getRealTime() + 15
self.statusLines.append([time,status,color])
# update display of new status lines
self.statusReadout.reparentTo(aspect2d)
statusText = ""
lastColor = None
for currLine in self.statusLines:
statusText += currLine[1] + '\n'
lastColor = currLine[2]
self.statusReadout.setText(statusText)
if (lastColor):
self.statusReadout.textNode.setCardColor(
lastColor[0], lastColor[1], lastColor[2], lastColor[3])
self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
else:
self.statusReadout.textNode.setCardColor(1,1,1,1)
self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
def updateStatusReadoutTimeouts(self,task=None):
removalList = []
for currLine in self.statusLines:
if (globalClock.getRealTime() >= currLine[0]):
removalList.append(currLine)
for currRemoval in removalList:
self.statusLines.remove(currRemoval)
self.updateStatusReadout(None)
# perform doMethodLater again after delay
# This crashes when CTRL-C'ing, so this is a cheap hack.
#return 2
from direct.task import Task
return Task.again
"""
Base class for Level Editor
You should write your own LevelEditor class inheriting this.
Refer LevelEditor.py for example.
"""
from direct.showbase.DirectObject import *
from direct.directtools.DirectUtil import *
from direct.gui.DirectGui import *
from FileMgr import *
from ActionMgr import *
from MayaConverter import *
class LevelEditorBase(DirectObject):
""" Base Class for Panda3D LevelEditor """
def __init__(self):
#loadPrcFileData('startup', 'window-type none')
self.currentFile = None
self.fNeedToSave = False
self.actionEvents = []
#self.objectMgr = ObjectMgr(self)
self.fileMgr = FileMgr(self)
self.actionMgr = ActionMgr()
self.NPParent = render
# define your own config file in inherited class
self.settingsFile = None
# you can show/hide specific properties by using propertiesMask and this mode
self.mode = BitMask32()
def initialize(self):
""" You should call this in your __init__ method of inherited LevelEditor class """
# specifiy what obj can be 'selected' as objects
base.direct.selected.addTag('OBJRoot')
self.actionEvents.extend([
# Node path events
('DIRECT-select', self.select),
('DIRECT-delete', self.handleDelete),
('DIRECT-preDeselectAll', self.deselectAll),
('DIRECT_deselectAll', self.deselectAllCB),
('preRemoveNodePath', self.removeNodePathHook),
('DIRECT_deselectedNodePath', self.deselectAllCB),
('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', self.selectedNodePathHook),
('DIRECT_deselectAll', self.deselectAll),
('LE-Undo', self.actionMgr.undo),
('LE-Redo', self.actionMgr.redo),
('LE-Duplicate', self.objectMgr.duplicateSelected),
('DIRECT_manipulateObjectCleanup', self.cleanUpManipulating),
('LE-MakeLive', self.objectMgr.makeSelectedLive),
('LE-NewScene', self.ui.onNew),
('LE-SaveScene', self.ui.onSave),
('LE-OpenScene', self.ui.onOpen),
('LE-Quit', self.ui.quit),
('DIRECT-mouse3', self.handleMouse3),
('DIRECT-toggleWidgetVis', self.toggleWidget),
])
# Add all the action events
for event in self.actionEvents:
if len(event) == 3:
self.accept(event[0], event[1], event[2])
else:
self.accept(event[0], event[1])
# editor state text display such as edit mode
self.statusReadout = OnscreenText(
pos = (-1.2, 0.9), bg=Vec4(1,1,1,1),
scale = 0.05, align = TextNode.ALeft,
mayChange = 1, font = TextNode.getDefaultFont())
self.statusReadout.setText("")
# Make sure readout is never lit or drawn in wireframe
useDirectRenderStyle(self.statusReadout)
self.statusReadout.reparentTo(hidden)
self.statusLines = []
taskMgr.doMethodLater(5, self.updateStatusReadoutTimeouts, 'updateStatus')
self.loadSettings()
self.reset()
def setTitleWithFilename(self, filename=""):
title = self.ui.appname
if filename != "":
filenameshort = os.path.basename(filename)
title = title + " (%s)"%filenameshort
self.ui.SetLabel(title)
def removeNodePathHook(self, nodePath):
if nodePath is None:
return
base.direct.deselect(nodePath)
self.objectMgr.removeObjectByNodePath(nodePath)
if (base.direct.selected.last != None and nodePath.compareTo(base.direct.selected.last)==0):
# if base.direct.selected.last is refering to this
# removed obj, clear the reference
if (hasattr(__builtins__,'last')):
__builtins__.last = None
else:
__builtins__['last'] = None
base.direct.selected.last = None
def toggleWidget(self):
if self.objectMgr.currNodePath:
obj = self.objectMgr.findObjectByNodePath(self.objectMgr.currNodePath)
if obj and not obj[OG.OBJ_DEF].movable:
return
base.direct.toggleWidgetVis()
def handleMouse3(self, modifiers):
if base.direct.fAlt or modifiers == 4:
return
self.ui.onRightDown()
def handleDelete(self):
oldSelectedNPs = base.direct.selected.getSelectedAsList()
oldUIDs = []
for oldNP in oldSelectedNPs:
obj = self.objectMgr.findObjectByNodePath(oldNP)
if obj:
oldUIDs.append(obj[OG.OBJ_UID])
action = ActionDeleteObj(self)
self.actionMgr.push(action)
action()
for uid in oldUIDs:
self.ui.sceneGraphUI.delete(uid)
## reply = wx.MessageBox("Do you want to delete selected?", "Delete?",
## wx.YES_NO | wx.ICON_QUESTION)
## if reply == wx.YES:
## base.direct.removeAllSelected()
## else:
## # need to reset COA
## dnp = base.direct.selected.last
## # Update camera controls coa to this point
## # Coa2Camera = Coa2Dnp * Dnp2Camera
## mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.direct.camera)
## row = mCoa2Camera.getRow(3)
## coa = Vec3(row[0], row[1], row[2])
## base.direct.cameraControl.updateCoa(coa)
def cleanUpManipulating(self, selectedNPs):
for np in selectedNPs:
obj = self.objectMgr.findObjectByNodePath(np)
if obj:
action = ActionTransformObj(self, obj[OG.OBJ_UID], Mat4(np.getMat()))
self.actionMgr.push(action)
action()
def select(self, nodePath, fMultiSelect=0, fSelectTag=1, fResetAncestry=1, fLEPane=0, fUndo=1):
if fUndo:
# Select tagged object if present
if fSelectTag:
for tag in base.direct.selected.tagList:
if nodePath.hasNetTag(tag):
nodePath = nodePath.findNetTag(tag)
break
action = ActionSelectObj(self, nodePath, fMultiSelect)
self.actionMgr.push(action)
action()
else:
base.direct.selectCB(nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo)
def selectedNodePathHook(self, nodePath, fMultiSelect = 0, fSelectTag = 1, fLEPane = 0):
# handle unpickable nodepath
if nodePath.getName() in base.direct.iRay.unpickable:
base.direct.deselect(nodePath)
return
if fMultiSelect == 0 and fLEPane == 0:
oldSelectedNPs = base.direct.selected.getSelectedAsList()
for oldNP in oldSelectedNPs:
obj = self.objectMgr.findObjectByNodePath(oldNP)
if obj:
self.ui.sceneGraphUI.deSelect(obj[OG.OBJ_UID])
self.objectMgr.selectObject(nodePath, fLEPane)
self.ui.buildContextMenu(nodePath)
def deselectAll(self, np=None):
if len(base.direct.selected.getSelectedAsList()) ==0:
return
action = ActionDeselectAll(self)
self.actionMgr.push(action)
action()
def deselectAllCB(self, dnp=None):
self.objectMgr.deselectAll()
def reset(self):
if self.fNeedToSave:
reply = wx.MessageBox("Do you want to save current scene?", "Save?",
wx.YES_NO | wx.ICON_QUESTION)
if reply == wx.YES:
result = self.ui.onSave()
if result == False:
return
base.direct.deselectAll()
self.ui.reset()
self.objectMgr.reset()
self.actionMgr.reset()
self.ui.perspView.camera.setPos(-19, -19, 19)
self.ui.perspView.camera.lookAt(Point3(0, 0, 0))
self.ui.leftView.camera.setPos(600, 0, 0)
self.ui.frontView.camera.setPos(0, -600, 0)
self.ui.topView.camera.setPos(0, 0, 600)
self.resetOrthoCam(self.ui.topView)
self.resetOrthoCam(self.ui.frontView)
self.resetOrthoCam(self.ui.leftView)
self.fNeedToSave = False
self.setTitleWithFilename()
def resetOrthoCam(self, view):
base.direct.drList[base.camList.index(NodePath(view.camNode))].orthoFactor = 0.1
x = view.ClientSize.GetWidth() * 0.1
y = view.ClientSize.GetHeight() * 0.1
view.camLens.setFilmSize(x, y)
def save(self):
if self.currentFile:
self.fileMgr.saveToFile(self.currentFile)
def saveAs(self, fileName):
self.fileMgr.saveToFile(fileName)
self.currentFile = fileName
def load(self, fileName):
self.reset()
self.fileMgr.loadFromFile(fileName)
self.currentFile = fileName
def saveSettings(self):
if self.settingsFile is None:
return
try:
f = open(self.settingsFile, 'w')
f.write('gridSize\n%f\n'%self.ui.perspView.grid.gridSize)
f.write('gridSpacing\n%f\n'%self.ui.perspView.grid.gridSpacing)
f.write('hotKey\n%s\n'%base.direct.hotKeyMap)
f.close()
except:
pass
def loadSettings(self):
if self.settingsFile is None:
return
try:
f = open(self.settingsFile, 'r')
configLines = f.readlines()
f.close()
gridSize = 100.0
gridSpacing = 5.0
for i in range(0, len(configLines)):
line = configLines[i]
i = i + 1
if line.startswith('gridSize'):
gridSize = float(configLines[i])
elif line.startswith('gridSpacing'):
gridSpacing = float(configLines[i])
elif line.startswith('hotKey'):
customHotKeyMap = eval(configLines[i])
customHotKeyDict = {}
for hotKey in customHotKeyMap.keys():
desc = customHotKeyMap[hotKey]
customHotKeyDict[desc[1]] = hotKey
overriddenKeys = []
for key in base.direct.hotKeyMap.keys():
desc = base.direct.hotKeyMap[key]
if desc[1] in customHotKeyDict.keys():
overriddenKeys.append(key)
for key in overriddenKeys:
del base.direct.hotKeyMap[key]
base.direct.hotKeyMap.update(customHotKeyMap)
self.ui.updateGrids(gridSize, gridSpacing)
self.ui.updateMenu()
except:
pass
def convertMaya(self, modelname, callBack, obj=None, isAnim=False):
if obj and isAnim:
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, obj, isAnim)
else:
reply = wx.MessageBox("Is it an animation file?", "Animation?",
wx.YES_NO | wx.ICON_QUESTION)
if reply == wx.YES:
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, True)
else:
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
mayaConverter.Show()
def convertFromMaya(self, modelname, callBack):
mayaConverter = MayaConverter(self.ui, self, modelname, callBack, None, False)
mayaConverter.Show()
def updateStatusReadout(self, status, color=None):
if status:
# add new status line, first check to see if it already exists
alreadyExists = False
for currLine in self.statusLines:
if (status == currLine[1]):
alreadyExists = True
break
if (alreadyExists == False):
time = globalClock.getRealTime() + 15
self.statusLines.append([time,status,color])
# update display of new status lines
self.statusReadout.reparentTo(aspect2d)
statusText = ""
lastColor = None
for currLine in self.statusLines:
statusText += currLine[1] + '\n'
lastColor = currLine[2]
self.statusReadout.setText(statusText)
if (lastColor):
self.statusReadout.textNode.setCardColor(
lastColor[0], lastColor[1], lastColor[2], lastColor[3])
self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
else:
self.statusReadout.textNode.setCardColor(1,1,1,1)
self.statusReadout.textNode.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
def updateStatusReadoutTimeouts(self,task=None):
removalList = []
for currLine in self.statusLines:
if (globalClock.getRealTime() >= currLine[0]):
removalList.append(currLine)
for currRemoval in removalList:
self.statusLines.remove(currRemoval)
self.updateStatusReadout(None)
# perform doMethodLater again after delay
# This crashes when CTRL-C'ing, so this is a cheap hack.
#return 2
from direct.task import Task
return Task.again
def propMeetsReq(self, typeName, parentNP):
if self.ui.parentToSelectedMenuItem.IsChecked():
if base.direct.selected.last:
parent = base.le.objectMgr.findObjectByNodePath(base.direct.selected.last)
if parent:
parentNP[0] = parent[OG.OBJ_NP]
else:
parentNP[0] = None
return True

View File

@ -23,7 +23,10 @@ class PandaTextDropTarget(wx.TextDropTarget):
def OnDropText(self, x, y, text):
# create new object
action = ActionAddNewObj(self.editor, text)
parentNPRef = [None]
if not self.editor.propMeetsReq(text, parentNPRef):
return
action = ActionAddNewObj(self.editor, text, parent=parentNPRef[0])
self.editor.actionMgr.push(action)
newobj = action()
if newobj is None:
@ -112,6 +115,7 @@ ID_GRID_SIZE = 302
ID_GRID_SNAP = 303
ID_SHOW_PANDA_OBJECT = 304
ID_HOT_KEYS = 305
ID_PARENT_TO_SELECTED = 306
class LevelEditorUIBase(WxPandaShell):
""" Class for Panda3D LevelEditor """
@ -131,6 +135,7 @@ class LevelEditorUIBase(WxPandaShell):
ID_GRID_SNAP : ("Grid S&nap", None),
ID_SHOW_PANDA_OBJECT : ("Show &Panda Objects", None),
ID_HOT_KEYS : ("&Hot Keys", None),
ID_PARENT_TO_SELECTED : ("&Parent To Selected", None)
})
self.editor = editor
@ -191,6 +196,8 @@ class LevelEditorUIBase(WxPandaShell):
self.showPandaObjectsMenuItem = self.menuOptions.Append(ID_SHOW_PANDA_OBJECT, self.MENU_TEXTS[ID_SHOW_PANDA_OBJECT][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.onShowPandaObjects, self.showPandaObjectsMenuItem)
self.parentToSelectedMenuItem = self.menuOptions.Append(ID_PARENT_TO_SELECTED, self.MENU_TEXTS[ID_PARENT_TO_SELECTED][0], kind = wx.ITEM_CHECK)
self.hotKeysMenuItem = self.menuOptions.Append(ID_HOT_KEYS, self.MENU_TEXTS[ID_HOT_KEYS][0])
self.Bind(wx.EVT_MENU, self.onHotKeys, self.hotKeysMenuItem)

View File

@ -180,7 +180,7 @@ class ObjectMgrBase:
if self.editor:
if fSelectObject:
self.editor.select(newobj, fUndo=0)
self.editor.ui.sceneGraphUI.add(newobj)
self.editor.ui.sceneGraphUI.add(newobj, parent)
self.editor.fNeedToSave = True
return newobj
@ -771,3 +771,5 @@ class ObjectMgrBase:
def flatten(self, newobjModel, objDef, uid):
# override this to flatten models
pass

View File

@ -112,7 +112,7 @@ class SceneGraphUIBase(wx.Panel):
item, cookie = self.tree.GetNextChild(parent, cookie)
self.removePandaObjectChildren(itemToRemove)
def add(self, item):
def add(self, item, parentNP = None):
#import pdb;pdb.set_trace()
if item is None:
return
@ -120,10 +120,10 @@ class SceneGraphUIBase(wx.Panel):
if obj is None:
return
parentNodePath = obj[OG.OBJ_NP].getParent()
parentObj = self.editor.objectMgr.findObjectByNodePath(parentNodePath)
if parentNP is None :
parentNP = obj[OG.OBJ_NP].getParent()
parentObj = self.editor.objectMgr.findObjectByNodePath(parentNP)
#import pdb;pdb.set_trace()
if parentObj is None:
parent = self.root
else: