Browse Source

WIP Undo/Redo

Josh Engebretson 10 years ago
parent
commit
b72e854694

+ 13 - 18
Script/AtomicEditor/ui/frames/inspector/ComponentInspector.ts

@@ -93,9 +93,11 @@ class ComponentInspector extends Atomic.UISection {
     inspect(component: Atomic.Component) {
 
         this.component = component;
+
         this.text = component.typeName;
 
-        this.subscribeToEvent(component, "HistoryComponentChangedUndoRedo", (ev) => this.handleHistoryComponentChangedUndoRedo(ev));
+        component.scene.sendEvent("SceneEditSerializable", { serializable: component, operation: 0});
+        this.subscribeToEvent(component, "SceneEditSerializableUndoRedo", (data) => this.handleSceneEditSerializableUndoRedoEvent(data));
 
         // For JSComponents append the filename
         if (component.typeName == "JSComponent") {
@@ -294,6 +296,16 @@ class ComponentInspector extends Atomic.UISection {
 
     }
 
+    handleSceneEditSerializableUndoRedoEvent(ev) {
+
+      for (var i in this.bindings) {
+          this.bindings[i].objectLocked = true;
+          this.bindings[i].setWidgetValueFromObject();
+          this.bindings[i].objectLocked = false;
+      }
+
+    }
+
     // Move these to a mixing class
 
     addPrefabUI(layout: Atomic.UILayout) {
@@ -588,23 +600,6 @@ class ComponentInspector extends Atomic.UISection {
         }
     }
 
-    handleHistoryComponentChangedUndoRedo(ev) {
-
-      for (var i in this.bindings) {
-          this.bindings[i].objectLocked = true;
-      }
-
-      for (var i in this.bindings) {
-          this.bindings[i].setWidgetValueFromObject();
-      }
-
-      for (var i in this.bindings) {
-          this.bindings[i].objectLocked = false;
-      }
-
-    }
-
-
     component: Atomic.Component;
     bindings: Array<DataBinding> = new Array();
 

+ 9 - 24
Script/AtomicEditor/ui/frames/inspector/DataBinding.ts

@@ -67,9 +67,7 @@ class DataBinding {
                 var lp = new Atomic.UILayoutParams();
                 lp.width = 140;
                 field.layoutParams = lp;
-
                 editFields.push(field);
-
                 widget = field;
             }
 
@@ -83,7 +81,6 @@ class DataBinding {
             var lp = new Atomic.UILayoutParams();
             lp.width = 140;
             field.layoutParams = lp;
-
             editFields.push(field);
 
             widget = field;
@@ -98,9 +95,7 @@ class DataBinding {
             var lp = new Atomic.UILayoutParams();
             lp.width = 140;
             field.layoutParams = lp;
-
             editFields.push(field);
-
             widget = field;
         }
         else if (attrInfo.type == Atomic.VAR_VECTOR3 || attrInfo.type == Atomic.VAR_QUATERNION) {
@@ -143,7 +138,6 @@ class DataBinding {
             }
 
         } else if (attrInfo.type == Atomic.VAR_VECTOR2) {
-
             var layout = new Atomic.UILayout();
             widget = layout;
             layout.spacing = 0;
@@ -177,6 +171,7 @@ class DataBinding {
                 parent.gravity = Atomic.UI_GRAVITY_LEFT_RIGHT;
                 parent.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
 
+
                 var lp = new Atomic.UILayoutParams();
                 lp.width = 140;
                 o.editField.layoutParams = lp;
@@ -272,7 +267,6 @@ class DataBinding {
     }
 
     setWidgetValueFromObject() {
-
         if (this.widgetLocked)
             return;
 
@@ -467,7 +461,7 @@ class DataBinding {
 
     handleUIWidgetFocusChangedEvent(ev: Atomic.UIWidgetFocusChangedEvent) {
 
-        // does our object have a scene property? (Node/Component)
+        // TODO: once new base class stuff is in, should be able to check for type
         var scene = this.object["scene"];
 
         if (!scene)
@@ -483,7 +477,7 @@ class DataBinding {
             if (this.initalEditValue != ev.widget.text) {
 
                 // focus changed, with value change record in history
-                this.createHistorySnapshot();
+                scene.sendEvent("SceneEditSerializable", { serializable: this.object, operation: 1 });
 
             }
 
@@ -504,7 +498,6 @@ class DataBinding {
 
                 this.object.setAttribute(this.attrInfo.name, Number(ev.refid) - 1);
                 this.setWidgetValueFromObject();
-                this.createHistorySnapshot();
 
             }
 
@@ -520,6 +513,7 @@ class DataBinding {
 
             }
 
+
         }
 
         if (ev.type == Atomic.UI_EVENT_TYPE_CHANGED) {
@@ -528,9 +522,11 @@ class DataBinding {
                 //EditorUI.getCurrentResourceEditor().setModified(true);
                 this.setObjectValueFromWidget(ev.target);
 
-                // create a history snapshot, UIEditFields handle this when losing focus
-                if (ev.target.getTypeName() != "UIEditField") {
-                    this.createHistorySnapshot();
+                if (ev.target.getTypeName() != "UIEditField" && ev.target.getTypeName() != "UIInlineSelect") {
+
+                    // TODO: once new base class stuff is in, should be able to check for type
+                    if (this.object["scene"])
+                        this.object["scene"].sendEvent("SceneEditSerializable", { serializable: this.object, operation: 1 });
                 }
 
                 return true;
@@ -541,23 +537,12 @@ class DataBinding {
 
     }
 
-    createHistorySnapshot() {
-
-        if (this.object.getTypeName() == "Node") {
-            this.object.sendEvent("HistoryNodeChanged", { scene: this.object["scene"], node: this.object });
-        } else if (this.object["node"]) { // TODO: need better component detection
-            this.object.sendEvent("HistoryComponentChanged", { scene: this.object["scene"], component: this.object });
-        }
-
-    }
-
     object: Atomic.Serializable;
     objectLocked: boolean = true;
     widgetLocked: boolean = false;
     attrInfo: Atomic.AttributeInfo;
     widget: Atomic.UIWidget;
     enumSource: Atomic.UISelectItemSource;
-
     initalEditValue: string;
 
 }

+ 5 - 9
Script/AtomicEditor/ui/frames/inspector/NodeInspector.ts

@@ -120,10 +120,11 @@ class NodeInspector extends ScriptWidget {
 
         this.bindings = new Array();
 
-        this.subscribeToEvent(node, "HistoryNodeChangedUndoRedo", (ev) => this.handleHistoryNodeChangedUndoRedo(ev));        
-
         this.node = node;
 
+        node.scene.sendEvent("SceneEditSerializable", { serializable: node, operation: 0});
+        this.subscribeToEvent(node, "SceneEditSerializableUndoRedo", (data) => this.handleSceneEditSerializableUndoRedoEvent(data));        
+
         this.isPrefab = this.detectPrefab(node);
 
         var fd = new Atomic.UIFontDescription();
@@ -316,22 +317,17 @@ class NodeInspector extends ScriptWidget {
 
     }
 
-    handleHistoryNodeChangedUndoRedo(ev) {
+    handleSceneEditSerializableUndoRedoEvent(ev) {
 
       for (var i in this.bindings) {
           this.bindings[i].objectLocked = true;
-      }
-
-      for (var i in this.bindings) {
           this.bindings[i].setWidgetValueFromObject();
-      }
-
-      for (var i in this.bindings) {
           this.bindings[i].objectLocked = false;
       }
 
     }
 
+
     isPrefab: boolean;
     node: Atomic.Node;
     nodeLayout: Atomic.UILayout;

+ 16 - 2
Source/AtomicEditor/Editors/SceneEditor3D/Gizmo3D.cpp

@@ -21,7 +21,8 @@ namespace AtomicEditor
 {
 
 
-Gizmo3D::Gizmo3D(Context* context) : Object(context)
+Gizmo3D::Gizmo3D(Context* context) : Object(context),
+    dragging_(false)
 {
     ResourceCache* cache = GetSubsystem<ResourceCache>();
 
@@ -169,7 +170,18 @@ void Gizmo3D::Use()
     // Recalculate axes only when not left-dragging
     bool drag = input->GetMouseButtonDown(MOUSEB_LEFT);// && (Abs(input->GetMouseMoveX()) > 3 || Abs(input->GetMouseMoveY()) > 3);
     if (!drag)
+    {
+        if (dragging_)
+        {
+            VariantMap eventData;
+            eventData[SceneEditSerializable::P_SERIALIZABLE] = editNodes_->At(0);
+            eventData[SceneEditSerializable::P_OPERATION] = 1;
+            scene_->SendEvent(E_SCENEEDITSERIALIZABLE, eventData);
+            dragging_ = false;
+        }
+
         CalculateGizmoAxes();
+    }
 
     gizmoAxisX_.Update(cameraRay, scale, drag, camera_->GetNode());
     gizmoAxisY_.Update(cameraRay, scale, drag, camera_->GetNode());
@@ -209,7 +221,7 @@ void Gizmo3D::Use()
         gizmoAxisZ_.lastSelected_ = gizmoAxisZ_.selected_;
     }
 
-    if (drag)
+    if (drag && Selected())
         Drag();
 
 }
@@ -359,6 +371,8 @@ void Gizmo3D::Drag()
 {
     bool moved = false;
 
+    dragging_ = true;
+
     float scale = gizmoNode_->GetScale().x_;
 
     if (editMode_ == EDIT_MOVE)

+ 1 - 0
Source/AtomicEditor/Editors/SceneEditor3D/Gizmo3D.h

@@ -152,6 +152,7 @@ private:
     AxisMode axisMode_;
 
     Vector<Node *> *editNodes_;
+    bool dragging_;
 
 };
 

+ 43 - 157
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditHistory.cpp

@@ -16,16 +16,9 @@ namespace AtomicEditor
 
 SceneEditHistory::SceneEditHistory(Context* context, Scene* scene) :
     Object(context),
-    scene_(scene),
-    locked_(false)
+    scene_(scene)
 {
-    SubscribeToEvent(E_HISTORYNODEADDED, HANDLER(SceneEditHistory, HandleHistoryNodeAdded));
-    SubscribeToEvent(E_HISTORYNODEREMOVED, HANDLER(SceneEditHistory, HandleHistoryNodeRemoved));
-    SubscribeToEvent(E_HISTORYNODECHANGED, HANDLER(SceneEditHistory, HandleHistoryNodeChanged));
-
-    SubscribeToEvent(E_HISTORYCOMPONENTCHANGED, HANDLER(SceneEditHistory, HandleHistoryComponentChanged));
-
-    SubscribeToEvent(E_EDITORACTIVENODECHANGE, HANDLER(SceneEditHistory, HandleEditorActiveNodeChange));
+    SubscribeToEvent(scene_, E_SCENEEDITSERIALIZABLE, HANDLER(SceneEditHistory, HandleSceneEditSerializable));    
 }
 
 SceneEditHistory::~SceneEditHistory()
@@ -33,151 +26,73 @@ SceneEditHistory::~SceneEditHistory()
 
 }
 
-void SceneEditHistory::AddUndoOp(SceneHistoryOp* op)
+void SceneEditHistory::AddUndoOp(SceneEditOp* op)
 {
     undoHistory_.Push(op);
 
-    // adding a new undo op invalids redos
     for (unsigned i = 0; i < redoHistory_.Size(); i++)
     {
         delete redoHistory_[i];
     }
 
     redoHistory_.Clear();
-
-    if (activeNode_.NotNull())
-    {
-        if (op->type_ == SCENEHISTORYOP_NODECHANGED)
-        {
-            activeNodeCurrentState_.Clear();
-            activeNode_->Animatable::Save(activeNodeCurrentState_);
-            activeNodeCurrentState_.Seek(0);
-        }
-
-        if (op->type_ == SCENEHISTORYOP_COMPONENTCHANGED)
-        {
-            ComponentChangedOp* ccop = (ComponentChangedOp*) op;
-            currentComponentStates_[ccop->component_].Clear();
-            ccop->component_->Animatable::Save(currentComponentStates_[ccop->component_]);
-            currentComponentStates_[ccop->component_].Seek(0);
-        }
-    }
-
 }
 
-void SceneEditHistory::HandleHistoryNodeAdded(StringHash eventType, VariantMap& eventData)
+void SceneEditHistory::HandleSceneEditSerializableUndoRedo(StringHash eventType, VariantMap& eventData)
 {
-    if (locked_)
-        return;
-
-    Scene* scene = static_cast<Scene*>(eventData[HistoryNodeAdded::P_SCENE].GetPtr());
-    if (scene != scene_)
-        return;
+    SharedPtr<Serializable> serial(static_cast<Serializable*>(eventData[SceneEditSerializableUndoRedo::P_SERIALIZABLE].GetPtr()));
 
-    Node* node = static_cast<Node*>(eventData[HistoryNodeAdded::P_NODE].GetPtr());
-
-    NodeAddedOp* op = new NodeAddedOp(node);
-    AddUndoOp(op);
-}
-
-void SceneEditHistory::HandleHistoryNodeChanged(StringHash eventType, VariantMap& eventData)
-{
-    if (locked_)
-        return;
-
-    Scene* scene = static_cast<Scene*>(eventData[HistoryNodeChanged::P_SCENE].GetPtr());
-
-    if (scene != scene_)
-        return;
-
-    Node* node = static_cast<Node*>(eventData[HistoryNodeChanged::P_NODE].GetPtr());
-
-    NodeChangedOp* op = new NodeChangedOp(node, activeNodeCurrentState_);
-
-    if (activeNodeCurrentState_.GetSize() != op->newState_.GetSize() ||
-            memcmp(activeNodeCurrentState_.GetData(), op->newState_.GetData(), op->newState_.GetSize()))
-    {
-        activeNodeCurrentState_ = op->newState_;
-        AddUndoOp(op);
-    }
-    else
+    if (editStates_.Contains(serial))
     {
-        delete op;
+        editStates_[serial] = eventData[SceneEditSerializableUndoRedo::P_STATE].GetVectorBuffer();
     }
-
-}
-
-void SceneEditHistory::HandleHistoryNodeRemoved(StringHash eventType, VariantMap& eventData)
-{
-    if (locked_)
-        return;
 }
 
-void SceneEditHistory::HandleEditorActiveNodeChange(StringHash eventType, VariantMap& eventData)
+void SceneEditHistory::HandleSceneEditSerializable(StringHash eventType, VariantMap& eventData)
 {
-    Node* node = static_cast<Node*>(eventData[EditorActiveNodeChange::P_NODE].GetPtr());
-
-    if (activeNode_ == node)
-        return;
 
-    activeNode_ = node;
-    activeNodeCurrentState_.Clear();
-    currentComponentStates_.Clear();
+    int editop = eventData[SceneEditSerializable::P_OPERATION].GetInt();
 
-    if (activeNode_.Null())
-        return;
+    SharedPtr<Serializable> serial(static_cast<Serializable*>(eventData[SceneEditSerializable::P_SERIALIZABLE].GetPtr()));
 
-    node->Animatable::Save(activeNodeCurrentState_);
-    activeNodeCurrentState_.Seek(0);
-
-    const Vector<SharedPtr<Component> >& comps = activeNode_->GetComponents();
-    for (unsigned i = 0; i < comps.Size(); i++)
+    if (editop == 0) // begin
     {
-        comps[i]->Animatable::Save(currentComponentStates_[comps[i]]);
-        currentComponentStates_[comps[i]].Seek(0);
+        if (editStates_.Contains(serial))
+            return;
+
+        SubscribeToEvent(serial, E_SCENEEDITSERIALIZABLEUNDOREDO, HANDLER(SceneEditHistory, HandleSceneEditSerializableUndoRedo));
+        VectorBuffer& vb = editStates_[serial];
+        vb.Clear();
+        serial->Serializable::Save(vb);
+        vb.Seek(0);
     }
-}
-
-void SceneEditHistory::HandleHistoryComponentChanged(StringHash eventType, VariantMap& eventData)
-{
-    if (locked_)
-        return;
-
-    Component* component = static_cast<Component*>(eventData[HistoryComponentChanged::P_COMPONENT].GetPtr());
-
-    if (!component || component->GetNode() != activeNode_)
-        return;
-
-    assert(currentComponentStates_.Contains(component));
+    else if (editop == 1) // change
+    {
+        if (!editStates_.Contains(serial))
+            return;
 
-    ComponentChangedOp* op = new ComponentChangedOp(component, currentComponentStates_[component]);
+        VectorBuffer& beginState = editStates_[serial];
+        VectorBuffer deltaState;
+        serial->Serializable::Save(deltaState);
+        deltaState.Seek(0);
 
-    if (currentComponentStates_[component].GetSize() != op->newState_.GetSize() ||
-            memcmp(currentComponentStates_[component].GetData(), op->newState_.GetData(), op->newState_.GetSize()))
-    {
-        activeNodeCurrentState_ = op->newState_;
-        AddUndoOp(op);
+        if (beginState.GetSize() != deltaState.GetSize() ||
+                memcmp(beginState.GetData(), deltaState.GetData(), deltaState.GetSize()))
+        {
+            SerializableEditOp* op = new SerializableEditOp(serial, beginState, deltaState);
+            AddUndoOp(op);
+            editStates_[serial] = deltaState;
+        }
     }
-    else
+    else if (editop == 2) // end
     {
-        delete op;
-    }
-
-
-}
+        if (!editStates_.Contains(serial))
+            return;
 
-void SceneEditHistory::BeginUndoRedo()
-{
-    //VariantMap evData;
-    //evData[SceneUndoRedoBegin::P_SCENE] = scene_;
-    //SendEvent(E_SCENEUNDOREDOBEGIN, evData);
-}
+        UnsubscribeFromEvent(serial, E_SCENEEDITSERIALIZABLEUNDOREDO);
 
-void SceneEditHistory::EndUndoRedo()
-{
-    //VariantMap evData;
-    //evData[SceneUndoRedoEnd::P_SCENE] = scene_;
-    //SendEvent(E_SCENEUNDOREDOEND, evData);
+        editStates_.Erase(serial);
+    }
 }
 
 void SceneEditHistory::Undo()
@@ -185,26 +100,13 @@ void SceneEditHistory::Undo()
     if (!undoHistory_.Size())
         return;
 
-    SceneHistoryOp* op = undoHistory_.Back();
+    SceneEditOp* op = undoHistory_.Back();
     undoHistory_.Pop();
 
     op->Undo();
 
-    VariantMap eventData;
-    if (op->type_ == SCENEHISTORYOP_NODECHANGED)
-    {
-        NodeChangedOp* ncop = (NodeChangedOp*) op;
-        eventData[HistoryNodeChangedUndoRedo::P_NODE] = ncop->node_;
-        ncop->node_->SendEvent(E_HISTORYNODECHANGEDUNDOREDO, eventData);
-    }
-    else if (op->type_ == SCENEHISTORYOP_COMPONENTCHANGED)
-    {
-        ComponentChangedOp* ccop = (ComponentChangedOp*) op;
-        eventData[HistoryComponentChangedUndoRedo::P_COMPONENT] = ccop->component_;
-        ccop->component_->SendEvent(E_HISTORYCOMPONENTCHANGEDUNDOREDO, eventData);
-    }
-
     redoHistory_.Push(op);
+
 }
 
 void SceneEditHistory::Redo()
@@ -212,29 +114,13 @@ void SceneEditHistory::Redo()
     if (!redoHistory_.Size())
         return;
 
-    SceneHistoryOp* op = redoHistory_.Back();
+    SceneEditOp* op = redoHistory_.Back();
     redoHistory_.Pop();
 
     op->Redo();
 
     undoHistory_.Push(op);
 
-    VariantMap eventData;
-    if (op->type_ == SCENEHISTORYOP_NODECHANGED)
-    {
-        NodeChangedOp* ncop = (NodeChangedOp*) op;
-        eventData[HistoryNodeChangedUndoRedo::P_NODE] = ncop->node_;
-        ncop->node_->SendEvent(E_HISTORYNODECHANGEDUNDOREDO, eventData);
-    }
-    else if (op->type_ == SCENEHISTORYOP_COMPONENTCHANGED)
-    {
-        ComponentChangedOp* ccop = (ComponentChangedOp*) op;
-        eventData[HistoryComponentChangedUndoRedo::P_COMPONENT] = ccop->component_;
-        ccop->component_->SendEvent(E_HISTORYCOMPONENTCHANGEDUNDOREDO, eventData);
-    }
-
-
-
 }
 
 }

+ 8 - 25
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditHistory.h

@@ -13,16 +13,15 @@ using namespace Atomic;
 namespace Atomic
 {
 
+class Serializable;
 class Scene;
-class Node;
-class Component;
 
 }
 
 namespace AtomicEditor
 {
 
-class SceneHistoryOp;
+class SceneEditOp;
 
 /// Simple scene history to support undo/redo via snapshots of scene state
 class SceneEditHistory: public Object
@@ -37,35 +36,19 @@ public:
     void Undo();
     void Redo();
 
-    void Lock() { locked_ = true; }
-    void Unlock() { locked_ = false; }
-
 private:
 
-    void HandleEditorActiveNodeChange(StringHash eventType, VariantMap& eventData);
-
-    void HandleHistoryNodeAdded(StringHash eventType, VariantMap& eventData);
-    void HandleHistoryNodeRemoved(StringHash eventType, VariantMap& eventData);
-    void HandleHistoryNodeChanged(StringHash eventType, VariantMap& eventData);
-
-    void HandleHistoryComponentChanged(StringHash eventType, VariantMap& eventData);
+    void HandleSceneEditSerializable(StringHash eventType, VariantMap& eventData);
+    void HandleSceneEditSerializableUndoRedo(StringHash eventType, VariantMap& eventData);
 
-
-    void AddUndoOp(SceneHistoryOp* op);
-
-    void BeginUndoRedo();
-    void EndUndoRedo();
+    void AddUndoOp(SceneEditOp* op);
 
     WeakPtr<Scene> scene_;
 
-    WeakPtr<Node> activeNode_;
-    VectorBuffer activeNodeCurrentState_;
-
-    HashMap<Component*, VectorBuffer> currentComponentStates_;
+    HashMap< SharedPtr<Serializable>, VectorBuffer > editStates_;
 
-    bool locked_;
-    PODVector<SceneHistoryOp*> undoHistory_;
-    PODVector<SceneHistoryOp*> redoHistory_;
+    PODVector<SceneEditOp*> undoHistory_;
+    PODVector<SceneEditOp*> redoHistory_;
 
 };
 

+ 46 - 47
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditOps.cpp

@@ -1,12 +1,15 @@
 
+#include <Atomic/IO/Log.h>
 #include <Atomic/Scene/Node.h>
 #include <Atomic/Scene/Component.h>
 
 #include "SceneEditOps.h"
+#include "SceneEditor3DEvents.h"
 
 namespace AtomicEditor
 {
 
+
 NodeEditOp::NodeEditOp(Node* node)
 {
     node_ = node;
@@ -15,78 +18,74 @@ NodeEditOp::NodeEditOp(Node* node)
     parent_ = node->GetParent();
 }
 
-NodeAddedOp::NodeAddedOp(Node* node) : NodeEditOp(node)
+NodeAddedRemovedOp::NodeAddedRemovedOp(Node* node, bool added) : NodeEditOp(node),
+    added_(added)
 {
-    type_ = SCENEHISTORYOP_NODEADDED;
-
+    type_ = SCENEEDIT_NODE_ADDED_REMOVED;
 }
 
-bool NodeAddedOp::Undo()
+bool NodeAddedRemovedOp::Undo()
 {
-    node_->Remove();
     return true;
 }
 
-bool NodeAddedOp::Redo()
+bool NodeAddedRemovedOp::Redo()
 {
-    parent_->AddChild(node_);
     return true;
 }
 
-NodeChangedOp::NodeChangedOp(Node* node, const VectorBuffer& prevState) : NodeEditOp(node)
+SerializableEditOp::SerializableEditOp(Serializable* serializable, const VectorBuffer& beginState, const VectorBuffer& endState) : SceneEditOp(),
+    serializable_(serializable),
+    beginState_(beginState),
+    endState_(endState)
 {
-    type_ = SCENEHISTORYOP_NODECHANGED;
+    type_ = SCENEEDIT_SERIALIZABLE_EDIT;
 
-    prevState_ = prevState;
-    node->Animatable::Save(newState_);
-    newState_.Seek(0);
-}
-
-bool NodeChangedOp::Undo()
-{
-    node_->Animatable::Load(prevState_);
-    prevState_.Seek(0);
-    return true;
-}
+    if (!beginState_.GetSize())
+    {
+        LOGERRORF("Zero size beginState");
+    }
 
-bool NodeChangedOp::Redo()
-{
-    node_->Animatable::Load(newState_);
-    newState_.Seek(0);
-    return true;
+    if (!endState_.GetSize())
+    {
+        LOGERRORF("Zero size endState");
+    }
 }
 
-//------------ Component Ops
+bool SerializableEditOp::Undo()
+{    
+    if (!serializable_->Serializable::Load(beginState_))
+    {
+        LOGERRORF("Error loading beginState");
+    }
+    beginState_.Seek(0);
 
-ComponentEditOp::ComponentEditOp(Component* component)
-{
-    component_ = component;
+    VariantMap eventData;
+    eventData[SceneEditSerializableUndoRedo::P_SERIALIZABLE] = serializable_;
+    eventData[SceneEditSerializableUndoRedo::P_UNDO] = true;
+    eventData[SceneEditSerializableUndoRedo::P_STATE] = beginState_;
+    serializable_->SendEvent(E_SCENEEDITSERIALIZABLEUNDOREDO, eventData);
 
+    return true;
 }
 
-ComponentChangedOp::ComponentChangedOp(Component* component, const VectorBuffer& prevState) : ComponentEditOp(component)
+bool SerializableEditOp::Redo()
 {
-    type_ = SCENEHISTORYOP_COMPONENTCHANGED;
 
-    prevState_ = prevState;
-    component_->Animatable::Save(newState_);
-    newState_.Seek(0);
-}
+    if (!serializable_->Serializable::Load(endState_))
+    {
+        LOGERRORF("Error loading endState");
+    }
 
-bool ComponentChangedOp::Undo()
-{
-    component_->Animatable::Load(prevState_);
-    prevState_.Seek(0);
-    return true;
-}
+    endState_.Seek(0);
+
+    VariantMap eventData;
+    eventData[SceneEditSerializableUndoRedo::P_SERIALIZABLE] = serializable_;
+    eventData[SceneEditSerializableUndoRedo::P_UNDO] = false;
+    eventData[SceneEditSerializableUndoRedo::P_STATE] = endState_;
+    serializable_->SendEvent(E_SCENEEDITSERIALIZABLEUNDOREDO, eventData);
 
-bool ComponentChangedOp::Redo()
-{
-    component_->Animatable::Load(newState_);
-    newState_.Seek(0);
     return true;
 }
 
-
-
 }

+ 32 - 33
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditOps.h

@@ -16,6 +16,7 @@ namespace Atomic
 class Scene;
 class Node;
 class Component;
+class Serializable;
 
 }
 
@@ -24,32 +25,30 @@ using namespace Atomic;
 namespace AtomicEditor
 {
 
-enum SceneHistoryOpType
+enum SceneEditType
 {
-    SCENEHISTORYOP_UNKNOWN = 0,
-    SCENEHISTORYOP_NODEADDED,
-    SCENEHISTORYOP_NODEREMOVED,
-    SCENEHISTORYOP_NODECHANGED,
-
-    SCENEHISTORYOP_COMPONENTCHANGED
+    SCENEEDIT_UNKNOWN = 0,
+    SCENEEDIT_NODE_ADDED_REMOVED,
+    SCENEEDIT_COMPONENT_ADDED_REMOVED,
+    SCENEEDIT_SERIALIZABLE_EDIT,
 };
 
-class SceneHistoryOp
+class SceneEditOp
 {
 
 public:
 
-    SceneHistoryOp() { type_ = SCENEHISTORYOP_UNKNOWN; }
-    virtual ~SceneHistoryOp() { }
+    SceneEditOp() { type_ = SCENEEDIT_UNKNOWN; }
+    virtual ~SceneEditOp() { }
 
     virtual bool Undo() = 0;
     virtual bool Redo() = 0;
 
-    SceneHistoryOpType type_;
+    SceneEditType type_;
 
 };
 
-class NodeEditOp : public SceneHistoryOp
+class NodeEditOp : public SceneEditOp
 {
 protected:
 
@@ -62,33 +61,20 @@ public:
 
 };
 
-class NodeAddedOp : public NodeEditOp
+class NodeAddedRemovedOp : public NodeEditOp
 {
 
 public:
 
-    NodeAddedOp(Node* node);
-
-    bool Undo();
-    bool Redo();
-};
-
-class NodeChangedOp : public NodeEditOp
-{
+    NodeAddedRemovedOp(Node* node, bool added);
 
-public:
-
-    NodeChangedOp(Node* node, const VectorBuffer& prevState);
+    bool added_;
 
     bool Undo();
     bool Redo();
-
-    VectorBuffer prevState_;
-    VectorBuffer newState_;
-
 };
 
-class ComponentEditOp : public SceneHistoryOp
+class ComponentEditOp : public SceneEditOp
 {
 protected:
 
@@ -100,19 +86,32 @@ public:
 
 };
 
-class ComponentChangedOp : public ComponentEditOp
+class ComponentAddedRemovedOp : public ComponentEditOp
 {
 
 public:
 
-    ComponentChangedOp(Component* component, const VectorBuffer& prevState);
+    ComponentAddedRemovedOp(Node* node, bool added);
+
+    bool added_;
 
     bool Undo();
     bool Redo();
+};
+
+class SerializableEditOp : public SceneEditOp
+{
 
-    VectorBuffer prevState_;
-    VectorBuffer newState_;
+public:
+
+    SerializableEditOp(Serializable* serializable, const VectorBuffer& beginState, const VectorBuffer& endState);
+
+    SharedPtr<Serializable> serializable_;
+    VectorBuffer beginState_;
+    VectorBuffer endState_;
 
+    bool Undo();
+    bool Redo();
 };
 
 

+ 15 - 25
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3DEvents.h

@@ -28,42 +28,32 @@ EVENT(E_GIZMOMOVED, GizmoMoved)
 
 }
 
-EVENT(E_HISTORYNODEADDED, HistoryNodeAdded)
+EVENT(E_SCENEEDITNODEADDEDREMOVED, SceneEditNodeAddedRemoved)
 {
-    PARAM(P_SCENE, Scene);            // Scene
-    PARAM(P_NODE, Node);            // Node
+    PARAM(P_SCENE, Scene);             // Scene
+    PARAM(P_NODE, Node);               // Node
+    PARAM(P_ADDED, Added);             // bool
 }
 
-EVENT(E_HISTORYNODEREMOVED, HistoryNodeRemoved)
+EVENT(E_SCENEEDITCOMPONENTADDEDREMOVED, SceneEditComponentAddedRemoved)
 {
-    PARAM(P_SCENE, Scene);            // Scene
-    PARAM(P_NODE, Node);             // Node
+    PARAM(P_SCENE, Scene);             // Scene
+    PARAM(P_COMPONENT, Component);     // Component
+    PARAM(P_ADDED, Added);             // bool
 }
 
-EVENT(E_HISTORYNODECHANGED, HistoryNodeChanged)
+EVENT(E_SCENEEDITSERIALIZABLE, SceneEditSerializable)
 {
-    PARAM(P_SCENE, Scene);            // Scene
-    PARAM(P_NODE, Node);              // Node
+    PARAM(P_SERIALIZABLE, Serializable);     // Serializable
+    PARAM(P_OPERATION, Operation);           // int (0: begin, 1: change, 2: end)
 }
 
-EVENT(E_HISTORYCOMPONENTCHANGED, HistoryComponentChanged)
+EVENT(E_SCENEEDITSERIALIZABLEUNDOREDO, SceneEditSerializableUndoRedo)
 {
-    PARAM(P_SCENE, Scene);            // Scene
-    PARAM(P_COMPONENT, Component);    // Component
+    PARAM(P_SERIALIZABLE, Serializable);     // Serializable
+    PARAM(P_STATE, State);                   // State (VectorBuffer);
+    PARAM(P_UNDO, Undo);                     // bool (true: undo, false: redo)
 }
 
-EVENT(E_HISTORYNODECHANGEDUNDOREDO, HistoryNodeChangedUndoRedo)
-{
-    PARAM(P_SCENE, Scene);            // Scene
-    PARAM(P_NODE, Node);    // Node
-}
-
-EVENT(E_HISTORYCOMPONENTCHANGEDUNDOREDO, HistoryComponentChangedUndoRedo)
-{
-    PARAM(P_SCENE, Scene);            // Scene
-    PARAM(P_COMPONENT, Component);    // Component
-}
-
-
 
 }

+ 0 - 5
Source/AtomicEditor/Editors/SceneEditor3D/SceneView3D.cpp

@@ -516,11 +516,6 @@ void SceneView3D::HandleDragEnded(StringHash eventType, VariantMap& eventData)
         VariantMap neventData;
         neventData[EditorActiveNodeChange::P_NODE] = dragNode_;
         SendEvent(E_EDITORACTIVENODECHANGE, neventData);
-
-        VariantMap heventData;
-        heventData[HistoryNodeAdded::P_NODE] = dragNode_;
-        heventData[HistoryNodeAdded::P_SCENE] = scene_;
-        SendEvent(E_HISTORYNODEADDED, heventData);
     }
 
     if (dragObject && dragObject->GetObject()->GetType() == ToolCore::Asset::GetTypeStatic())