Browse Source

Added functionality to show multiple components in the atribute editor when a node or nodes are selected in the hierarchy window. Remove 'editable' parameter in the attribute creation functions as now whether an attribute is editable or not is dynamically set when loading the attribute value and not at the time of its editor creation. Exposed to all the UIElement-derived class a new function to load (partial) UI layout.

Wei Tjong Yao 12 years ago
parent
commit
38d12c122c

+ 23 - 29
Bin/Data/Scripts/Editor/AttributeEditor.as

@@ -21,8 +21,6 @@ Color normalTextColor(1.0f, 1.0f, 1.0f);
 Color modifiedTextColor(1.0f, 0.8f, 0.5f);
 Color modifiedTextColor(1.0f, 0.8f, 0.5f);
 Color nonEditableTextColor(0.7f, 0.7f, 0.7f);
 Color nonEditableTextColor(0.7f, 0.7f, 0.7f);
 
 
-const String DIFF_VALUE("---");
-
 String sceneResourcePath;
 String sceneResourcePath;
 
 
 UIElement@ SetEditable(UIElement@ element, bool editable)
 UIElement@ SetEditable(UIElement@ element, bool editable)
@@ -36,7 +34,7 @@ UIElement@ SetEditable(UIElement@ element, bool editable)
 
 
 UIElement@ SetValue(LineEdit@ element, const String&in value, bool sameValue)
 UIElement@ SetValue(LineEdit@ element, const String&in value, bool sameValue)
 {
 {
-    element.text = sameValue ? value : DIFF_VALUE;
+    element.text = sameValue ? value : "---";
     element.cursorPosition = 0;
     element.cursorPosition = 0;
     return element;
     return element;
 }
 }
@@ -95,12 +93,11 @@ UIElement@ CreateAttributeEditorParent(ListView@ list, const String&in name, uin
     return editorParent;
     return editorParent;
 }
 }
 
 
-LineEdit@ CreateAttributeLineEdit(UIElement@ parent, Array<Serializable@>@ serializables, bool editable, uint index, uint subIndex)
+LineEdit@ CreateAttributeLineEdit(UIElement@ parent, Array<Serializable@>@ serializables, uint index, uint subIndex)
 {
 {
     LineEdit@ attrEdit = LineEdit();
     LineEdit@ attrEdit = LineEdit();
     attrEdit.SetStyle(uiStyle, "EditorAttributeEdit");
     attrEdit.SetStyle(uiStyle, "EditorAttributeEdit");
     attrEdit.SetFixedHeight(ATTR_HEIGHT - 2);
     attrEdit.SetFixedHeight(ATTR_HEIGHT - 2);
-    SetEditable(attrEdit, editable);
     attrEdit.vars["Index"] = index;
     attrEdit.vars["Index"] = index;
     attrEdit.vars["SubIndex"] = subIndex;
     attrEdit.vars["SubIndex"] = subIndex;
     SetAttributeEditorID(attrEdit, serializables);
     SetAttributeEditorID(attrEdit, serializables);
@@ -108,29 +105,28 @@ LineEdit@ CreateAttributeLineEdit(UIElement@ parent, Array<Serializable@>@ seria
     return attrEdit;
     return attrEdit;
 }
 }
 
 
-void CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, bool editable, uint index)
+void CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, uint index)
 {
 {
     AttributeInfo info = serializables[0].attributeInfos[index];
     AttributeInfo info = serializables[0].attributeInfos[index];
-    CreateAttributeEditor(list, serializables, info.name, info.type, info.enumNames, editable, index, 0);
+    CreateAttributeEditor(list, serializables, info.name, info.type, info.enumNames, index, 0);
 }
 }
 
 
-UIElement@ CreateStringAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, bool editable, uint index, uint subIndex)
+UIElement@ CreateStringAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, uint index, uint subIndex)
 {
 {
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
-    LineEdit@ attrEdit = CreateAttributeLineEdit(parent, serializables, editable, index, subIndex);
+    LineEdit@ attrEdit = CreateAttributeLineEdit(parent, serializables, index, subIndex);
     attrEdit.dragDropMode = DD_TARGET;
     attrEdit.dragDropMode = DD_TARGET;
     SubscribeToEvent(attrEdit, "TextChanged", "EditAttribute");
     SubscribeToEvent(attrEdit, "TextChanged", "EditAttribute");
     SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
     SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
     return parent;
     return parent;
 }
 }
 
 
-UIElement@ CreateBoolAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, bool editable, uint index, uint subIndex)
+UIElement@ CreateBoolAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, uint index, uint subIndex)
 {
 {
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
     CheckBox@ attrEdit = CheckBox();
     CheckBox@ attrEdit = CheckBox();
     attrEdit.style = uiStyle;
     attrEdit.style = uiStyle;
     attrEdit.SetFixedSize(16, 16);
     attrEdit.SetFixedSize(16, 16);
-    SetEditable(attrEdit, editable);
     attrEdit.vars["Index"] = index;
     attrEdit.vars["Index"] = index;
     attrEdit.vars["SubIndex"] = subIndex;
     attrEdit.vars["SubIndex"] = subIndex;
     SetAttributeEditorID(attrEdit, serializables);
     SetAttributeEditorID(attrEdit, serializables);
@@ -139,7 +135,7 @@ UIElement@ CreateBoolAttributeEditor(ListView@ list, Array<Serializable@>@ seria
     return parent;
     return parent;
 }
 }
 
 
-UIElement@ CreateNumAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, bool editable, uint index, uint subIndex)
+UIElement@ CreateNumAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, uint index, uint subIndex)
 {
 {
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
     uint numCoords = type - VAR_FLOAT + 1;
     uint numCoords = type - VAR_FLOAT + 1;
@@ -152,21 +148,21 @@ UIElement@ CreateNumAttributeEditor(ListView@ list, Array<Serializable@>@ serial
     
     
     for (uint i = 0; i < numCoords; ++i)
     for (uint i = 0; i < numCoords; ++i)
     {
     {
-        LineEdit@ attrEdit = CreateAttributeLineEdit(parent, serializables, editable, index, subIndex);
+        LineEdit@ attrEdit = CreateAttributeLineEdit(parent, serializables, index, subIndex);
         SubscribeToEvent(attrEdit, "TextChanged", "EditAttribute");
         SubscribeToEvent(attrEdit, "TextChanged", "EditAttribute");
         SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
         SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
     }     
     }     
     return parent;    
     return parent;    
 }
 }
 
 
-UIElement@ CreateIntAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, bool editable, uint index, uint subIndex)
+UIElement@ CreateIntAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, uint index, uint subIndex)
 {
 {
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
     UIElement@ parent = CreateAttributeEditorParent(list, name, index, subIndex);
     // Check for enums
     // Check for enums
     if (enumNames is null || enumNames.empty)
     if (enumNames is null || enumNames.empty)
     {
     {
         // No enums, create a numeric editor
         // No enums, create a numeric editor
-        LineEdit@ attrEdit = CreateAttributeLineEdit(parent, serializables, editable, index, subIndex);
+        LineEdit@ attrEdit = CreateAttributeLineEdit(parent, serializables, index, subIndex);
         SubscribeToEvent(attrEdit, "TextChanged", "EditAttribute");
         SubscribeToEvent(attrEdit, "TextChanged", "EditAttribute");
         SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
         SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
     }
     }
@@ -176,7 +172,6 @@ UIElement@ CreateIntAttributeEditor(ListView@ list, Array<Serializable@>@ serial
         attrEdit.style = uiStyle;
         attrEdit.style = uiStyle;
         attrEdit.SetFixedHeight(ATTR_HEIGHT - 2);
         attrEdit.SetFixedHeight(ATTR_HEIGHT - 2);
         attrEdit.resizePopup = true;
         attrEdit.resizePopup = true;
-        SetEditable(attrEdit, editable);
         attrEdit.vars["Index"] = index;
         attrEdit.vars["Index"] = index;
         attrEdit.vars["SubIndex"] = subIndex;
         attrEdit.vars["SubIndex"] = subIndex;
         attrEdit.SetLayout(LM_HORIZONTAL, 0, IntRect(4, 1, 4, 1));
         attrEdit.SetLayout(LM_HORIZONTAL, 0, IntRect(4, 1, 4, 1));
@@ -196,7 +191,7 @@ UIElement@ CreateIntAttributeEditor(ListView@ list, Array<Serializable@>@ serial
     return parent;
     return parent;
 }
 }
 
 
-UIElement@ CreateResourceRefAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, bool editable, uint index, uint subIndex, bool suppressedSeparatedLabel = false)
+UIElement@ CreateResourceRefAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, uint index, uint subIndex, bool suppressedSeparatedLabel = false)
 {
 {
     UIElement@ parent;
     UIElement@ parent;
     ShortStringHash resourceType;
     ShortStringHash resourceType;
@@ -216,14 +211,13 @@ UIElement@ CreateResourceRefAttributeEditor(ListView@ list, Array<Serializable@>
     container.SetFixedHeight(ATTR_HEIGHT);
     container.SetFixedHeight(ATTR_HEIGHT);
     parent.AddChild(container);
     parent.AddChild(container);
         
         
-    LineEdit@ attrEdit = CreateAttributeLineEdit(container, serializables, editable, index, subIndex);
+    LineEdit@ attrEdit = CreateAttributeLineEdit(container, serializables, index, subIndex);
     attrEdit.vars["Type"] = resourceType.value;
     attrEdit.vars["Type"] = resourceType.value;
     SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
     SubscribeToEvent(attrEdit, "TextFinished", "EditAttribute");
 
 
     Button@ pickButton = Button();
     Button@ pickButton = Button();
     pickButton.style = uiStyle;
     pickButton.style = uiStyle;
     pickButton.SetFixedSize(36, ATTR_HEIGHT - 2);
     pickButton.SetFixedSize(36, ATTR_HEIGHT - 2);
-    SetEditable(pickButton, editable);
     pickButton.vars["Index"] = index;
     pickButton.vars["Index"] = index;
     pickButton.vars["SubIndex"] = subIndex;
     pickButton.vars["SubIndex"] = subIndex;
     SetAttributeEditorID(pickButton, serializables);
     SetAttributeEditorID(pickButton, serializables);
@@ -253,26 +247,26 @@ UIElement@ CreateResourceRefAttributeEditor(ListView@ list, Array<Serializable@>
     return parent;
     return parent;
 }
 }
 
 
-UIElement@ CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, bool editable, uint index, uint subIndex, bool suppressedSeparatedLabel = false)
+UIElement@ CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializables, const String&in name, VariantType type, Array<String>@ enumNames, uint index, uint subIndex, bool suppressedSeparatedLabel = false)
 {
 {
     UIElement@ parent;
     UIElement@ parent;
 
 
     AttributeInfo info = serializables[0].attributeInfos[index];
     AttributeInfo info = serializables[0].attributeInfos[index];
     if (type == VAR_STRING || type == VAR_BUFFER)
     if (type == VAR_STRING || type == VAR_BUFFER)
-        parent = CreateStringAttributeEditor(list, serializables, name, type, enumNames, editable, index, subIndex);
+        parent = CreateStringAttributeEditor(list, serializables, name, type, enumNames, index, subIndex);
     else if (type == VAR_BOOL)
     else if (type == VAR_BOOL)
-        parent = CreateBoolAttributeEditor(list, serializables, name, type, enumNames, editable, index, subIndex);
+        parent = CreateBoolAttributeEditor(list, serializables, name, type, enumNames, index, subIndex);
     else if ((type >= VAR_FLOAT && type <= VAR_VECTOR4) || type == VAR_QUATERNION || type == VAR_COLOR || type == VAR_INTVECTOR2 || type == VAR_INTRECT)
     else if ((type >= VAR_FLOAT && type <= VAR_VECTOR4) || type == VAR_QUATERNION || type == VAR_COLOR || type == VAR_INTVECTOR2 || type == VAR_INTRECT)
-        parent = CreateNumAttributeEditor(list, serializables, name, type, enumNames, editable, index, subIndex);
+        parent = CreateNumAttributeEditor(list, serializables, name, type, enumNames, index, subIndex);
     else if (type == VAR_INT)
     else if (type == VAR_INT)
-        parent = CreateIntAttributeEditor(list, serializables, name, type, enumNames, editable, index, subIndex);
+        parent = CreateIntAttributeEditor(list, serializables, name, type, enumNames, index, subIndex);
     else if (type == VAR_RESOURCEREF)
     else if (type == VAR_RESOURCEREF)
-        parent = CreateResourceRefAttributeEditor(list, serializables, name, type, enumNames, editable, index, subIndex, suppressedSeparatedLabel);
+        parent = CreateResourceRefAttributeEditor(list, serializables, name, type, enumNames, index, subIndex, suppressedSeparatedLabel);
     else if (type == VAR_RESOURCEREFLIST)
     else if (type == VAR_RESOURCEREFLIST)
     {
     {
         uint numRefs = serializables[0].attributes[index].GetResourceRefList().length;
         uint numRefs = serializables[0].attributes[index].GetResourceRefList().length;
         for (uint i = 0; i < numRefs; ++i)
         for (uint i = 0; i < numRefs; ++i)
-            CreateAttributeEditor(list, serializables, name, VAR_RESOURCEREF, null, editable, index, i, i > 0);
+            CreateAttributeEditor(list, serializables, name, VAR_RESOURCEREF, null, index, i, i > 0);
     }
     }
     else if (type == VAR_VARIANTVECTOR)
     else if (type == VAR_VARIANTVECTOR)
     {
     {
@@ -284,7 +278,7 @@ UIElement@ CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializa
         Array<Variant>@ vector = serializables[0].attributes[index].GetVariantVector();
         Array<Variant>@ vector = serializables[0].attributes[index].GetVariantVector();
         for (uint i = 0; i < vector.length; ++i)
         for (uint i = 0; i < vector.length; ++i)
         {
         {
-            CreateAttributeEditor(list, serializables, vectorStruct.variableNames[nameIndex], vector[i].type, null, editable, index, i);
+            CreateAttributeEditor(list, serializables, vectorStruct.variableNames[nameIndex], vector[i].type, null, index, i);
             ++nameIndex;
             ++nameIndex;
             if (nameIndex >= vectorStruct.variableNames.length)
             if (nameIndex >= vectorStruct.variableNames.length)
                 nameIndex = vectorStruct.restartIndex;
                 nameIndex = vectorStruct.restartIndex;
@@ -297,7 +291,7 @@ UIElement@ CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializa
         for (uint i = 0; i < keys.length; ++i)
         for (uint i = 0; i < keys.length; ++i)
         {
         {
             Variant value = map[keys[i]];
             Variant value = map[keys[i]];
-            parent = CreateAttributeEditor(list, serializables, scene.GetVarName(keys[i]) + " (Var)", value.type, null, editable, index, i);
+            parent = CreateAttributeEditor(list, serializables, scene.GetVarName(keys[i]) + " (Var)", value.type, null, index, i);
             // Add the variant key to the parent
             // Add the variant key to the parent
             parent.vars["Key"] = keys[i].value;
             parent.vars["Key"] = keys[i].value;
         }
         }
@@ -627,7 +621,7 @@ void UpdateAttributes(Array<Serializable@>@ serializables, ListView@ list, bool
             continue;
             continue;
 
 
         if (fullUpdate)
         if (fullUpdate)
-            CreateAttributeEditor(list, serializables, info.mode & AM_NOEDIT == 0, i);
+            CreateAttributeEditor(list, serializables, i);
 
 
         LoadAttributeEditor(list, serializables, info.mode & AM_NOEDIT == 0, i);
         LoadAttributeEditor(list, serializables, info.mode & AM_NOEDIT == 0, i);
     }
     }

+ 56 - 22
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -1,10 +1,26 @@
-// Urho3D editor node/component edit window handling
+// Urho3D editor attribute inspector window handling
 #include "Scripts/Editor/AttributeEditor.as"
 #include "Scripts/Editor/AttributeEditor.as"
 
 
 Window@ nodeWindow;
 Window@ nodeWindow;
+UIElement@ componentParentContainer;
 
 
 bool applyMaterialList = true;
 bool applyMaterialList = true;
 
 
+void AddComponentContainer()
+{
+    componentParentContainer.LoadXML(cache.GetResource("XMLFile", "UI/EditorComponent.xml"), uiStyle);
+}
+
+void DeleteAllComponentContainers()
+{
+    componentParentContainer.RemoveAllChildren();
+}
+
+UIElement@ GetComponentContainer(uint index)
+{
+    return componentParentContainer.children[index];
+}
+
 void CreateNodeWindow()
 void CreateNodeWindow()
 {
 {
     if (nodeWindow !is null)
     if (nodeWindow !is null)
@@ -14,6 +30,8 @@ void CreateNodeWindow()
     InitVectorStructs();
     InitVectorStructs();
 
 
     nodeWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorNodeWindow.xml"), uiStyle);
     nodeWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorNodeWindow.xml"), uiStyle);
+    componentParentContainer = nodeWindow.GetChild("ComponentParentContainer", true);
+    AddComponentContainer();
     ui.root.AddChild(nodeWindow);
     ui.root.AddChild(nodeWindow);
     int height = Min(ui.root.height - 60, 500);
     int height = Min(ui.root.height - 60, 500);
     nodeWindow.SetSize(300, height);
     nodeWindow.SetSize(300, height);
@@ -44,7 +62,6 @@ void UpdateNodeWindow()
     PickResourceCanceled();
     PickResourceCanceled();
 
 
     Text@ nodeTitle = nodeWindow.GetChild("NodeTitle", true);
     Text@ nodeTitle = nodeWindow.GetChild("NodeTitle", true);
-    Text@ componentTitle = nodeWindow.GetChild("ComponentTitle", true);
 
 
     if (editNode is null)
     if (editNode is null)
     {
     {
@@ -63,21 +80,6 @@ void UpdateNodeWindow()
         nodeTitle.text = editNode.typeName + " (" + idStr + ")";
         nodeTitle.text = editNode.typeName + " (" + idStr + ")";
     }
     }
 
 
-    if (editComponents.empty)
-    {
-        if (selectedComponents.length <= 1)
-            componentTitle.text = "No component";
-        else
-            componentTitle.text = selectedComponents.length + " components";
-    }
-    else
-    {
-        String multiplierText;
-        if (editComponents.length > 1)
-            multiplierText = " (" + editComponents.length + "x)";
-        componentTitle.text = GetComponentTitle(editComponents[0], 0) + multiplierText;
-    }
-
     UpdateAttributes(true);
     UpdateAttributes(true);
 }
 }
 
 
@@ -86,14 +88,46 @@ void UpdateAttributes(bool fullUpdate)
     if (nodeWindow !is null)
     if (nodeWindow !is null)
     {
     {
         Array<Serializable@> nodes;
         Array<Serializable@> nodes;
-        Array<Serializable@> components;
         if (editNode !is null)
         if (editNode !is null)
             nodes.Push(editNode);
             nodes.Push(editNode);
-        for (uint i = 0; i < editComponents.length; ++i)
-            components.Push(editComponents[i]);
-
         UpdateAttributes(nodes, nodeWindow.GetChild("NodeAttributeList", true), fullUpdate);
         UpdateAttributes(nodes, nodeWindow.GetChild("NodeAttributeList", true), fullUpdate);
-        UpdateAttributes(components, nodeWindow.GetChild("ComponentAttributeList", true), fullUpdate);
+
+        if (fullUpdate)
+            DeleteAllComponentContainers();
+        
+        if (editComponents.empty)
+        {
+            if (componentParentContainer.numChildren == 0)
+                AddComponentContainer();
+            
+            Text@ componentTitle = GetComponentContainer(0).GetChild("ComponentTitle");
+            if (selectedComponents.length <= 1)
+                componentTitle.text = "No component";
+            else
+                componentTitle.text = selectedComponents.length + " components";            
+        }
+        else
+        {
+            uint numEditableComponents = editComponents.length / numEditableComponentsPerNode;
+            String multiplierText;
+            if (numEditableComponents > 1)
+                multiplierText = " (" + numEditableComponents + "x)";
+            
+            for (uint j = 0; j < numEditableComponentsPerNode; ++j)
+            {
+                if (j >= componentParentContainer.numChildren)
+                    AddComponentContainer();
+                
+                Text@ componentTitle = GetComponentContainer(j).GetChild("ComponentTitle");
+                componentTitle.text = GetComponentTitle(editComponents[j], 0) + multiplierText;
+                
+                Array<Serializable@> components;
+                for (uint i = 0; i < numEditableComponents; ++i)
+                    components.Push(editComponents[j * numEditableComponents + i]);
+                
+                UpdateAttributes(components, GetComponentContainer(j).GetChild("ComponentAttributeList"), fullUpdate);
+            }
+        }
     }
     }
 }
 }
 
 

+ 2 - 0
Bin/Data/Scripts/Editor/EditorScene.as

@@ -22,6 +22,7 @@ Array<Component@> selectedComponents;
 Node@ editNode;
 Node@ editNode;
 Array<Node@> editNodes;
 Array<Node@> editNodes;
 Array<Component@> editComponents;
 Array<Component@> editComponents;
+uint numEditableComponentsPerNode = 1;
 
 
 Array<XMLFile@> copyBuffer;
 Array<XMLFile@> copyBuffer;
 bool copyBufferLocal = false;
 bool copyBufferLocal = false;
@@ -36,6 +37,7 @@ void ClearSelection()
     editNode = null;
     editNode = null;
     editNodes.Clear();
     editNodes.Clear();
     editComponents.Clear();
     editComponents.Clear();
+    numEditableComponentsPerNode = 1;
 
 
     HideGizmo();
     HideGizmo();
 }
 }

+ 19 - 12
Bin/Data/Scripts/Editor/EditorSceneWindow.as

@@ -546,25 +546,32 @@ void HandleSceneWindowSelectionChange()
             editComponents = selectedComponents;
             editComponents = selectedComponents;
     }
     }
     
     
-    // If just nodes selected, and no components, show the first component(s) for editing if possible
+    // If just nodes selected, and no components, show as much matching component(s) for editing as possible
     if (!selectedNodes.empty && selectedComponents.empty && selectedNodes[0].numComponents > 0)
     if (!selectedNodes.empty && selectedComponents.empty && selectedNodes[0].numComponents > 0)
     {
     {
-        ShortStringHash compType = selectedNodes[0].components[0].type;
-        bool sameType = true;
-        for (uint i = 1; i < selectedNodes.length; ++i)
+        uint count = 0;
+        for (uint j = 0; j < selectedNodes[0].numComponents; ++j)
         {
         {
-            if (selectedNodes[i].numComponents == 0 || selectedNodes[i].components[0].type != compType)
+            ShortStringHash compType = selectedNodes[0].components[j].type;
+            bool sameType = true;
+            for (uint i = 1; i < selectedNodes.length; ++i)
             {
             {
-                sameType = false;
-                break;
+                if (selectedNodes[i].numComponents <= j || selectedNodes[i].components[j].type != compType)
+                {
+                    sameType = false;
+                    break;
+                }
             }
             }
-        }
 
 
-        if (sameType)
-        {
-            for (uint i = 0; i < selectedNodes.length; ++i)
-                editComponents.Push(selectedNodes[i].components[0]);
+            if (sameType)
+            {
+                ++count;
+                for (uint i = 0; i < selectedNodes.length; ++i)
+                    editComponents.Push(selectedNodes[i].components[j]);
+            }
         }
         }
+        if (count > 1)
+            numEditableComponentsPerNode = count;
     }
     }
 
 
     if (selectedNodes.empty && editNode !is null)
     if (selectedNodes.empty && editNode !is null)

+ 4 - 9
Bin/Data/UI/EditorNodeWindow.xml

@@ -87,14 +87,9 @@
             </element>
             </element>
         </element>
         </element>
     </element>
     </element>
-    <element type="BorderImage" style="EditorDivider" />
-    <element type="Text">
-        <attribute name="Name" value="ComponentTitle" />
-        <attribute name="Min Size" value="0 17" />
-        <attribute name="Max Size" value="2147483647 17" />
-    </element>
-    <element type="ListView">
-        <attribute name="Name" value="ComponentAttributeList" />
-        <attribute name="Highlight Mode" value="Always" />
+    <element>
+        <attribute name="Name" value="ComponentParentContainer" />
+        <attribute name="Layout Mode" value="Vertical" />
+        <attribute name="Layout Spacing" value="4" />
     </element>
     </element>
 </element>
 </element>

+ 14 - 0
Docs/ScriptAPI.dox

@@ -3070,6 +3070,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3168,6 +3169,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3272,6 +3274,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3383,6 +3386,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3490,6 +3494,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3596,6 +3601,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3706,6 +3712,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3816,6 +3823,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -3923,6 +3931,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -4057,6 +4066,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -4171,6 +4181,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -4286,6 +4297,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -4404,6 +4416,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)
@@ -4533,6 +4546,7 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(const XMLElement&, XMLFile@)
 - bool LoadXML(File@)
 - bool LoadXML(File@)
+- bool LoadXML(XMLFile@, XMLFile@)
 - bool SaveXML(File@)
 - bool SaveXML(File@)
 - void SetStyle(const XMLElement&)
 - void SetStyle(const XMLElement&)
 - void SetStyle(XMLFile@, const String&)
 - void SetStyle(XMLFile@, const String&)

+ 16 - 1
Engine/Engine/APITemplates.h

@@ -731,6 +731,20 @@ static bool UIElementLoadXML(File* file, UIElement* ptr)
         return false;
         return false;
 }
 }
 
 
+static bool UIElementLoadXML(XMLFile* file, XMLFile* styleFile, UIElement* ptr)
+{
+    if (file)
+    {
+        XMLElement rootElem = file->GetRoot("element");
+        if (rootElem)
+            return ptr->LoadXML(rootElem, styleFile);
+        else
+            return false;
+    }
+    else
+        return false;
+}
+    
 static bool UIElementSaveXML(File* file, UIElement* ptr)
 static bool UIElementSaveXML(File* file, UIElement* ptr)
 {
 {
     if (file)
     if (file)
@@ -783,7 +797,8 @@ template <class T> void RegisterUIElement(asIScriptEngine* engine, const char* c
     RegisterNamedObjectConstructor<T>(engine, className);
     RegisterNamedObjectConstructor<T>(engine, className);
     RegisterSubclass<UIElement, T>(engine, "UIElement", className);
     RegisterSubclass<UIElement, T>(engine, "UIElement", className);
     engine->RegisterObjectMethod(className, "bool LoadXML(const XMLElement&in, XMLFile@+)", asMETHODPR(T, LoadXML, (const XMLElement&, XMLFile*), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool LoadXML(const XMLElement&in, XMLFile@+)", asMETHODPR(T, LoadXML, (const XMLElement&, XMLFile*), bool), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "bool LoadXML(File@+)", asFUNCTION(UIElementLoadXML), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod(className, "bool LoadXML(File@+)", asFUNCTIONPR(UIElementLoadXML, (File*, UIElement*), bool), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod(className, "bool LoadXML(XMLFile@+, XMLFile@+)", asFUNCTIONPR(UIElementLoadXML, (XMLFile*, XMLFile*, UIElement*), bool), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "bool SaveXML(File@+)", asFUNCTION(UIElementSaveXML), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "bool SaveXML(File@+)", asFUNCTION(UIElementSaveXML), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "void SetStyle(const XMLElement&in)", asMETHODPR(T, SetStyle, (const XMLElement&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void SetStyle(const XMLElement&in)", asMETHODPR(T, SetStyle, (const XMLElement&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void SetStyle(XMLFile@+, const String&in)", asMETHODPR(T, SetStyle, (XMLFile*, const String&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void SetStyle(XMLFile@+, const String&in)", asMETHODPR(T, SetStyle, (XMLFile*, const String&), void), asCALL_THISCALL);