Browse Source

Scene change events. Removes need for hardcoded hierarchy updates in the editor. May potentially have caused regressions, so needs to be approached with care.

Lasse Öörni 12 years ago
parent
commit
171e802c8f

+ 1 - 1
Bin/Data/Scripts/Editor/EditorImport.as

@@ -42,7 +42,7 @@ void ImportModel(const String&in fileName)
         newModel.model = cache.GetResource("Model", modelName);
         ApplyMaterialList(newModel);
 
-        UpdateAndFocusNode(newNode);
+        FocusNode(newNode);
     }
 }
 

+ 8 - 5
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -47,7 +47,7 @@ void CreateNodeWindow()
     SubscribeToEvent(nodeWindow.GetChild("CloseButton", true), "Released", "HideNodeWindow");
     SubscribeToEvent(nodeWindow.GetChild("NewVarDropDown", true), "ItemSelected", "CreateNewVariable");
     SubscribeToEvent(nodeWindow.GetChild("DeleteVarButton", true), "Released", "DeleteVariable");
-    SubscribeToEvent("ScriptObjectCreated", "HandleScriptObjectCreated");
+    SubscribeToEvent("AttributeListChanged", "HandleAttributeListChanged");
 }
 
 void HideNodeWindow()
@@ -287,13 +287,16 @@ void DeleteVariable(StringHash eventType, VariantMap& eventData)
         UpdateAttributes(false);
 }
 
-void HandleScriptObjectCreated(StringHash eventType, VariantMap& eventData)
+void HandleAttributeListChanged(StringHash eventType, VariantMap& eventData)
 {
-    Object@ sender = GetEventSender();
-    
+    if (suppressSceneChanges)
+        return;
+
+    Component@ component = eventData["Component"].GetComponent();
+
     for (uint i = 0; i < editComponents.length; ++i)
     {
-        if (sender is editComponents[i])
+        if (component is editComponents[i])
         {
             // Update inspector fully, as attribute set might have changed
             UpdateAttributes(true);

+ 11 - 29
Bin/Data/Scripts/Editor/EditorScene.as

@@ -26,7 +26,6 @@ uint numEditableComponentsPerNode = 1;
 
 Array<XMLFile@> copyBuffer;
 bool copyBufferLocal = false;
-bool copyBufferExpanded = false;
 
 bool inSelectionModify = false;
 
@@ -61,6 +60,8 @@ void ResetScene()
 {
     ClearSelection();
 
+    suppressSceneChanges = true;
+
     // Create a scene with default values, these will be overridden when loading scenes
     editorScene.Clear();
     editorScene.name = "";
@@ -71,6 +72,8 @@ void ResetScene()
 
     UpdateSceneWindow();
     UpdateNodeWindow();
+    
+    suppressSceneChanges = false;
 
     runUpdate = false;
     sceneFileName = "";
@@ -190,7 +193,7 @@ bool LoadScene(const String&in fileName)
 {
     if (fileName.empty)
         return false;
-    
+
     ui.cursor.shape = CS_BUSY;
     
     // Always load the scene from the filesystem, not from resource paths
@@ -205,6 +208,8 @@ bool LoadScene(const String&in fileName)
         return false;
 
     // Clear the old scene
+    suppressSceneChanges = true;
+
     ClearSelection();
     editorScene.Clear();
 
@@ -227,6 +232,9 @@ bool LoadScene(const String&in fileName)
     UpdateWindowTitle();
     UpdateSceneWindow();
     UpdateNodeWindow();
+
+    suppressSceneChanges = false;
+
     ResetCamera();
     CreateGizmo();
 
@@ -285,7 +293,7 @@ void LoadNode(const String&in fileName)
 
     if (newNode !is null)
     {
-        UpdateAndFocusNode(newNode);
+        FocusNode(newNode);
         instantiateFileName = fileName;
     }
 }
@@ -371,8 +379,6 @@ bool SceneDelete()
         node.Remove();
         EndModify(id);
 
-        UpdateSceneWindowNode(nodeIndex, null);
-
         // If deleting only one node, select the next item in the same index
         if (selectedNodes.length == 1 && selectedComponents.empty)
             list.selection = nodeIndex;
@@ -401,8 +407,6 @@ bool SceneDelete()
         node.RemoveComponent(component);
         EndModify(id);
 
-        UpdateSceneWindowNode(nodeIndex, node);
-
         // If deleting only one component, select the next item in the same index
         if (selectedComponents.length == 1 && selectedNodes.empty)
             list.selection = index;
@@ -463,7 +467,6 @@ bool SceneCopy()
             copyBuffer.Push(xml);
         }
 
-        copyBufferExpanded = SaveExpandedStatus(GetNodeListIndex(selectedNodes[0]));
         return true;
     }
 }
@@ -513,16 +516,9 @@ bool ScenePaste()
             newNode.ApplyAttributes();
             EndModify(newNode.id);
             EndModify(editorScene.id);
-
-            uint addIndex = GetParentAddIndex(newNode);
-            UpdateSceneWindowNode(addIndex, newNode);
-            RestoreExpandedStatus(addIndex, copyBufferExpanded);
         }
     }
 
-    if (pasteComponents)
-        UpdateSceneWindowNode(editNode);
-
     return true;
 }
 
@@ -532,7 +528,6 @@ void SceneUnparent()
         return;
 
     ListView@ list = sceneWindow.GetChild("NodeList", true);
-    list.contentElement.DisableLayoutUpdate();
 
     // Parent selected nodes to root
     for (uint i = 0; i < selectedNodes.length; ++i)
@@ -549,20 +544,7 @@ void SceneUnparent()
         sourceNode.parent = targetNode;
         EndModify(sourceNode.id);
         EndModify(targetNode.id);
-
-        ListView@ list = sceneWindow.GetChild("NodeList", true);
-
-        uint sourceIndex = GetNodeListIndex(sourceNode);
-        bool expanded = SaveExpandedStatus(sourceIndex);
-        list.RemoveItem(sourceIndex);
-        uint addIndex = GetParentAddIndex(sourceNode);
-        UpdateSceneWindowNode(addIndex, sourceNode);
-        UpdateNodeAttributes();
-        RestoreExpandedStatus(addIndex, expanded);
     }
-
-    list.contentElement.EnableLayoutUpdate();
-    list.contentElement.UpdateLayout();
 }
 
 void SceneResetPosition()

+ 60 - 51
Bin/Data/Scripts/Editor/EditorSceneWindow.as

@@ -7,6 +7,8 @@ const uint NO_ITEM = 0xffffffff;
 
 Window@ sceneWindow;
 
+bool suppressSceneChanges = false;
+
 void CreateSceneWindow()
 {
     if (sceneWindow !is null)
@@ -57,8 +59,10 @@ void CreateSceneWindow()
     SubscribeToEvent(newComponentList, "ItemSelected", "HandleCreateComponent");
     SubscribeToEvent("DragDropTest", "HandleDragDropTest");
     SubscribeToEvent("DragDropFinish", "HandleDragDropFinish");
-    SubscribeToEvent("BoneHierarchyCreated", "HandleBoneHierarchyCreated");
-    SubscribeToEvent("TerrainCreated", "HandleTerrainCreated");
+    SubscribeToEvent(editorScene, "NodeAdded", "HandleNodeAdded");
+    SubscribeToEvent(editorScene, "NodeRemoved", "HandleNodeRemoved");
+    SubscribeToEvent(editorScene, "ComponentAdded", "HandleComponentAdded");
+    SubscribeToEvent(editorScene, "ComponentRemoved", "HandleComponentRemoved");
 }
 
 void ShowSceneWindow()
@@ -116,16 +120,19 @@ uint UpdateSceneWindowNode(uint itemIndex, Node@ node)
 {
     ListView@ list = sceneWindow.GetChild("NodeList", true);
 
-    // Whenever we're updating the root, disable layout update to optimize speed
-    if (node is editorScene)
-        list.contentElement.DisableLayoutUpdate();
+    // Whenever we're updating, disable layout update to optimize speed
+    list.contentElement.DisableLayoutUpdate();
 
     // Remove old item if exists
     if (itemIndex < list.numItems && (node is null || (list.items[itemIndex].vars["Type"].GetInt() == ITEM_NODE &&
         list.items[itemIndex].vars["NodeID"].GetUInt() == node.id)))
         list.RemoveItem(itemIndex);
     if (node is null)
+    {
+        list.contentElement.EnableLayoutUpdate();
+        list.contentElement.UpdateLayout();
         return itemIndex;
+    }
 
     int indent = GetNodeIndent(node);
 
@@ -161,11 +168,8 @@ uint UpdateSceneWindowNode(uint itemIndex, Node@ node)
     }
 
     // Re-enable layout update (and do manual layout) now
-    if (node is editorScene)
-    {
-        list.contentElement.EnableLayoutUpdate();
-        list.contentElement.UpdateLayout();
-    }
+    list.contentElement.EnableLayoutUpdate();
+    list.contentElement.UpdateLayout();
 
     return itemIndex;
 }
@@ -378,7 +382,7 @@ void SelectNode(Node@ node, bool multiselect)
         list.ClearSelection();
         return;
     }
-                                
+
     uint nodeItem = GetNodeListIndex(node);
 
     // Go in the parent chain up to make sure the chain is expanded
@@ -636,7 +640,6 @@ void HandleDragDropFinish(StringHash eventType, VariantMap& eventData)
         targetNode = editorScene;
 
     // Perform the reparenting
-    // Set transform so that the world transform stays through the parent change
     BeginModify(targetNode.id);
     BeginModify(sourceNode.id);
     sourceNode.parent = targetNode;
@@ -646,18 +649,12 @@ void HandleDragDropFinish(StringHash eventType, VariantMap& eventData)
     // Verify success
     if (sourceNode.parent !is targetNode)
         return;
-    
-    // Update the node list now. If a node was moved into the root, this potentially refreshes the whole scene window.
-    // Therefore disable layout update first
-    ListView@ list = sceneWindow.GetChild("NodeList", true);
 
-    uint sourceIndex = GetNodeListIndex(sourceNode);
-    bool expanded = SaveExpandedStatus(sourceIndex);
-    list.RemoveItem(sourceIndex);
-    uint addIndex = GetParentAddIndex(sourceNode);
-    UpdateSceneWindowNode(addIndex, sourceNode);
+    // Node coordinates may change as a result of the drag/drop.
+    /// \todo This should also be detected via an event
     UpdateNodeAttributes();
-    RestoreExpandedStatus(addIndex, expanded);
+
+    FocusNode(sourceNode); // Focus the node at its new position in the list
 }
 
 bool TestSceneWindowElements(UIElement@ source, UIElement@ target)
@@ -685,17 +682,15 @@ bool TestSceneWindowElements(UIElement@ source, UIElement@ target)
     return true;
 }
 
-void UpdateAndFocusNode(Node@ node)
+void FocusNode(Node@ node)
 {
-    UpdateSceneWindowNode(node);
     uint index = GetNodeListIndex(node);
     ListView@ list = sceneWindow.GetChild("NodeList", true);
     list.selection = index;
 }
 
-void UpdateAndFocusComponent(Component@ component)
+void FocusComponent(Component@ component)
 {
-    UpdateSceneWindowNode(component.node);
     uint index = GetComponentListIndex(component);
     ListView@ list = sceneWindow.GetChild("NodeList", true);
     list.selection = index;
@@ -712,7 +707,7 @@ void HandleCreateNode(StringHash eventType, VariantMap& eventData)
     // Set the new node a certain distance from the camera
     newNode.position = GetNewNodePosition();
 
-    UpdateAndFocusNode(newNode);
+    FocusNode(newNode);
 }
 
 void HandleCreateComponent(StringHash eventType, VariantMap& eventData)
@@ -733,23 +728,7 @@ void HandleCreateComponent(StringHash eventType, VariantMap& eventData)
     /// \todo Allow to specify the createmode
     Component@ newComponent = editNode.CreateComponent(text.text, editNode.id < FIRST_LOCAL_ID ? REPLICATED : LOCAL);
 
-    UpdateAndFocusComponent(newComponent);
-}
-
-void HandleBoneHierarchyCreated(StringHash eventType, VariantMap& eventData)
-{
-    Node@ node = eventData["Node"].GetNode();
-    ListView@ list = sceneWindow.GetChild("NodeList", true);
-    if (list.numItems > 0 && GetNodeListIndex(node) != NO_ITEM)
-        UpdateSceneWindowNode(node);
-}
-
-void HandleTerrainCreated(StringHash eventType, VariantMap& eventData)
-{
-    Node@ node = eventData["Node"].GetNode();
-    ListView@ list = sceneWindow.GetChild("NodeList", true);
-    if (list.numItems > 0 && GetNodeListIndex(node) != NO_ITEM)
-        UpdateSceneWindowNode(node);
+    FocusComponent(newComponent);
 }
 
 void CreateBuiltinObject(const String& name)
@@ -761,7 +740,7 @@ void CreateBuiltinObject(const String& name)
     StaticModel@ object = newNode.CreateComponent("StaticModel");
     object.model = cache.GetResource("Model", "Models/" + name + ".mdl");
 
-    UpdateAndFocusNode(newNode);
+    FocusNode(newNode);
 }
 
 bool CheckSceneWindowFocus()
@@ -783,14 +762,44 @@ bool CheckForExistingGlobalComponent(Node@ node, const String&in typeName)
         return node.HasComponent(typeName);
 }
 
-bool SaveExpandedStatus(uint itemIndex)
+void HandleNodeAdded(StringHash eventType, VariantMap& eventData)
 {
-    ListView@ list = sceneWindow.GetChild("NodeList", true);
-    return list.items[itemIndex].vars["Expanded"].GetBool();
+    if (suppressSceneChanges)
+        return;
+
+    Node@ node = eventData["Node"].GetNode();
+    UpdateSceneWindowNode(node);
 }
 
-void RestoreExpandedStatus(uint itemIndex, bool expanded)
+void HandleNodeRemoved(StringHash eventType, VariantMap& eventData)
 {
-    ListView@ list = sceneWindow.GetChild("NodeList", true);
-    list.Expand(itemIndex, expanded);
+    if (suppressSceneChanges)
+        return;
+
+    Node@ node = eventData["Node"].GetNode();
+    uint index = GetNodeListIndex(node);
+    UpdateSceneWindowNode(index, null);
+}
+
+void HandleComponentAdded(StringHash eventType, VariantMap& eventData)
+{
+    if (suppressSceneChanges)
+        return;
+
+    Node@ node = eventData["Node"].GetNode();
+    UpdateSceneWindowNode(node);
 }
+
+void HandleComponentRemoved(StringHash eventType, VariantMap& eventData)
+{
+    if (suppressSceneChanges)
+        return;
+
+    Component@ component = eventData["Component"].GetComponent();
+    uint index = GetComponentListIndex(component);
+    if (index != NO_ITEM)
+    {
+        ListView@ list = sceneWindow.GetChild("NodeList", true);
+        list.RemoveItem(index);
+    }
+}

+ 17 - 0
Engine/Scene/Component.cpp

@@ -25,6 +25,7 @@
 #include "Context.h"
 #include "ReplicationState.h"
 #include "Scene.h"
+#include "SceneEvents.h"
 
 #include "DebugNew.h"
 
@@ -182,6 +183,22 @@ void Component::SetNode(Node* node)
     OnNodeSet(node_);
 }
 
+void Component::SendAttributeListChange()
+{
+    Scene* scene = GetScene();
+    if (scene)
+    {
+        using namespace AttributeListChanged;
+        
+        VariantMap eventData;
+        eventData[P_SCENE] = (void*)scene;
+        eventData[P_NODE] = (void*)GetNode();
+        eventData[P_COMPONENT] = (void*)this;
+        
+        scene->SendEvent(E_ATTRIBUTELISTCHANGED, eventData);
+    }
+}
+
 Component* Component::GetComponent(ShortStringHash type) const
 {
     return node_ ? node_->GetComponent(type) : 0;

+ 2 - 0
Engine/Scene/Component.h

@@ -94,6 +94,8 @@ protected:
     void SetID(unsigned id);
     /// Set scene node. Called by Node when creating the component.
     void SetNode(Node* node);
+    /// Send an attribute list change event.
+    void SendAttributeListChange();
     
     /// Scene node.
     Node* node_;

+ 53 - 0
Engine/Scene/Node.cpp

@@ -28,6 +28,7 @@
 #include "Profiler.h"
 #include "ReplicationState.h"
 #include "Scene.h"
+#include "SceneEvents.h"
 #include "SmoothedTransform.h"
 #include "XMLFile.h"
 
@@ -494,6 +495,19 @@ void Node::AddChild(Node* node)
     node->parent_ = this;
     node->MarkDirty();
     node->MarkNetworkUpdate();
+    
+    // Send change event
+    if (scene_)
+    {
+        using namespace NodeAdded;
+        
+        VariantMap eventData;
+        eventData[P_SCENE] = (void*)scene_;
+        eventData[P_PARENT] = (void*)this;
+        eventData[P_NODE] = (void*)node;
+        
+        scene_->SendEvent(E_NODEADDED, eventData);
+    }
 }
 
 void Node::RemoveChild(Node* node)
@@ -1184,6 +1198,19 @@ void Node::AddComponent(Component* component, unsigned id, CreateMode mode)
     component->MarkNetworkUpdate();
     MarkNetworkUpdate();
     MarkReplicationDirty();
+    
+    // Send change event
+    if (scene_)
+    {
+        using namespace ComponentAdded;
+        
+        VariantMap eventData;
+        eventData[P_SCENE] = (void*)scene_;
+        eventData[P_NODE] = (void*)this;
+        eventData[P_COMPONENT] = (void*)component;
+        
+        scene_->SendEvent(E_COMPONENTADDED, eventData);
+    }
 }
 
 void Node::UpdateWorldTransform() const
@@ -1199,6 +1226,19 @@ void Node::UpdateWorldTransform() const
 
 void Node::RemoveChild(Vector<SharedPtr<Node> >::Iterator i)
 {
+    // Send change event. Do not send when already being destroyed
+    if (Refs() > 0 && scene_)
+    {
+        using namespace NodeRemoved;
+        
+        VariantMap eventData;
+        eventData[P_SCENE] = (void*)scene_;
+        eventData[P_PARENT] = (void*)this;
+        eventData[P_NODE] = (void*)(*i).Get();
+        
+        scene_->SendEvent(E_NODEREMOVED, eventData);
+    }
+    
     (*i)->parent_ = 0;
     (*i)->MarkDirty();
     (*i)->MarkNetworkUpdate();
@@ -1282,6 +1322,19 @@ void Node::RemoveComponent(Vector<SharedPtr<Component> >::Iterator i)
 {
     WeakPtr<Component> componentWeak(*i);
     
+    // Send node change event. Do not send when already being destroyed
+    if (Refs() > 0 && scene_)
+    {
+        using namespace ComponentRemoved;
+        
+        VariantMap eventData;
+        eventData[P_SCENE] = (void*)scene_;
+        eventData[P_NODE] = (void*)this;
+        eventData[P_COMPONENT] = (void*)(*i).Get();
+        
+        scene_->SendEvent(E_COMPONENTREMOVED, eventData);
+    }
+    
     RemoveListener(*i);
     if (scene_)
         scene_->ComponentRemoved(*i);

+ 40 - 0
Engine/Scene/SceneEvents.h

@@ -87,4 +87,44 @@ EVENT(E_ASYNCLOADFINISHED, AsyncLoadFinished)
     PARAM(P_SCENE, Scene);                  // Scene pointer
 };
 
+/// A child node has been added to a parent node.
+EVENT(E_NODEADDED, NodeAdded)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_PARENT, Parent);                // Node pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+}
+
+/// A child node is about to be removed from a parent node.
+EVENT(E_NODEREMOVED, NodeRemoved)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_PARENT, Parent);                // Node pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+}
+
+/// A component has been created to a node.
+EVENT(E_COMPONENTADDED, ComponentAdded)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+    PARAM(P_COMPONENT, Component);          // Component pointer
+}
+
+/// A component is about to be removed from a node.
+EVENT(E_COMPONENTREMOVED, ComponentRemoved)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+    PARAM(P_COMPONENT, Component);          // Component pointer
+}
+
+/// The attribute structure of a component has changed, requiring refresh in editor.
+EVENT(E_ATTRIBUTELISTCHANGED, AttributeListChanged)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+    PARAM(P_COMPONENT, Component);          // Component pointer
+}
+
 }

+ 2 - 1
Engine/Script/ScriptInstance.cpp

@@ -382,7 +382,7 @@ void ScriptInstance::CreateObject()
         if (methods_[METHOD_START])
             scriptFile_->Execute(scriptObject_, methods_[METHOD_START]);
         
-        SendEvent(E_SCRIPTOBJECTCREATED);
+        SendAttributeListChange();
     }
     else
         LOGERROR("Failed to create object of class " + className_ + " from " + scriptFile_->GetName());
@@ -403,6 +403,7 @@ void ScriptInstance::ReleaseObject()
         
         ClearScriptMethods();
         ClearScriptAttributes();
+        SendAttributeListChange();
         
         scriptObject_->SetUserData(0);
         scriptObject_->Release();

+ 0 - 5
Engine/Script/ScriptInstance.h

@@ -34,11 +34,6 @@ namespace Urho3D
 class Script;
 class ScriptFile;
 
-/// Script object created successfully.
-EVENT(E_SCRIPTOBJECTCREATED, ScriptObjectCreated)
-{
-}
-
 /// Inbuilt scripted component methods.
 enum ScriptInstanceMethod
 {