Poodletooth-iLand/panda/direct/leveleditor/ActionMgr.py
2015-03-03 17:10:12 -05:00

400 lines
14 KiB
Python

from pandac.PandaModules import *
import ObjectGlobals as OG
class ActionMgr:
def __init__(self):
self.undoList = []
self.redoList = []
def reset(self):
while len(self.undoList) > 0:
action = self.undoList.pop()
action.destroy()
while len(self.redoList) > 0:
action = self.redoList.pop()
action.destroy()
def push(self, action):
self.undoList.append(action)
if len(self.redoList) > 0:
self.redoList.pop()
def undo(self):
if len(self.undoList) < 1:
print 'No more undo'
else:
action = self.undoList.pop()
self.redoList.append(action)
action.undo()
def redo(self):
if len(self.redoList) < 1:
print 'No more redo'
else:
action = self.redoList.pop()
self.undoList.append(action)
action.redo()
class ActionBase(Functor):
""" Base class for user actions """
def __init__(self, function, *args, **kargs):
self.function = function
if function is None:
def nullFunc():
pass
function = nullFunc
Functor.__init__(self, function, *args, **kargs)
self.result = None
def _do__call__(self, *args, **kargs):
self.saveStatus()
self.result = Functor._do__call__(self, *args, **kargs)
self.postCall()
return self.result
# needed this line to override _do__call__
__call__ = _do__call__
def redo(self):
self.result = self._do__call__()
return self.result
def saveStatus(self):
# save object status for undo here
pass
def postCall(self):
# implement post process here
pass
def undo(self):
print "undo method is not defined for this action"
class ActionAddNewObj(ActionBase):
""" Action class for adding new object """
def __init__(self, editor, *args, **kargs):
self.editor = editor
function = self.editor.objectMgr.addNewObject
ActionBase.__init__(self, function, *args, **kargs)
self.uid = None
def postCall(self):
obj = self.editor.objectMgr.findObjectByNodePath(self.result)
if obj:
self.uid = obj[OG.OBJ_UID]
def redo(self):
if self.uid is None:
print "Can't redo this add"
else:
self.result = self._do__call__(uid=self.uid)
return self.result
def undo(self):
if self.result is None:
print "Can't undo this add"
else:
print "Undo: addNewObject"
if self.uid:
obj = self.editor.objectMgr.findObjectById(self.uid)
else:
obj = self.editor.objectMgr.findObjectByNodePath(self.result)
if obj:
self.uid = obj[OG.OBJ_UID]
self.editor.ui.sceneGraphUI.delete(self.uid)
base.direct.deselect(obj[OG.OBJ_NP])
base.direct.removeNodePath(obj[OG.OBJ_NP])
self.result = None
else:
print "Can't undo this add"
class ActionDeleteObj(ActionBase):
""" Action class for deleting object """
def __init__(self, editor, *args, **kargs):
self.editor = editor
function = base.direct.removeAllSelected
ActionBase.__init__(self, function, *args, **kargs)
self.selectedUIDs = []
self.hierarchy = {}
self.objInfos = {}
self.objTransforms = {}
def saveStatus(self):
selectedNPs = base.direct.selected.getSelectedAsList()
def saveObjStatus(np, isRecursive=True):
obj = self.editor.objectMgr.findObjectByNodePath(np)
if obj:
uid = obj[OG.OBJ_UID]
if not isRecursive:
self.selectedUIDs.append(uid)
objNP = obj[OG.OBJ_NP]
self.objInfos[uid] = obj
self.objTransforms[uid] = objNP.getMat()
parentNP = objNP.getParent()
if parentNP == render:
self.hierarchy[uid] = None
else:
parentObj = self.editor.objectMgr.findObjectByNodePath(parentNP)
if parentObj:
self.hierarchy[uid] = parentObj[OG.OBJ_UID]
for child in np.getChildren():
if child.hasTag('OBJRoot'):
saveObjStatus(child)
for np in selectedNPs:
saveObjStatus(np, False)
def undo(self):
if len(self.hierarchy.keys()) == 0 or\
len(self.objInfos.keys()) == 0:
print "Can't undo this deletion"
else:
print "Undo: deleteObject"
def restoreObject(uid, parentNP):
obj = self.objInfos[uid]
objDef = obj[OG.OBJ_DEF]
objModel = obj[OG.OBJ_MODEL]
objProp = obj[OG.OBJ_PROP]
objRGBA = obj[OG.OBJ_RGBA]
objNP = self.editor.objectMgr.addNewObject(objDef.name,
uid,
obj[OG.OBJ_MODEL],
parentNP)
self.editor.objectMgr.updateObjectColor(objRGBA[0], objRGBA[1], objRGBA[2], objRGBA[3], objNP)
self.editor.objectMgr.updateObjectProperties(objNP, objProp)
objNP.setMat(self.objTransforms[uid])
while (len(self.hierarchy.keys()) > 0):
for uid in self.hierarchy.keys():
if self.hierarchy[uid] is None:
parentNP = None
restoreObject(uid, parentNP)
del self.hierarchy[uid]
else:
parentObj = self.editor.objectMgr.findObjectById(self.hierarchy[uid])
if parentObj:
parentNP = parentObj[OG.OBJ_NP]
restoreObject(uid, parentNP)
del self.hierarchy[uid]
base.direct.deselectAllCB()
for uid in self.selectedUIDs:
obj = self.editor.objectMgr.findObjectById(uid)
if obj:
self.editor.select(obj[OG.OBJ_NP], fMultiSelect=1, fUndo=0)
self.selecteUIDs = []
self.hierarchy = {}
self.objInfos = {}
class ActionDeleteObjById(ActionBase):
""" Action class for deleting object """
def __init__(self, editor, uid):
self.editor = editor
function = self.editor.objectMgr.removeObjectById
self.uid = uid
ActionBase.__init__(self, function, self.uid)
self.hierarchy = {}
self.objInfos = {}
self.objTransforms = {}
def saveStatus(self):
def saveObjStatus(uid_np, isUID=False):
if isUID:
obj = self.editor.objectMgr.findObjectById(uid_np)
else:
obj = self.editor.objectMgr.findObjectByNodePath(uid_np)
if obj:
uid = obj[OG.OBJ_UID]
objNP = obj[OG.OBJ_NP]
self.objInfos[uid] = obj
self.objTransforms[uid] = objNP.getMat()
parentNP = objNP.getParent()
if parentNP == render:
self.hierarchy[uid] = None
else:
parentObj = self.editor.objectMgr.findObjectByNodePath(parentNP)
if parentObj:
self.hierarchy[uid] = parentObj[OG.OBJ_UID]
for child in objNP.getChildren():
if child.hasTag('OBJRoot'):
saveObjStatus(child)
saveObjStatus(self.uid, True)
def undo(self):
if len(self.hierarchy.keys()) == 0 or\
len(self.objInfos.keys()) == 0:
print "Can't undo this deletion"
else:
print "Undo: deleteObjectById"
def restoreObject(uid, parentNP):
obj = self.objInfos[uid]
objDef = obj[OG.OBJ_DEF]
objModel = obj[OG.OBJ_MODEL]
objProp = obj[OG.OBJ_PROP]
objRGBA = obj[OG.OBJ_RGBA]
objNP = self.editor.objectMgr.addNewObject(objDef.name,
uid,
obj[OG.OBJ_MODEL],
parentNP)
self.editor.objectMgr.updateObjectColor(objRGBA[0], objRGBA[1], objRGBA[2], objRGBA[3], objNP)
self.editor.objectMgr.updateObjectProperties(objNP, objProp)
objNP.setMat(self.objTransforms[uid])
while (len(self.hierarchy.keys()) > 0):
for uid in self.hierarchy.keys():
if self.hierarchy[uid] is None:
parentNP = None
restoreObject(uid, parentNP)
del self.hierarchy[uid]
else:
parentObj = self.editor.objectMgr.findObjectById(self.hierarchy[uid])
if parentObj:
parentNP = parentObj[OG.OBJ_NP]
restoreObject(uid, parentNP)
del self.hierarchy[uid]
self.hierarchy = {}
self.objInfos = {}
class ActionChangeHierarchy(ActionBase):
""" Action class for changing Scene Graph Hierarchy """
def __init__(self, editor, oldGrandParentId, oldParentId, newParentId, childName, *args, **kargs):
self.editor = editor
self.oldGrandParentId = oldGrandParentId
self.oldParentId = oldParentId
self.newParentId = newParentId
self.childName = childName
function = self.editor.ui.sceneGraphUI.parent
ActionBase.__init__(self, function, self.oldParentId, self.newParentId, self.childName, **kargs)
def undo(self):
self.editor.ui.sceneGraphUI.parent(self.oldParentId, self.oldGrandParentId, self.childName)
class ActionSelectObj(ActionBase):
""" Action class for adding new object """
def __init__(self, editor, *args, **kargs):
self.editor = editor
function = base.direct.selectCB
ActionBase.__init__(self, function, *args, **kargs)
self.selectedUIDs = []
def saveStatus(self):
selectedNPs = base.direct.selected.getSelectedAsList()
for np in selectedNPs:
obj = self.editor.objectMgr.findObjectByNodePath(np)
if obj:
uid = obj[OG.OBJ_UID]
self.selectedUIDs.append(uid)
def undo(self):
print "Undo : selectObject"
base.direct.deselectAllCB()
for uid in self.selectedUIDs:
obj = self.editor.objectMgr.findObjectById(uid)
if obj:
self.editor.select(obj[OG.OBJ_NP], fMultiSelect=1, fUndo=0)
self.selectedUIDs = []
class ActionTransformObj(ActionBase):
""" Action class for object transformation """
def __init__(self, editor, *args, **kargs):
self.editor = editor
function = self.editor.objectMgr.setObjectTransform
ActionBase.__init__(self, function, *args, **kargs)
self.uid = args[0]
#self.xformMat = Mat4(args[1])
self.origMat = None
def saveStatus(self):
obj = self.editor.objectMgr.findObjectById(self.uid)
if obj:
self.origMat = Mat4(self.editor.objectMgr.objectsLastXform[obj[OG.OBJ_UID]])
#self.origMat = Mat4(obj[OG.OBJ_NP].getMat())
def _do__call__(self, *args, **kargs):
self.result = ActionBase._do__call__(self, *args, **kargs)
obj = self.editor.objectMgr.findObjectById(self.uid)
if obj:
self.editor.objectMgr.objectsLastXform[self.uid] = Mat4(obj[OG.OBJ_NP].getMat())
return self.result
def undo(self):
if self.origMat is None:
print "Can't undo this transform"
else:
print "Undo: transformObject"
obj = self.editor.objectMgr.findObjectById(self.uid)
if obj:
obj[OG.OBJ_NP].setMat(self.origMat)
self.editor.objectMgr.objectsLastXform[self.uid] = Mat4(self.origMat)
del self.origMat
self.origMat = None
class ActionDeselectAll(ActionBase):
""" Action class for adding new object """
def __init__(self, editor, *args, **kargs):
self.editor = editor
function = base.direct.deselectAllCB
ActionBase.__init__(self, function, *args, **kargs)
self.selectedUIDs = []
def saveStatus(self):
selectedNPs = base.direct.selected.getSelectedAsList()
for np in selectedNPs:
obj = self.editor.objectMgr.findObjectByNodePath(np)
if obj:
uid = obj[OG.OBJ_UID]
self.selectedUIDs.append(uid)
def undo(self):
print "Undo : deselectAll"
base.direct.deselectAllCB()
for uid in self.selectedUIDs:
obj = self.editor.objectMgr.findObjectById(uid)
if obj:
self.editor.select(obj[OG.OBJ_NP], fMultiSelect=1, fUndo=0)
self.selectedUIDs = []
class ActionUpdateObjectProp(ActionBase):
""" Action class for updating object property """
def __init__(self, editor, fSelectObject, obj, propName, val, oldVal, function, undoFunc, *args, **kargs):
self.editor = editor
self.fSelectObject = fSelectObject
self.obj = obj
self.propName = propName
self.newVal = val
self.oldVal = oldVal
self.undoFunc = undoFunc
ActionBase.__init__(self, function, *args, **kargs)
def saveStatus(self):
self.obj[OG.OBJ_PROP][self.propName] = self.newVal
def redo(self):
self.result = self._do__call__()#uid=self.uid, xformMat=self.xformMat)
if self.editor and self.fSelectObject:
base.direct.select(self.obj[OG.OBJ_NP], fUndo=0)
return self.result
def undo(self):
print "Undo : updateObjectProp"
if self.oldVal:
self.obj[OG.OBJ_PROP][self.propName] = self.oldVal
if self.undoFunc:
self.undoFunc()
if self.editor and self.fSelectObject:
base.direct.select(self.obj[OG.OBJ_NP], fUndo=0)