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

View File

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

View File

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