Browse Source

Added local axis movement mode to the editor.
Optimized UI child element queries and sorting.

Lasse Öörni 14 years ago
parent
commit
6c5d216c27

+ 18 - 1
Bin/Data/Scripts/Editor/EditorCamera.as

@@ -11,6 +11,12 @@ enum ObjectMoveMode
     OBJ_SCALE
     OBJ_SCALE
 }
 }
 
 
+enum AxisMode
+{
+    AXIS_WORLD = 0,
+    AXIS_LOCAL
+}
+
 float cameraBaseSpeed = 10;
 float cameraBaseSpeed = 10;
 float cameraBaseRotationSpeed = 0.2;
 float cameraBaseRotationSpeed = 0.2;
 float cameraShiftSpeedMultiplier = 5;
 float cameraShiftSpeedMultiplier = 5;
@@ -24,6 +30,7 @@ bool moveSnap = false;
 bool rotateSnap = false;
 bool rotateSnap = false;
 bool scaleSnap = false;
 bool scaleSnap = false;
 ObjectMoveMode moveMode = OBJ_MOVE;
 ObjectMoveMode moveMode = OBJ_MOVE;
+AxisMode axisMode = AXIS_WORLD;
 
 
 Text@ renderStatsText;
 Text@ renderStatsText;
 Text@ cameraPosText;
 Text@ cameraPosText;
@@ -35,6 +42,11 @@ Array<String> moveModeText = {
     "Scale   "
     "Scale   "
 };
 };
 
 
+Array<String> axisModeText = {
+    "World   ",
+    "Local   "
+};
+
 void CreateCamera()
 void CreateCamera()
 {
 {
     // Note: the camera will not be bound into the scene, so that it is not listed, and does not get deleted
     // Note: the camera will not be bound into the scene, so that it is not listed, and does not get deleted
@@ -389,7 +401,7 @@ void UpdateStats(float timeStep)
     yText.Resize(8);
     yText.Resize(8);
     zText.Resize(8);
     zText.Resize(8);
 
 
-    cameraPosText.text = moveModeText[moveMode] + "Updates: " + (runUpdate ? "Running " : "Paused  ") + " Camera pos: " + xText
+    cameraPosText.text = moveModeText[moveMode] + axisModeText[axisMode] + "Updates: " + (runUpdate ? "Running " : "Paused  ") + " Camera pos: " + xText
         + " " + yText + " " + zText + " ";
         + " " + yText + " " + zText + " ";
 
 
     renderStatsText.size = renderStatsText.minSize;
     renderStatsText.size = renderStatsText.minSize;
@@ -469,6 +481,8 @@ void MoveCamera(float timeStep)
             case OBJ_MOVE:
             case OBJ_MOVE:
                 if (!moveSnap)
                 if (!moveSnap)
                 {
                 {
+                    if (axisMode == AXIS_LOCAL)
+                        adjust = selectedNode.rotation * adjust;
                     selectedNode.position = selectedNode.position + adjust * moveStep;
                     selectedNode.position = selectedNode.position + adjust * moveStep;
                     changed = true;
                     changed = true;
                 }
                 }
@@ -542,6 +556,9 @@ void SteppedObjectManipulation(int key)
     {
     {
     case OBJ_MOVE:
     case OBJ_MOVE:
         {
         {
+            if (axisMode == AXIS_LOCAL)
+                adjust = selectedNode.rotation * adjust;
+
             Vector3 pos = selectedNode.position;
             Vector3 pos = selectedNode.position;
             if (adjust.x != 0)
             if (adjust.x != 0)
             {
             {

+ 12 - 2
Bin/Data/Scripts/Editor/EditorUI.as

@@ -17,13 +17,14 @@ void CreateUI()
     uiStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
     uiStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
 
 
     CreateCursor();
     CreateCursor();
-    CreateMenuBar();                                                                              
+    CreateMenuBar();
     CreateSceneWindow();
     CreateSceneWindow();
     CreateNodeWindow();
     CreateNodeWindow();
     CreateEditorSettingsDialog();
     CreateEditorSettingsDialog();
     CreateStatsBar();
     CreateStatsBar();
     CreateConsole();
     CreateConsole();
-    
+    CreateDebugHud();
+
     SubscribeToEvent("ScreenMode", "ResizeUI");
     SubscribeToEvent("ScreenMode", "ResizeUI");
     SubscribeToEvent("MenuSelected", "HandleMenuSelected");
     SubscribeToEvent("MenuSelected", "HandleMenuSelected");
     SubscribeToEvent("KeyDown", "HandleKeyDown");
     SubscribeToEvent("KeyDown", "HandleKeyDown");
@@ -169,6 +170,13 @@ void CreateConsole()
     console.numRows = 16;
     console.numRows = 16;
 }
 }
 
 
+void CreateDebugHud()
+{
+    engine.CreateDebugHud();
+    debugHud.style = uiStyle;
+    debugHud.mode = DEBUGHUD_SHOW_NONE;
+}
+
 void CenterDialog(UIElement@ element)
 void CenterDialog(UIElement@ element)
 {
 {
     IntVector2 size = element.size;
     IntVector2 size = element.size;
@@ -411,6 +419,8 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             moveMode = OBJ_ROTATE;
             moveMode = OBJ_ROTATE;
         else if (key == '3')
         else if (key == '3')
             moveMode = OBJ_SCALE;
             moveMode = OBJ_SCALE;
+        else if (key == '4')
+            axisMode = AxisMode(axisMode ^ AXIS_LOCAL);
         else
         else
             SteppedObjectManipulation(key);
             SteppedObjectManipulation(key);
     }
     }

+ 11 - 3
Engine/Engine/APITemplates.h

@@ -462,7 +462,7 @@ static CScriptArray* NodeGetChildrenWithScript(bool recursive, Node* ptr)
 static CScriptArray* NodeGetChildrenWithClassName(const String& className, bool recursive, Node* ptr)
 static CScriptArray* NodeGetChildrenWithClassName(const String& className, bool recursive, Node* ptr)
 {
 {
     PODVector<Node*> nodes;
     PODVector<Node*> nodes;
-    PODVector<Node*> ret;
+    PODVector<Node*> result;
     
     
     ptr->GetChildrenWithComponent<ScriptInstance>(nodes, recursive);
     ptr->GetChildrenWithComponent<ScriptInstance>(nodes, recursive);
     for (PODVector<Node*>::Iterator i = nodes.Begin(); i != nodes.End(); ++i)
     for (PODVector<Node*>::Iterator i = nodes.Begin(); i != nodes.End(); ++i)
@@ -475,12 +475,12 @@ static CScriptArray* NodeGetChildrenWithClassName(const String& className, bool
             {
             {
                 ScriptInstance* instance = static_cast<ScriptInstance*>(j->Get());
                 ScriptInstance* instance = static_cast<ScriptInstance*>(j->Get());
                 if (instance->GetClassName() == className)
                 if (instance->GetClassName() == className)
-                    ret.Push(node);
+                    result.Push(node);
             }
             }
         }
         }
     }
     }
     
     
-    return VectorToHandleArray<Node>(ret, "Array<Node@>");
+    return VectorToHandleArray<Node>(result, "Array<Node@>");
 }
 }
 
 
 /// Template function for registering a class derived from Node.
 /// Template function for registering a class derived from Node.
@@ -671,6 +671,13 @@ template <class T> void RegisterTexture(asIScriptEngine* engine, const char* cla
     engine->RegisterObjectMethod(className, "bool get_dataLost() const", asMETHOD(T, IsDataLost), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool get_dataLost() const", asMETHOD(T, IsDataLost), asCALL_THISCALL);
 }
 }
 
 
+static CScriptArray* UIElementGetChildren(bool recursive, UIElement* ptr)
+{
+    PODVector<UIElement*> elements;
+    ptr->GetChildren(elements, recursive);
+    return VectorToHandleArray<UIElement>(elements, "Array<UIElement@>");
+}
+
 static unsigned UIElementGetNumChildrenNonRecursive(UIElement* ptr)
 static unsigned UIElementGetNumChildrenNonRecursive(UIElement* ptr)
 {
 {
     return ptr->GetNumChildren(false);
     return ptr->GetNumChildren(false);
@@ -710,6 +717,7 @@ template <class T> void RegisterUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "void RemoveAllChildren()", asMETHOD(T, RemoveAllChildren), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveAllChildren()", asMETHOD(T, RemoveAllChildren), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void Remove()", asMETHOD(T, Remove), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void Remove()", asMETHOD(T, Remove), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "UIElement@+ GetChild(const String&in, bool recursive = false) const", asMETHODPR(T, GetChild, (const String&, bool) const, UIElement*), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "UIElement@+ GetChild(const String&in, bool recursive = false) const", asMETHODPR(T, GetChild, (const String&, bool) const, UIElement*), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "Array<UIElement@>@ GetChildren(bool recursive = false) const", asFUNCTION(UIElementGetChildren), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "IntVector2 ScreenToElement(const IntVector2&in)", asMETHOD(T, ScreenToElement), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntVector2 ScreenToElement(const IntVector2&in)", asMETHOD(T, ScreenToElement), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntVector2 ElementToScreen(const IntVector2&in)", asMETHOD(T, ElementToScreen), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntVector2 ElementToScreen(const IntVector2&in)", asMETHOD(T, ElementToScreen), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool IsInside(IntVector2, bool)", asMETHOD(T, IsInside), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool IsInside(IntVector2, bool)", asMETHOD(T, IsInside), asCALL_THISCALL);

+ 2 - 2
Engine/IO/FileSystem.h

@@ -97,9 +97,9 @@ String GetFileName(const String& fullPath);
 String GetExtension(const String& fullPath);
 String GetExtension(const String& fullPath);
 /// Return the filename and extension from a full path. The extension will be converted to lowercase.
 /// Return the filename and extension from a full path. The extension will be converted to lowercase.
 String GetFileNameAndExtension(const String& fullPath);
 String GetFileNameAndExtension(const String& fullPath);
-/// Add a slash in the end of the path if missing, and convert backslashes to slashes.
+/// Add a slash at the end of the path if missing and convert to internal format (use slashes.)
 String AddTrailingSlash(const String& pathName);
 String AddTrailingSlash(const String& pathName);
-/// Remove the slash from the end of a path if exists, and convert backslashes to slashes.
+/// Remove the slash from the end of a path if exists and convert to internal format (use slashes.)
 String RemoveTrailingSlash(const String& pathName);
 String RemoveTrailingSlash(const String& pathName);
 /// Return the parent path, or the path itself if not available.
 /// Return the parent path, or the path itself if not available.
 String GetParentPath(const String& pathName);
 String GetParentPath(const String& pathName);

+ 3 - 1
Engine/UI/DropDownList.cpp

@@ -192,7 +192,9 @@ UIElement* DropDownList::GetItem(unsigned index) const
 
 
 PODVector<UIElement*> DropDownList::GetItems() const
 PODVector<UIElement*> DropDownList::GetItems() const
 {
 {
-    return listView_->GetContentElement()->GetChildren();
+    PODVector<UIElement*> items;
+    listView_->GetContentElement()->GetChildren(items);
+    return items;
 }
 }
 
 
 unsigned DropDownList::GetSelection() const
 unsigned DropDownList::GetSelection() const

+ 2 - 2
Engine/UI/FileSelector.cpp

@@ -181,11 +181,11 @@ void FileSelector::SetStyle(XMLFile* style)
     okButton_->SetStyle(style, "FileSelectorButton");
     okButton_->SetStyle(style, "FileSelectorButton");
     cancelButton_->SetStyle(style, "FileSelectorButton");
     cancelButton_->SetStyle(style, "FileSelectorButton");
     
     
-    PODVector<UIElement*> filterTexts = filterList_->GetListView()->GetContentElement()->GetChildren();
+    const Vector<SharedPtr<UIElement> >& filterTexts = filterList_->GetListView()->GetContentElement()->GetChildren();
     for (unsigned i = 0; i < filterTexts.Size(); ++i)
     for (unsigned i = 0; i < filterTexts.Size(); ++i)
         filterTexts[i]->SetStyle(style, "FileSelectorFilterText");
         filterTexts[i]->SetStyle(style, "FileSelectorFilterText");
     
     
-    PODVector<UIElement*> listTexts = fileList_->GetContentElement()->GetChildren();
+    const Vector<SharedPtr<UIElement> >& listTexts = fileList_->GetContentElement()->GetChildren();
     for (unsigned i = 0; i < listTexts.Size(); ++i)
     for (unsigned i = 0; i < listTexts.Size(); ++i)
         listTexts[i]->SetStyle(style, "FileSelectorListText");
         listTexts[i]->SetStyle(style, "FileSelectorListText");
     
     

+ 4 - 1
Engine/UI/ListView.cpp

@@ -64,6 +64,7 @@ ListView::ListView(Context* context) :
     UIElement* container = new UIElement(context_);
     UIElement* container = new UIElement(context_);
     container->SetActive(true);
     container->SetActive(true);
     container->SetLayout(LM_VERTICAL);
     container->SetLayout(LM_VERTICAL);
+    container->SetSortingEnabled(false);
     SetContentElement(container);
     SetContentElement(container);
     
     
     SubscribeToEvent(E_UIMOUSECLICK, HANDLER(ListView, HandleUIMouseClick));
     SubscribeToEvent(E_UIMOUSECLICK, HANDLER(ListView, HandleUIMouseClick));
@@ -633,7 +634,9 @@ UIElement* ListView::GetItem(unsigned index) const
 
 
 PODVector<UIElement*> ListView::GetItems() const
 PODVector<UIElement*> ListView::GetItems() const
 {
 {
-    return contentElement_->GetChildren();
+    PODVector<UIElement*> items;
+    contentElement_->GetChildren(items);
+    return items;
 }
 }
 
 
 unsigned ListView::GetSelection() const
 unsigned ListView::GetSelection() const

+ 26 - 26
Engine/UI/UI.cpp

@@ -53,11 +53,6 @@
 
 
 #include "DebugNew.h"
 #include "DebugNew.h"
 
 
-static bool CompareUIElements(const UIElement* lhs, const UIElement* rhs)
-{
-    return lhs->GetPriority() < rhs->GetPriority();
-}
-
 OBJECTTYPESTATIC(UI);
 OBJECTTYPESTATIC(UI);
 
 
 UI::UI(Context* context) :
 UI::UI(Context* context) :
@@ -402,7 +397,7 @@ UIElement* UI::GetFrontElement() const
     if (!rootElement_)
     if (!rootElement_)
         return 0;
         return 0;
     
     
-    PODVector<UIElement*> rootChildren = rootElement_->GetChildren(false);
+    const Vector<SharedPtr<UIElement> >& rootChildren = rootElement_->GetChildren();
     int maxPriority = M_MIN_INT;
     int maxPriority = M_MIN_INT;
     UIElement* front = 0;
     UIElement* front = 0;
     
     
@@ -474,8 +469,8 @@ void UI::Update(float timeStep, UIElement* element)
 {
 {
     element->Update(timeStep);
     element->Update(timeStep);
     
     
-    const PODVector<UIElement*> children = element->GetChildren();
-    for (PODVector<UIElement*>::ConstIterator i = children.Begin(); i != children.End(); ++i)
+    const Vector<SharedPtr<UIElement> >& children = element->GetChildren();
+    for (Vector<SharedPtr<UIElement> >::ConstIterator i = children.Begin(); i != children.End(); ++i)
         Update(timeStep, *i);
         Update(timeStep, *i);
 }
 }
 
 
@@ -486,18 +481,17 @@ void UI::GetBatches(UIElement* element, IntRect currentScissor)
     if (currentScissor.left_ == currentScissor.right_ || currentScissor.top_ == currentScissor.bottom_)
     if (currentScissor.left_ == currentScissor.right_ || currentScissor.top_ == currentScissor.bottom_)
         return;
         return;
     
     
-    PODVector<UIElement*> children = element->GetChildren();
+    element->SortChildren();
+    const Vector<SharedPtr<UIElement> >& children = element->GetChildren();
     if (children.Empty())
     if (children.Empty())
         return;
         return;
     
     
-    Sort(children.Begin(), children.End(), CompareUIElements);
-    
     // For non-root elements draw all children of same priority before recursing into their children: assumption is that they have
     // For non-root elements draw all children of same priority before recursing into their children: assumption is that they have
     // same renderstate
     // same renderstate
-    PODVector<UIElement*>::ConstIterator i = children.Begin();
+    Vector<SharedPtr<UIElement> >::ConstIterator i = children.Begin();
     if (element != rootElement_)
     if (element != rootElement_)
     {
     {
-        PODVector<UIElement*>::ConstIterator j = i;
+        Vector<SharedPtr<UIElement> >::ConstIterator j = i;
         int currentPriority = children.Front()->GetPriority();
         int currentPriority = children.Front()->GetPriority();
         while (i != children.End())
         while (i != children.End())
         {
         {
@@ -554,13 +548,14 @@ void UI::GetElementAt(UIElement*& result, UIElement* current, const IntVector2&
     if (!current)
     if (!current)
         return;
         return;
     
     
-    // Get children from lowest priority to highest
-    PODVector<UIElement*> children = current->GetChildren(false);
-    Sort(children.Begin(), children.End(), CompareUIElements);
+    current->SortChildren();
+    const Vector<SharedPtr<UIElement> >& children = current->GetChildren();
     
     
-    for (PODVector<UIElement*>::ConstIterator i = children.Begin(); i != children.End(); ++i)
+    for (Vector<SharedPtr<UIElement> >::ConstIterator i = children.Begin(); i != children.End(); ++i)
     {
     {
         UIElement* element = *i;
         UIElement* element = *i;
+        bool hasChildren = element->GetNumChildren() > 0;
+        
         if (element != cursor_.Get() && element->IsVisible())
         if (element != cursor_.Get() && element->IsVisible())
         {
         {
             if (element->IsInside(position, true))
             if (element->IsInside(position, true))
@@ -569,10 +564,15 @@ void UI::GetElementAt(UIElement*& result, UIElement* current, const IntVector2&
                 // are sorted from lowest to highest priority, the topmost match should remain
                 // are sorted from lowest to highest priority, the topmost match should remain
                 if (element->IsActive() || !activeOnly)
                 if (element->IsActive() || !activeOnly)
                     result = element;
                     result = element;
+                
+                if (hasChildren)
+                    GetElementAt(result, element, position, activeOnly);
+            }
+            else
+            {
+                if (hasChildren && element->IsInsideCombined(position, true))
+                    GetElementAt(result, element, position, activeOnly);
             }
             }
-            
-            if (element->IsInsideCombined(position, true))
-                GetElementAt(result, element, position, activeOnly);
         }
         }
     }
     }
 }
 }
@@ -812,19 +812,19 @@ void UI::HandleKeyDown(StringHash eventType, VariantMap& eventData)
                 topLevel = topLevel->GetParent();
                 topLevel = topLevel->GetParent();
             if (topLevel)
             if (topLevel)
             {
             {
-                PODVector<UIElement*> children = topLevel->GetChildren(true);
-                for (PODVector<UIElement*>::Iterator i = children.Begin(); i != children.End();)
+                topLevel->GetChildren(tempElements_, true);
+                for (PODVector<UIElement*>::Iterator i = tempElements_.Begin(); i != tempElements_.End();)
                 {
                 {
                     if ((*i)->GetFocusMode() < FM_FOCUSABLE)
                     if ((*i)->GetFocusMode() < FM_FOCUSABLE)
-                        i = children.Erase(i);
+                        i = tempElements_.Erase(i);
                     else
                     else
                         ++i;
                         ++i;
                 }
                 }
-                for (unsigned i = 0; i < children.Size(); ++i)
+                for (unsigned i = 0; i < tempElements_.Size(); ++i)
                 {
                 {
-                    if (children[i] == element)
+                    if (tempElements_[i] == element)
                     {
                     {
-                        UIElement* next = children[(i + 1) % children.Size()];
+                        UIElement* next = tempElements_[(i + 1) % tempElements_.Size()];
                         SetFocusElement(next);
                         SetFocusElement(next);
                         return;
                         return;
                     }
                     }

+ 2 - 0
Engine/UI/UI.h

@@ -142,6 +142,8 @@ private:
     PODVector<UIQuad> quads_;
     PODVector<UIQuad> quads_;
     /// UI vertex buffer.
     /// UI vertex buffer.
     SharedPtr<VertexBuffer> vertexBuffer_;
     SharedPtr<VertexBuffer> vertexBuffer_;
+    /// UI element query vector.
+    PODVector<UIElement*> tempElements_;
     /// Clipboard text.
     /// Clipboard text.
     String clipBoard_;
     String clipBoard_;
     /// Mouse buttons held down.
     /// Mouse buttons held down.

+ 38 - 15
Engine/UI/UIElement.cpp

@@ -24,6 +24,7 @@
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "Context.h"
 #include "Context.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
+#include "Sort.h"
 #include "StringUtils.h"
 #include "StringUtils.h"
 #include "UI.h"
 #include "UI.h"
 #include "UIElement.h"
 #include "UIElement.h"
@@ -65,6 +66,11 @@ static const String dragDropModes[] =
     ""
     ""
 };
 };
 
 
+static bool CompareUIElements(const UIElement* lhs, const UIElement* rhs)
+{
+    return lhs->GetPriority() < rhs->GetPriority();
+}
+
 OBJECTTYPESTATIC(UIElement);
 OBJECTTYPESTATIC(UIElement);
 
 
 UIElement::UIElement(Context* context) :
 UIElement::UIElement(Context* context) :
@@ -97,6 +103,8 @@ UIElement::UIElement(Context* context) :
     positionDirty_(true),
     positionDirty_(true),
     opacityDirty_(true),
     opacityDirty_(true),
     derivedColorDirty_(true),
     derivedColorDirty_(true),
+    sortOrderDirty_(false),
+    sortingEnabled_(true),
     colorGradient_(false)
     colorGradient_(false)
 {
 {
 }
 }
@@ -488,6 +496,8 @@ void UIElement::SetColor(Corner corner, const Color& color)
 void UIElement::SetPriority(int priority)
 void UIElement::SetPriority(int priority)
 {
 {
     priority_ = priority;
     priority_ = priority;
+    if (parent_)
+        parent_->sortOrderDirty_ = true;
 }
 }
 
 
 void UIElement::SetOpacity(float opacity)
 void UIElement::SetOpacity(float opacity)
@@ -747,8 +757,8 @@ void UIElement::BringToFront()
     // and decrease others' priority by one. However, take into account only active (enabled) elements
     // and decrease others' priority by one. However, take into account only active (enabled) elements
     // and those which have the BringToBack flag set
     // and those which have the BringToBack flag set
     int maxPriority = M_MIN_INT;
     int maxPriority = M_MIN_INT;
-    PODVector<UIElement*> topLevelElements = root->GetChildren();
-    for (PODVector<UIElement*>::Iterator i = topLevelElements.Begin(); i != topLevelElements.End(); ++i)
+    const Vector<SharedPtr<UIElement> >& rootChildren = root->GetChildren();
+    for (Vector<SharedPtr<UIElement> >::ConstIterator i = rootChildren.Begin(); i != rootChildren.End(); ++i)
     {
     {
         UIElement* other = *i;
         UIElement* other = *i;
         if (other->IsActive() && other->bringToBack_ && other != ptr)
         if (other->IsActive() && other->bringToBack_ && other != ptr)
@@ -790,6 +800,9 @@ void UIElement::InsertChild(unsigned index, UIElement* element)
     if (element->parent_)
     if (element->parent_)
         element->parent_->RemoveChild(element);
         element->parent_->RemoveChild(element);
     
     
+    if (sortingEnabled_)
+        sortOrderDirty_ = true;
+    
     element->parent_ = this;
     element->parent_ = this;
     element->MarkDirty();
     element->MarkDirty();
     UpdateLayout();
     UpdateLayout();
@@ -914,23 +927,17 @@ bool UIElement::HasFocus() const
         return ui->GetFocusElement() == this;
         return ui->GetFocusElement() == this;
 }
 }
 
 
-PODVector<UIElement*> UIElement::GetChildren(bool recursive) const
+void UIElement::GetChildren(PODVector<UIElement*>& dest, bool recursive) const
 {
 {
+    dest.Clear();
+    
     if (!recursive)
     if (!recursive)
     {
     {
-        PODVector<UIElement*> ret;
         for (Vector<SharedPtr<UIElement> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i)
         for (Vector<SharedPtr<UIElement> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i)
-            ret.Push(*i);
-        
-        return ret;
+            dest.Push(*i);
     }
     }
     else
     else
-    {
-        PODVector<UIElement*> allChildren;
-        GetChildrenRecursive(allChildren);
-        
-        return allChildren;
-    }
+        GetChildrenRecursive(dest);
 }
 }
 
 
 unsigned UIElement::GetNumChildren(bool recursive) const
 unsigned UIElement::GetNumChildren(bool recursive) const
@@ -1046,6 +1053,15 @@ IntRect UIElement::GetCombinedScreenRect()
     return combined;
     return combined;
 }
 }
 
 
+void UIElement::SortChildren()
+{
+    if (sortingEnabled_ && sortOrderDirty_)
+    {
+        Sort(children_.Begin(), children_.End(), CompareUIElements);
+        sortOrderDirty_ = false;
+    }
+}
+
 void UIElement::SetChildOffset(const IntVector2& offset)
 void UIElement::SetChildOffset(const IntVector2& offset)
 {
 {
     if (offset != childOffset_)
     if (offset != childOffset_)
@@ -1056,6 +1072,11 @@ void UIElement::SetChildOffset(const IntVector2& offset)
     }
     }
 }
 }
 
 
+void UIElement::SetSortingEnabled(bool enable)
+{
+    sortingEnabled_ = enable;
+}
+
 void UIElement::SetHovering(bool enable)
 void UIElement::SetHovering(bool enable)
 {
 {
     hovering_ = enable;
     hovering_ = enable;
@@ -1113,8 +1134,10 @@ void UIElement::GetChildrenRecursive(PODVector<UIElement*>& dest) const
 {
 {
     for (Vector<SharedPtr<UIElement> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i)
     for (Vector<SharedPtr<UIElement> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i)
     {
     {
-        dest.Push(*i);
-        (*i)->GetChildrenRecursive(dest);
+        UIElement* element = *i;
+        dest.Push(element);
+        if (!element->children_.Empty())
+            element->GetChildrenRecursive(dest);
     }
     }
 }
 }
 
 

+ 14 - 2
Engine/UI/UIElement.h

@@ -324,8 +324,10 @@ public:
     UIElement* GetChild(unsigned index) const;
     UIElement* GetChild(unsigned index) const;
     /// Return child element by name.
     /// Return child element by name.
     UIElement* GetChild(const String& name, bool recursive = false) const;
     UIElement* GetChild(const String& name, bool recursive = false) const;
-    /// Return all child elements.
-    PODVector<UIElement*> GetChildren(bool recursive = false) const;
+    /// Return immediate child elements.
+    const Vector<SharedPtr<UIElement> >& GetChildren() const { return children_; }
+    /// Return child elements either recursively or non-recursively.
+    void GetChildren(PODVector<UIElement*>& dest, bool recursive = false) const;
     /// Return parent element.
     /// Return parent element.
     UIElement* GetParent() const { return parent_; }
     UIElement* GetParent() const { return parent_; }
     /// Return root element.
     /// Return root element.
@@ -345,9 +347,15 @@ public:
     bool IsInsideCombined(IntVector2 position, bool isScreen);
     bool IsInsideCombined(IntVector2 position, bool isScreen);
     /// Return combined screen coordinate rect of element and its children.
     /// Return combined screen coordinate rect of element and its children.
     IntRect GetCombinedScreenRect();
     IntRect GetCombinedScreenRect();
+    /// Sort child elements if sort order dirty. Called by UI.
+    void SortChildren();
     
     
     /// %Set child offset.
     /// %Set child offset.
     void SetChildOffset(const IntVector2& offset);
     void SetChildOffset(const IntVector2& offset);
+    /// %Set whether child elements should be sorted according to priority.
+    void SetSortingEnabled(bool enable);
+    /// Return whether child elements are sorted according to priority.
+    bool GetSortingEnabled() const { return sortingEnabled_; }
     /// %Set hovering state.
     /// %Set hovering state.
     void SetHovering(bool enable);
     void SetHovering(bool enable);
     /// Adjust scissor for rendering.
     /// Adjust scissor for rendering.
@@ -442,6 +450,10 @@ private:
     bool opacityDirty_;
     bool opacityDirty_;
     /// Derived color dirty flag (only used when no gradient.)
     /// Derived color dirty flag (only used when no gradient.)
     bool derivedColorDirty_;
     bool derivedColorDirty_;
+    /// Child priority sorting dirty flag.
+    bool sortOrderDirty_;
+    /// Child priority sorting enabled flag.
+    bool sortingEnabled_;
     /// Has color gradient flag.
     /// Has color gradient flag.
     bool colorGradient_;
     bool colorGradient_;
 };
 };