Browse Source

Component reorder in editor. Fix attribute inspector not updating when nodes are added to e.g. StaticModelGroup via dragging. Clean up reorder related code. Set Urho icon as window icon in the editor. Closes #1463.

Lasse Öörni 9 years ago
parent
commit
34ddcdc294

+ 1 - 0
Source/Urho3D/AngelScript/APITemplates.h

@@ -705,6 +705,7 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "void RemoveComponents(bool, bool)", asMETHODPR(T, RemoveComponents, (bool, bool), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveComponents(const String&in)", asFUNCTION(NodeRemoveComponents), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "void RemoveAllComponents()", asMETHOD(T, RemoveAllComponents), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void ReorderComponent(Component@+, uint)", asMETHOD(T, ReorderComponent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void AddTag(const String&in)", asMETHOD(T, AddTag), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void AddTags(const String&in, int8 separator = ';')", asMETHODPR(T, AddTags, (const String&, char), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool RemoveTag(const String&in)", asMETHOD(T, RemoveTag), asCALL_THISCALL);

+ 2 - 1
Source/Urho3D/LuaScript/pkgs/Scene/Node.pkg

@@ -102,6 +102,7 @@ class Node : public Animatable
     void RemoveComponents(bool removeReplicated, bool removeLocal);
     void RemoveComponents(const String type);
     void RemoveAllComponents();
+    void ReorderComponent(Component* component, unsigned index);
 
     Node* Clone(CreateMode mode = REPLICATED);
 
@@ -203,7 +204,7 @@ class Node : public Animatable
     tolua_outside const PODVector<Node*>& NodeGetChildrenWithTag @ GetChildrenWithTag(const String& tag, bool recursive = false) const; 
 
     void SetID(unsigned id);
-    
+
     tolua_readonly tolua_property__get_set unsigned ID;
     tolua_property__get_set String name;
     tolua_readonly tolua_property__get_set StringHash nameHash;

+ 18 - 0
Source/Urho3D/Scene/Node.cpp

@@ -1063,6 +1063,24 @@ void Node::RemoveAllComponents()
     RemoveComponents(true, true);
 }
 
+void Node::ReorderComponent(Component* component, unsigned index)
+{
+    if (!component || component->GetNode() != this)
+        return;
+
+    for (Vector<SharedPtr<Component> >::Iterator i = components_.Begin(); i != components_.End(); ++i)
+    {
+        if (*i == component)
+        {
+            // Need shared ptr to insert. Also, prevent destruction when removing first
+            SharedPtr<Component> componentShared(component);
+            components_.Erase(i);
+            components_.Insert(index, componentShared);
+            return;
+        }
+    }
+}
+
 Node* Node::Clone(CreateMode mode)
 {
     // The scene itself can not be cloned

+ 2 - 0
Source/Urho3D/Scene/Node.h

@@ -289,6 +289,8 @@ public:
     void RemoveComponents(StringHash type);
     /// Remove all components from this node.
     void RemoveAllComponents();
+    /// Adjust index order of an existing component in this node.
+    void ReorderComponent(Component* component, unsigned index);
     /// Clone scene node, components and child nodes. Return the clone.
     Node* Clone(CreateMode mode = REPLICATED);
     /// Remove from the parent node. If no other shared pointer references exist, causes immediate deletion.

+ 37 - 23
bin/Data/Scripts/Editor/EditorActions.as

@@ -41,8 +41,8 @@ class CreateDrawableMaskAction : EditAction
             case EDIT_ZONE_MASK:
                 oldMask = drawable.zoneMask;
                 break;
-        } 
-                
+        }
+
         typeMask = editMaskType;
         redoMask = oldMask;
     }
@@ -279,7 +279,7 @@ class ReorderNodeAction : EditAction
     {
         nodeID = node.id;
         parentID = node.parent.id;
-        oldChildIndex = SceneFindChild(node.parent, node);
+        oldChildIndex = SceneFindChildIndex(node.parent, node);
         newChildIndex = newIndex;
     }
 
@@ -288,11 +288,7 @@ class ReorderNodeAction : EditAction
         Node@ parent = editorScene.GetNode(parentID);
         Node@ node = editorScene.GetNode(nodeID);
         if (parent !is null && node !is null)
-        {
             PerformReorder(parent, node, oldChildIndex);
-            UpdateHierarchyItem(parent); // Force update to make sure the order is current
-            SetSceneModified();
-        }
     }
 
     void Redo()
@@ -300,11 +296,39 @@ class ReorderNodeAction : EditAction
         Node@ parent = editorScene.GetNode(parentID);
         Node@ node = editorScene.GetNode(nodeID);
         if (parent !is null && node !is null)
-        {
             PerformReorder(parent, node, newChildIndex);
-            UpdateHierarchyItem(parent); // Force update to make sure the order is current
-            SetSceneModified();
-        }
+    }
+}
+
+class ReorderComponentAction : EditAction
+{
+    uint componentID;
+    uint nodeID;
+    uint oldComponentIndex;
+    uint newComponentIndex;
+
+    void Define(Component@ component, uint newIndex)
+    {
+        componentID = component.id;
+        nodeID = component.node.id;
+        oldComponentIndex = SceneFindComponentIndex(component.node, component);
+        newComponentIndex = newIndex;
+    }
+
+    void Undo()
+    {
+        Node@ node = editorScene.GetNode(nodeID);
+        Component@ component = editorScene.GetComponent(componentID);
+        if (node !is null && component !is null)
+            PerformReorder(node, component, oldComponentIndex);
+    }
+
+    void Redo()
+    {
+        Node@ node = editorScene.GetNode(nodeID);
+        Component@ component = editorScene.GetComponent(componentID);
+        if (node !is null && component !is null)
+            PerformReorder(node, component, newComponentIndex);
     }
 }
 
@@ -836,12 +860,7 @@ class ReorderUIElementAction : EditAction
         UIElement@ parent = GetUIElementByID(parentID);
         UIElement@ element = GetUIElementByID(elementID);
         if (parent !is null && element !is null)
-        {
-            parent.RemoveChild(element);
-            parent.InsertChild(oldChildIndex, element);
-            UpdateHierarchyItem(parent); // Force update to make sure the order is current
-            SetUIElementModified(parent);
-        }
+            PerformReorder(parent, element, oldChildIndex);
     }
 
     void Redo()
@@ -849,12 +868,7 @@ class ReorderUIElementAction : EditAction
         UIElement@ parent = GetUIElementByID(parentID);
         UIElement@ element = GetUIElementByID(elementID);
         if (parent !is null && element !is null)
-        {
-            parent.RemoveChild(element);
-            parent.InsertChild(newChildIndex, element);
-            UpdateHierarchyItem(parent); // Force update to make sure the order is current
-            SetUIElementModified(parent);
-        }
+            PerformReorder(parent, element, newChildIndex);
     }
 }
 

+ 83 - 57
bin/Data/Scripts/Editor/EditorHierarchyWindow.as

@@ -899,7 +899,7 @@ void HandleDragDropFinish(StringHash eventType, VariantMap& eventData)
     if (!accept)
         return;
 
-    // resource browser
+    // Resource browser
     if (source !is null && source.GetVar(TEXT_VAR_RESOURCE_TYPE).GetInt() > 0)
     {
         int type = source.GetVar(TEXT_VAR_RESOURCE_TYPE).GetInt();
@@ -1055,68 +1055,81 @@ void HandleDragDropFinish(StringHash eventType, VariantMap& eventData)
     }
     else if (itemType == ITEM_COMPONENT)
     {
-        Array<Node@> sourceNodes = GetMultipleSourceNodes(source);
         Component@ targetComponent = editorScene.GetComponent(target.vars[COMPONENT_ID_VAR].GetUInt());
-        if (targetComponent !is null && sourceNodes.length > 0)
-        {
-            // Drag node to StaticModelGroup to make it an instance
-            StaticModelGroup@ smg = cast<StaticModelGroup>(targetComponent);
-            if (smg !is null)
-            {
-                // Save undo action
-                EditAttributeAction action;
-                uint attrIndex = GetAttributeIndex(smg, "Instance Nodes");
-                Variant oldIDs = smg.attributes[attrIndex];
 
-                for (uint i = 0; i < sourceNodes.length; ++i)
-                    smg.AddInstanceNode(sourceNodes[i]);
-
-                action.Define(smg, attrIndex, oldIDs);
-                SaveEditAction(action);
-                SetSceneModified();
-            }
-
-            // Drag node to SplinePath to make it a control point
-            SplinePath@ spline = cast<SplinePath>(targetComponent);
-            if (spline !is null)
+        if (!input.qualifierDown[QUAL_CTRL])
+        {
+            Array<Node@> sourceNodes = GetMultipleSourceNodes(source);
+            if (targetComponent !is null && sourceNodes.length > 0)
             {
-                // Save undo action
-                EditAttributeAction action;
-                uint attrIndex = GetAttributeIndex(spline, "Control Points");
-                Variant oldIDs = spline.attributes[attrIndex];
-
-                for (uint i = 0; i < sourceNodes.length; ++i)
-                    spline.AddControlPoint(sourceNodes[i]);
+                // Drag node to StaticModelGroup to make it an instance
+                StaticModelGroup@ smg = cast<StaticModelGroup>(targetComponent);
+                if (smg !is null)
+                {
+                    // Save undo action
+                    EditAttributeAction action;
+                    uint attrIndex = GetAttributeIndex(smg, "Instance Nodes");
+                    Variant oldIDs = smg.attributes[attrIndex];
+
+                    for (uint i = 0; i < sourceNodes.length; ++i)
+                        smg.AddInstanceNode(sourceNodes[i]);
+
+                    action.Define(smg, attrIndex, oldIDs);
+                    SaveEditAction(action);
+                    SetSceneModified();
+                    UpdateAttributeInspector(false);
+                }
 
-                action.Define(spline, attrIndex, oldIDs);
-                SaveEditAction(action);
-                SetSceneModified();
-            }
+                // Drag node to SplinePath to make it a control point
+                SplinePath@ spline = cast<SplinePath>(targetComponent);
+                if (spline !is null)
+                {
+                    // Save undo action
+                    EditAttributeAction action;
+                    uint attrIndex = GetAttributeIndex(spline, "Control Points");
+                    Variant oldIDs = spline.attributes[attrIndex];
+
+                    for (uint i = 0; i < sourceNodes.length; ++i)
+                        spline.AddControlPoint(sourceNodes[i]);
+
+                    action.Define(spline, attrIndex, oldIDs);
+                    SaveEditAction(action);
+                    SetSceneModified();
+                    UpdateAttributeInspector(false);
+                }
 
-            // Drag a node to Constraint to make it the remote end of the constraint
-            Constraint@ constraint = cast<Constraint>(targetComponent);
-            RigidBody@ rigidBody = sourceNodes[0].GetComponent("RigidBody");
-            if (constraint !is null && rigidBody !is null)
-            {
-                // Save undo action
-                EditAttributeAction action;
-                uint attrIndex = GetAttributeIndex(constraint, "Other Body NodeID");
-                Variant oldID = constraint.attributes[attrIndex];
+                // Drag a node to Constraint to make it the remote end of the constraint
+                Constraint@ constraint = cast<Constraint>(targetComponent);
+                RigidBody@ rigidBody = sourceNodes[0].GetComponent("RigidBody");
+                if (constraint !is null && rigidBody !is null)
+                {
+                    // Save undo action
+                    EditAttributeAction action;
+                    uint attrIndex = GetAttributeIndex(constraint, "Other Body NodeID");
+                    Variant oldID = constraint.attributes[attrIndex];
 
-                constraint.otherBody = rigidBody;
+                    constraint.otherBody = rigidBody;
 
-                action.Define(constraint, attrIndex, oldID);
-                SaveEditAction(action);
-                SetSceneModified();
+                    action.Define(constraint, attrIndex, oldID);
+                    SaveEditAction(action);
+                    SetSceneModified();
+                    UpdateAttributeInspector(false);
+                }
             }
         }
+        else
+        {
+            // Reorder components within node
+            Component@ sourceComponent = editorScene.GetComponent(source.vars[COMPONENT_ID_VAR].GetUInt());
+            SceneReorder(sourceComponent, targetComponent);
+        }
     }
 }
 
 Array<Node@> GetMultipleSourceNodes(UIElement@ source)
 {
     Array<Node@> nodeList;
-    
+
     Node@ node = editorScene.GetNode(source.vars[NODE_ID_VAR].GetUInt());
     if (node !is null)
         nodeList.Push(node);
@@ -1246,8 +1259,8 @@ bool TestDragDrop(UIElement@ source, UIElement@ target, int& itemType)
     }
     else if (targetItemType == ITEM_COMPONENT)
     {
-        // Now only support dragging of nodes to StaticModelGroup, SplinePath or Constraint. Can be expanded to support others
         Node@ sourceNode;
+        Component@ sourceComponent;
         Component@ targetComponent;
         Variant variant = source.GetVar(NODE_ID_VAR);
         if (!variant.empty)
@@ -1255,17 +1268,30 @@ bool TestDragDrop(UIElement@ source, UIElement@ target, int& itemType)
         variant = target.GetVar(COMPONENT_ID_VAR);
         if (!variant.empty)
             targetComponent = editorScene.GetComponent(variant.GetUInt());
+        variant = source.GetVar(COMPONENT_ID_VAR);
+        if (!variant.empty)
+            sourceComponent = editorScene.GetComponent(variant.GetUInt());
 
         itemType = ITEM_COMPONENT;
 
-        if (sourceNode !is null && targetComponent !is null && (targetComponent.type == STATICMODELGROUP_TYPE ||
-            targetComponent.type == CONSTRAINT_TYPE || targetComponent.type == SPLINEPATH_TYPE))
-            return true;
+        if (!input.qualifierDown[QUAL_CTRL])
+        {
+            // Dragging of nodes to StaticModelGroup, SplinePath or Constraint
+            if (sourceNode !is null && targetComponent !is null && (targetComponent.type == STATICMODELGROUP_TYPE ||
+                targetComponent.type == CONSTRAINT_TYPE || targetComponent.type == SPLINEPATH_TYPE))
+                return true;
 
-        // resource browser
-        int type = source.GetVar(TEXT_VAR_RESOURCE_TYPE).GetInt();
-        if (targetComponent.type == STATICMODEL_TYPE || targetComponent.type == ANIMATEDMODEL_TYPE)
-            return type == RESOURCE_TYPE_MATERIAL || type == RESOURCE_TYPE_MODEL;
+            // Resource browser
+            int type = source.GetVar(TEXT_VAR_RESOURCE_TYPE).GetInt();
+            if (targetComponent.type == STATICMODEL_TYPE || targetComponent.type == ANIMATEDMODEL_TYPE)
+                return type == RESOURCE_TYPE_MATERIAL || type == RESOURCE_TYPE_MODEL;
+        }
+        else
+        {
+            // Reorder components within node
+            if (sourceComponent !is null && targetComponent !is null && sourceComponent.node is targetComponent.node)
+                return true;
+        }
 
         return false;
     }
@@ -1273,7 +1299,7 @@ bool TestDragDrop(UIElement@ source, UIElement@ target, int& itemType)
     {
         int type = source.GetVar(TEXT_VAR_RESOURCE_TYPE).GetInt();
 
-        // test against resource pickers
+        // Test against resource pickers
         LineEdit@ lineEdit = cast<LineEdit>(target);
         if (lineEdit !is null)
         {

+ 48 - 6
bin/Data/Scripts/Editor/EditorScene.as

@@ -865,7 +865,7 @@ bool SceneSmartDuplicateNode()
     
     // get bb for offset  
     Drawable@ drawable = GetFirstDrawable(node);
-    if (drawable !is null) 
+    if (drawable !is null)
     {
         bb = drawable.boundingBox;
         size =  bb.size * drawable.node.worldScale;
@@ -1070,28 +1070,59 @@ bool SceneReorder(Node@ sourceNode, Node@ targetNode)
         return true; // No-op
 
     Node@ parent = sourceNode.parent;
-    uint destIndex = SceneFindChild(parent, targetNode);
+    uint destIndex = SceneFindChildIndex(parent, targetNode);
 
     ReorderNodeAction action;
     action.Define(sourceNode, destIndex);
     SaveEditAction(action);
-
     PerformReorder(parent, sourceNode, destIndex);
-    UpdateHierarchyItem(parent); // Force update to make sure the order is current
-    SetSceneModified();
+    return true;
+}
+
+bool SceneReorder(Component@ sourceComponent, Component@ targetComponent)
+{
+    if (sourceComponent is null || targetComponent is null || sourceComponent.node !is targetComponent.node)
+        return false;
+    if (sourceComponent is targetComponent)
+        return true; // No-op
+
+    Node@ node = sourceComponent.node;
+    uint destIndex = SceneFindComponentIndex(node, targetComponent);
+
+    ReorderComponentAction action;
+    action.Define(sourceComponent, destIndex);
+    SaveEditAction(action);
+    PerformReorder(node, sourceComponent, destIndex);
     return true;
 }
 
 void PerformReorder(Node@ parent, Node@ child, uint destIndex)
 {
+    suppressSceneChanges = true;
+
     // Removal from scene zeroes the ID. Be prepared to restore it
     uint oldId = child.id;
     parent.RemoveChild(child);
     child.id = oldId;
     parent.AddChild(child, destIndex);
+    UpdateHierarchyItem(parent); // Force update to make sure the order is current
+    SetSceneModified();
+
+    suppressSceneChanges = false;
+}
+
+void PerformReorder(Node@ node, Component@ component, uint destIndex)
+{
+    suppressSceneChanges = true;
+
+    node.ReorderComponent(component, destIndex);
+    UpdateHierarchyItem(node); // Force update to make sure the order is current
+    SetSceneModified();
+
+    suppressSceneChanges = false;
 }
 
-uint SceneFindChild(Node@ parent, Node@ child)
+uint SceneFindChildIndex(Node@ parent, Node@ child)
 {
     for (uint i = 0; i < parent.numChildren; ++i)
     {
@@ -1102,6 +1133,17 @@ uint SceneFindChild(Node@ parent, Node@ child)
     return -1;
 }
 
+uint SceneFindComponentIndex(Node@ node, Component@ component)
+{
+    for (uint i = 0; i < node.numComponents; ++i)
+    {
+        if (node.components[i] is component)
+            return i;
+    }
+    
+    return -1;
+}
+
 bool SceneResetPosition()
 {
     if (editNode !is null)

+ 2 - 0
bin/Data/Scripts/Editor/EditorUI.as

@@ -72,6 +72,8 @@ void CreateUI()
     uiStyle = GetEditorUIXMLFile("UI/DefaultStyle.xml");
     ui.root.defaultStyle = uiStyle;
     iconStyle = GetEditorUIXMLFile("UI/EditorIcons.xml");
+    
+    graphics.windowIcon = cache.GetResource("Image", "Textures/UrhoIcon.png");
 
     CreateCursor();
     CreateMenuBar();

+ 12 - 3
bin/Data/Scripts/Editor/EditorUIElement.as

@@ -705,10 +705,19 @@ bool UIElementReorder(UIElement@ sourceElement, UIElement@ targetElement)
     ReorderUIElementAction action;
     action.Define(sourceElement, destIndex);
     SaveEditAction(action);
+    PerformReorder(parent, sourceElement, destIndex);
 
-    parent.RemoveChild(sourceElement);
-    parent.InsertChild(destIndex, sourceElement);
+    return true;
+}
+
+void PerformReorder(UIElement@ parent, UIElement@ child, uint destIndex)
+{
+    suppressSceneChanges = true;
+
+    parent.RemoveChild(child);
+    parent.InsertChild(destIndex, child);
     UpdateHierarchyItem(parent); // Force update to make sure the order is current
     SetUIElementModified(parent);
-    return true;
+
+    suppressSceneChanges = false;
 }