Browse Source

Made property update undoable

Gyedo Jeon 16 years ago
parent
commit
925460b124

+ 47 - 7
direct/src/leveleditor/ActionMgr.py

@@ -17,6 +17,8 @@ class ActionMgr:
 
     def push(self, action):
         self.undoList.append(action)
+        if len(self.redoList) > 0:
+            self.redoList.pop()
         print 'current undoList', self.undoList
 
     def undo(self):
@@ -41,6 +43,11 @@ 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
 
@@ -225,14 +232,15 @@ class ActionTransformObj(ActionBase):
     def saveStatus(self):
         obj = self.editor.objectMgr.findObjectById(self.uid)
         if obj:
-            self.origMat = Mat4(obj[OG.OBJ_NP].getMat())
+            self.origMat = Mat4(self.editor.objectMgr.objectsLastXform[obj[OG.OBJ_UID]])
+            #self.origMat = Mat4(obj[OG.OBJ_NP].getMat())
 
-    def redo(self):
-        if self.uid is None:
-            print "Can't redo this add"        
-        else:
-            self.result = self._do__call__()#uid=self.uid, xformMat=self.xformMat)
-            return self.result
+    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:
@@ -242,6 +250,7 @@ class ActionTransformObj(ActionBase):
             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
 
@@ -270,3 +279,34 @@ class ActionDeselectAll(ActionBase):
             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)        

+ 9 - 0
direct/src/leveleditor/LevelEditorBase.py

@@ -120,6 +120,7 @@ class LevelEditorBase(DirectObject):
             ('DIRECT_deselectAll', self.deselectAll),
             ('LE-Undo', self.actionMgr.undo),
             ('LE-Redo', self.actionMgr.redo),
+            ('DIRECT_manipulateObjectCleanup', self.cleanUpManipulating),
             ])
 
         # Add all the action events
@@ -170,6 +171,14 @@ class LevelEditorBase(DirectObject):
 ##             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

+ 40 - 25
direct/src/leveleditor/ObjectMgr.py

@@ -20,6 +20,7 @@ class ObjectMgr:
         self.objects = {}
         self.npIndex = {}
         self.saveData = []
+        self.objectsLastXform = {}
 
         self.lastUid = ''
         self.lastUidMode = 0
@@ -180,6 +181,7 @@ class ObjectMgr:
             return
 
         self.currNodePath = obj[OG.OBJ_NP]
+        self.objectsLastXform[obj[OG.OBJ_UID]] = Mat4(self.currNodePath.getMat())
         # [gjeon] to connect transform UI with nodepath's transform
         self.spawnUpdateObjectUITask()
         self.updateObjectPropertyUI(obj)
@@ -443,34 +445,47 @@ class ObjectMgr:
         propDataType = propDef[OG.PROP_DATATYPE]
 
         val = OG.TYPE_CONV[propDataType](val)
-        objProp[propName] = val
-
-        if propDef[OG.PROP_FUNC] is None:
-            return
+        oldVal = objProp[propName]
+        #objProp[propName] = val
         
-        funcName = propDef[OG.PROP_FUNC][OG.FUNC_NAME]
-        funcArgs = propDef[OG.PROP_FUNC][OG.FUNC_ARGS]
-
-        if funcName.startswith('.'):
-            if self.editor:
-                func = Functor(eval("base.le.objectHandler%s"%funcName))
-            else: # when loaded outside of LE
-                func = Functor(eval("base.objectHandler%s"%funcName))                
+        if propDef[OG.PROP_FUNC] is None:
+            func = None
+            undoFunc = None
         else:
-            func = Functor(eval(funcName))
-
-        # populate keyword arguments
-        kwargs = {}
-        for key in funcArgs.keys():
-            if funcArgs[key] == OG.ARG_VAL:
-                kwargs[key] = val
-            elif funcArgs[key] == OG.ARG_OBJ:
-                kwargs[key] = obj
+            funcName = propDef[OG.PROP_FUNC][OG.FUNC_NAME]
+            funcArgs = propDef[OG.PROP_FUNC][OG.FUNC_ARGS]
+
+            # populate keyword arguments
+            kwargs = {}
+            undoKwargs = {}
+            for key in funcArgs.keys():
+                if funcArgs[key] == OG.ARG_VAL:
+                    kwargs[key] = val
+                    undoKwargs[key] = oldVal
+                elif funcArgs[key] == OG.ARG_OBJ:
+                    undoKwargs[key] = obj
+                    objProp[propName] = val
+                    kwargs[key] = obj
+                else:
+                    kwargs[key] = funcArgs[key]
+                    undoKwargs[key] = funcArgs[key]
+
+            if funcName.startswith('.'):
+                if self.editor:
+                    func = Functor(eval("base.le.objectHandler%s"%funcName), **kwargs)
+                    undoFunc = Functor(eval("base.le.objectHandler%s"%funcName), **undoKwargs)
+                else: # when loaded outside of LE
+                    func = Functor(eval("base.objectHandler%s"%funcName), **kwargs)
+                    undoFunc = Functor(eval("base.objectHandler%s"%funcName), **undoKwargs)                    
             else:
-                kwargs[key] = funcArgs[key]
-
-        # finally call update function
-        func(**kwargs)
+                func = Functor(eval(funcName), **kwargs)
+                undoFunc = Functor(eval(funcName), **undoKwargs)
+                
+            # finally call update function
+            #func(**kwargs)
+        action = ActionUpdateObjectProp(self.editor, fSelectObject, obj, propName, val, oldVal, func, undoFunc)
+        self.editor.actionMgr.push(action)
+        action()
 
         if self.editor and fSelectObject:
             base.direct.select(obj[OG.OBJ_NP], fUndo=0)