Browse Source

Editor fixes and cleanup. Handle changing amount of component attributes as a result of edit.
API improvements.
Minor scene XML format changes to accomodate editing.

Lasse Öörni 15 years ago
parent
commit
5707722337

+ 101 - 76
Bin/CoreData/Scripts/EditorComponentWindow.as

@@ -12,6 +12,7 @@ const uint ATTR_EDITOR_VECTOR4 = 4;
 const uint MAX_ATTRNAME_LENGTH = 15;
 
 bool inReadAttributeEditor = false;
+uint lastAttributeCount = 0;
 
 void createComponentWindow()
 {
@@ -44,6 +45,7 @@ void updateComponentWindow()
     LineEdit@ nameEdit = componentWindow.getChild("NameEdit", true);
     ListView@ list = componentWindow.getChild("AttributeList", true);
     list.removeAllItems();
+    lastAttributeCount = 0;
 
     if ((selectedComponent is null) || (selectedEntity is null))
     {
@@ -57,7 +59,7 @@ void updateComponentWindow()
     nameEdit.setText(selectedComponent.getName());
     nameEdit.setEnabled(true);
     
-    fillComponentAttributes();
+    updateComponentAttributes();
     showComponentWindow();
 }
 
@@ -71,7 +73,7 @@ void editComponentName()
     updateSceneWindowEntity(selectedEntity);
 }
 
-void fillComponentAttributes()
+void updateComponentAttributes()
 {
     ListView@ list = componentWindow.getChild("AttributeList", true);
 
@@ -79,71 +81,96 @@ void fillComponentAttributes()
     XMLElement rootElem = componentData.createRootElement("component");
     selectedComponent.saveXML(rootElem);
 
+    // Check amount of attributes. If has changed, do full refresh. Otherwise just refresh values
     XMLElement categoryElem = rootElem.getChildElement();
-    uint index = 0;
+    uint attributeCount = 0;
     while (categoryElem.notNull())
     {
-        string category = categoryElem.getName();
+        attributeCount += categoryElem.getNumAttributes();
+        categoryElem = categoryElem.getNextElement();
+    }
 
-        Text@ text = Text();
-        text.setStyleAuto(uiStyle);
-        text.setText(category);
-        list.addItem(text);
+    categoryElem = rootElem.getChildElement();
+    uint index = 0;
+
+    if (attributeCount != lastAttributeCount)
+    {
+        IntVector2 listOldPos = list.getViewPosition();
 
-        array<string> attrs = categoryElem.getAttributeNames();
+        list.removeAllItems();
 
-        for (uint i = 0; i < attrs.size(); ++i)
+        attributeCount = 0;
+        while (categoryElem.notNull())
         {
-            string name = attrs[i];
-            if (name.length() > MAX_ATTRNAME_LENGTH)
-                name.resize(MAX_ATTRNAME_LENGTH);
-
-            UIElement@ bar = UIElement();
-            bar.setLayout(LM_HORIZONTAL, 4, IntRect(0, 0, 0, 0));
-            bar.setFixedHeight(18);
-            list.addItem(bar);
-
-            Text@ attrName = Text();
-            attrName.setStyle(uiStyle, "EditorAttributeText");
-            attrName.setText(" " + name);
-            attrName.setFixedWidth(120);
-            bar.addChild(attrName);
-
-            uint type = getAttributeEditorType(selectedComponent, category, attrs[i]);
-            createAttributeEditor(bar, type, categoryElem, index, attrs[i]);
-            readAttributeEditor(type, categoryElem, index, attrs[i]);
-        }
-        
-        UIElement@ spacer = UIElement();
-        spacer.setFixedHeight(4);
-        list.addItem(spacer);
+            string category = categoryElem.getName();
 
-        categoryElem = categoryElem.getNextElement();
-        ++index;
-    }
-}
+            Text@ text = Text();
+            text.setStyleAuto(uiStyle);
+            text.setText(category);
+            list.addItem(text);
 
-void refreshComponentAttributes()
-{
-    ListView@ list = componentWindow.getChild("AttributeList", true);
+            {
+                UIElement@ spacer = UIElement();
+                spacer.setFixedHeight(4);
+                list.addItem(spacer);
+            }
 
-    XMLElement rootElem = componentData.createRootElement("component");
-    selectedComponent.saveXML(rootElem);
+            array<string> attrs = categoryElem.getAttributeNames();
 
-    XMLElement categoryElem = rootElem.getChildElement();
-    uint index = 0;
-    while (categoryElem.notNull())
-    {
-        array<string> attrs = categoryElem.getAttributeNames();
+            for (uint i = 0; i < attrs.size(); ++i)
+            {
+                string name = attrs[i];
+                if (name.length() > MAX_ATTRNAME_LENGTH)
+                    name.resize(MAX_ATTRNAME_LENGTH);
+
+                UIElement@ bar = UIElement();
+                bar.setLayout(LM_HORIZONTAL, 4, IntRect(0, 0, 0, 0));
+                bar.setFixedHeight(18);
+                list.addItem(bar);
+
+                Text@ attrName = Text();
+                attrName.setStyle(uiStyle, "EditorAttributeText");
+                attrName.setText(" " + name);
+                attrName.setFixedWidth(120);
+                bar.addChild(attrName);
+
+                uint type = getAttributeEditorType(selectedComponent, category, attrs[i], categoryElem.getAttribute(attrs[i]));
+                createAttributeEditor(bar, type, categoryElem, index, attrs[i]);
+                readAttributeEditor(type, categoryElem, index, attrs[i]);
+            }
+
+            {
+                UIElement@ spacer = UIElement();
+                spacer.setFixedHeight(4);
+                list.addItem(spacer);
+            }
 
-        for (uint i = 0; i < attrs.size(); ++i)
+            categoryElem = categoryElem.getNextElement();
+            attributeCount += attrs.size();
+            ++index;
+        }
+    
+        lastAttributeCount = attributeCount;
+        
+        // Try to reset to old view position
+        list.setViewPosition(listOldPos);
+    }
+    else
+    {
+        while (categoryElem.notNull())
         {
-            uint type = getAttributeEditorType(selectedComponent, categoryElem.getName(), attrs[i]);
-            readAttributeEditor(type, categoryElem, index, attrs[i]);
+            array<string> attrs = categoryElem.getAttributeNames();
+        
+            for (uint i = 0; i < attrs.size(); ++i)
+            {
+                string category = categoryElem.getName();
+                uint type = getAttributeEditorType(selectedComponent, category, attrs[i], categoryElem.getAttribute(attrs[i]));
+                readAttributeEditor(type, categoryElem, index, attrs[i]);
+            }
+        
+            categoryElem = categoryElem.getNextElement();
+            ++index;
         }
-
-        categoryElem = categoryElem.getNextElement();
-        ++index;
     }
 }
 
@@ -167,7 +194,7 @@ void editComponentAttribute(StringHash eventType, VariantMap& eventData)
             writeAttributeEditor(attrEdit.userData["Type"].getInt(), categoryElem, index, attrEdit.userData["Attribute"].getString());
             selectedComponent.loadXML(rootElem);
             selectedComponent.postLoad();
-            refreshComponentAttributes();
+            updateComponentAttributes();
             return;
         }
         categoryElem = categoryElem.getNextElement();
@@ -175,40 +202,38 @@ void editComponentAttribute(StringHash eventType, VariantMap& eventData)
     }
 }
 
-int getAttributeEditorType(Component@ component, string category, string attribute)
+int getAttributeEditorType(Component@ component, const string& in category, const string& in attribute, const string& in value)
 {
+    // Note: we always use valid, ie. just serialized data for this
     if (cast<Node>(component) !is null)
     {
-        if (category == "transform")
-            return ATTR_EDITOR_VECTOR3;
-        if (category == "render")
+        if (attribute.find("name") >= 0)
+            return ATTR_EDITOR_STRING;
+        else if ((category == "animation") && (attribute == "startbone"))
+            return ATTR_EDITOR_STRING;
+        else if (category == "parent")
+            return ATTR_EDITOR_STRING; //! \todo Parent node selector needs to be done separately
+        else if ((value == "true") || (value == "false"))
             return ATTR_EDITOR_BOOL;
-        if ((category == "light") && (attribute == "color"))
-            return ATTR_EDITOR_VECTOR4;
-        if ((category == "body") && (attribute == "active"))
-            return ATTR_EDITOR_BOOL;
-        if (attribute == "velocity")
+
+        uint coords = value.split(' ').size();
+        if (coords == 2)
+            return ATTR_EDITOR_VECTOR2;
+        else if (coords == 3)
             return ATTR_EDITOR_VECTOR3;
-        if (category == "billboard")
-        {
-            if (attribute == "pos")
-                return ATTR_EDITOR_VECTOR3;
-            if (attribute == "size")
-                return ATTR_EDITOR_VECTOR2;
-            if (attribute == "uv")
-                return ATTR_EDITOR_VECTOR4;
-        }
+        else if (coords == 4)
+            return ATTR_EDITOR_VECTOR4;
     }
 
     return ATTR_EDITOR_STRING;
 }
 
-string getAttributeEditorName(uint index, string attribute)
+string getAttributeEditorName(uint index, const string& in attribute)
 {
     return "Attr_" + toString(index) + "_" + attribute;
 }
 
-void createAttributeEditor(UIElement@ bar, uint type, XMLElement categoryElem, uint index, string attribute)
+void createAttributeEditor(UIElement@ bar, uint type, XMLElement categoryElem, uint index, const string& in attribute)
 {
     switch (type)
     {
@@ -256,7 +281,7 @@ void createAttributeEditor(UIElement@ bar, uint type, XMLElement categoryElem, u
     }
 }
 
-void readAttributeEditor(uint type, XMLElement categoryElem, int index, string attribute)
+void readAttributeEditor(uint type, XMLElement categoryElem, int index, const string& in attribute)
 {
     inReadAttributeEditor = true;
 
@@ -299,7 +324,7 @@ void readAttributeEditor(uint type, XMLElement categoryElem, int index, string a
     inReadAttributeEditor = false;
 }
 
-void writeAttributeEditor(uint type, XMLElement categoryElem, int index, string attribute)
+void writeAttributeEditor(uint type, XMLElement categoryElem, int index, const string& in attribute)
 {
     ListView@ list = componentWindow.getChild("AttributeList", true);
     

+ 1 - 1
Bin/CoreData/Scripts/EditorSceneWindow.as

@@ -297,7 +297,7 @@ void handleEntityListSelectionChange()
 void handleEntityListDoubleClick()
 {
     //! \todo Doubleclick is problematic, because it also collapses/expands list items
-    
+
     /*
     ListView@ list = sceneWindow.getChild("EntityList", true);
     UIElement@ item = list.getSelectedItem();

+ 3 - 3
Bin/CoreData/Scripts/EditorUI.as

@@ -70,7 +70,7 @@ void createMenuBar()
     resizeUI();
 }
 
-Menu@ createMenuItem(string title, int accelKey, int accelQual)
+Menu@ createMenuItem(const string& in title, int accelKey, int accelQual)
 {
     Menu@ menu = Menu(title);
     menu.setStyleAuto(uiStyle);
@@ -109,7 +109,7 @@ Window@ createPopup(Menu@ baseMenu)
     return popup;
 }
 
-Menu@ createMenu(string title)
+Menu@ createMenu(const string& in title)
 {
     Menu@ menu = createMenuItem(title, 0, 0);
     menu.setFixedWidth(menu.getWidth());
@@ -118,7 +118,7 @@ Menu@ createMenu(string title)
     return menu;
 }
 
-void createFileSelector(string title, string ok, string cancel, string initialPath, array<string>@ filters,
+void createFileSelector(const string& in title, const string& in ok, const string& in cancel, const string& in initialPath, array<string>@ filters,
     uint initialFilter)
 {
     // Within the editor UI, the file selector is a kind of a "singleton". When the previous one is overwritten, also 

+ 1 - 1
Bin/Data/TestLevel.xml

@@ -44,7 +44,7 @@
         <component type="RigidBody" netflags="0">
             <transform pos="0 0 0" rot="1 0 0 0" scale="1 1 1" />
             <body mode="static" mass="1.0" friction="0.5" bounce="0" active="false" />
-            <collision shape="Physics/Level.xml" group="2" mask="3" />
+            <collision name="Physics/Level.xml" group="2" mask="3" />
         </component>
     </entity>
 </scene>

+ 1 - 0
Engine/Engine/RegisterResource.cpp

@@ -209,6 +209,7 @@ static void registerXMLElement(asIScriptEngine* engine)
     engine->RegisterObjectMethod("XMLElement", "bool setVector3(const string& in, const Vector3& in)", asMETHOD(XMLElement, setVector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool isNull() const", asMETHOD(XMLElement, isNull), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool notNull() const", asMETHOD(XMLElement, notNull), asCALL_THISCALL);
+    engine->RegisterObjectMethod("XMLElement", "uint getNumAttributes() const", asMETHOD(XMLElement, getNumAttributes), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool hasAttribute(const string& in) const", asMETHOD(XMLElement, hasAttribute), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "string getAttribute(const string& in) const", asMETHOD(XMLElement, getAttribute), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "array<string>@ getAttributeNames() const", asFUNCTION(XMLElementGetAttributeNames), asCALL_CDECL_OBJLAST);

+ 2 - 2
Engine/Physics/RigidBody.cpp

@@ -171,7 +171,7 @@ void RigidBody::saveXML(XMLElement& dest)
     bodyElem.setBool("active", isActive());
     
     XMLElement collisionElem = dest.createChildElement("collision");
-    collisionElem.setString("shape", getResourceName(mCollisionShape));
+    collisionElem.setString("name", getResourceName(mCollisionShape));
     collisionElem.setInt("group", mCollisionGroup);
     collisionElem.setInt("mask", mCollisionMask);
     
@@ -217,7 +217,7 @@ void RigidBody::loadXML(const XMLElement& source, ResourceCache* cache)
     mBounce = bodyElem.getFloat("bounce");
     
     XMLElement collisionElem = source.getChildElement("collision");
-    setCollisionShape(cache->getResource<CollisionShape>(collisionElem.getString("shape")));
+    setCollisionShape(cache->getResource<CollisionShape>(collisionElem.getString("name")));
     setCollisionGroup(collisionElem.getInt("group"));
     setCollisionMask(collisionElem.getInt("mask"));
     

+ 3 - 2
Engine/Renderer/BillboardSet.cpp

@@ -154,7 +154,8 @@ void BillboardSet::saveXML(XMLElement& dest)
         XMLElement billboardElem = dest.createChildElement("billboard");
         const Billboard& billboard = mBillboards[i];
         
-        // Optimization: write only enabled billboards
+        billboardElem.setBool("enabled", billboard.mEnabled);
+        
         if (billboard.mEnabled)
         {
             billboardElem.setVector3("pos", billboard.mPosition);
@@ -187,7 +188,7 @@ void BillboardSet::loadXML(const XMLElement& source, ResourceCache* cache)
     while ((billboardElem) && (index < mBillboards.size()))
     {
         Billboard& billboard = mBillboards[index];
-        billboard.mEnabled = billboardElem.hasAttribute("pos");
+        billboard.mEnabled = billboardElem.getBool("enabled");
         if (billboard.mEnabled)
         {
             billboard.mPosition = billboardElem.getVector3("pos");

+ 17 - 0
Engine/Resource/XMLElement.cpp

@@ -327,6 +327,23 @@ XMLElement XMLElement::getParentElement() const
     return XMLElement(dynamic_cast<TiXmlElement*>(mElement->Parent()));
 }
 
+unsigned XMLElement::getNumAttributes() const
+{
+    unsigned ret = 0;
+    
+    if (mElement)
+    {
+        const TiXmlAttribute* attribute = mElement->FirstAttribute();
+        while (attribute)
+        {
+            ++ret;
+            attribute = attribute->Next();
+        }
+    }
+    
+    return ret;
+}
+
 bool XMLElement::hasAttribute(const std::string& name) const
 {
     if (!mElement)

+ 2 - 0
Engine/Resource/XMLElement.h

@@ -111,6 +111,8 @@ public:
     XMLElement getNextElement(const std::string& name = std::string()) const;
     //! Return parent element
     XMLElement getParentElement() const;
+    //! Return number of attributes
+    unsigned getNumAttributes() const;
     //! Return whether has an attribute
     bool hasAttribute(const std::string& name) const;
     //! Return attribute, or empty if missing

+ 2 - 3
Engine/UI/LineEdit.cpp

@@ -375,9 +375,8 @@ void LineEdit::onChar(unsigned char c, int buttons, int qualifiers)
         VariantMap eventData;
         eventData[P_ELEMENT] = (void*)this;
         eventData[P_TEXT] = mLine;
-        sendEvent(EVENT_TEXTFINISHED, eventData);
-        
-        mText->clearSelection();
+        // This event may potentially cause deletion
+        SAFE_SEND_EVENT(EVENT_TEXTFINISHED, eventData);
     }
     else if ((c >= 0x20) && ((!mMaxLength) || (mLine.length() < mMaxLength)))
     {

+ 3 - 0
Engine/UI/UIElement.h

@@ -31,6 +31,9 @@
 #include "Vector2.h"
 #include "XMLFile.h"
 
+//! Helper macro to send an event and check if we were deleted as a result
+#define SAFE_SEND_EVENT(type, data) { WeakPtr<UIElement> self(static_cast<UIElement*>(this)); sendEvent(type, data); if (!self) return; }
+
 //! UI element horizontal alignment
 enum HorizontalAlignment
 {