Browse Source

UI layout system refactoring.
DropDownList improvements.
UI bugfixes.

Lasse Öörni 15 years ago
parent
commit
9350f4056e

+ 6 - 7
Bin/Data/UI/TestLayout.xml

@@ -42,12 +42,11 @@
     <element type="DropDownList">
     <element type="DropDownList">
         <position value="10 160" />
         <position value="10 160" />
         <size value="100 30" />
         <size value="100 30" />
+        <resizepopup enable="true" />
+        <layout mode="horizontal" border="8 8 8 8" />
         <popupitem name="PopupItem1" />
         <popupitem name="PopupItem1" />
         <popupitem name="PopupItem2" />
         <popupitem name="PopupItem2" />
         <popupitem name="PopupItem3" />
         <popupitem name="PopupItem3" />
-        <placeholder>
-            <alignment horizontal="center" vertical="center" />
-        </placeholder>
         <popup>
         <popup>
             <layout border="8 8 8 8" />
             <layout border="8 8 8 8" />
         </popup>
         </popup>
@@ -132,9 +131,9 @@
         <size value="200 16" />
         <size value="200 16" />
     </element>
     </element>
     <element type="Window" name="TestPopup">
     <element type="Window" name="TestPopup">
-        <layout orientation="vertical" horizontal="resizeelement" vertical="resizeelement" spacing="4" border="8 8 8 8" />
+        <layout mode="vertical" spacing="4" border="8 8 8 8" />
         <element type="Menu">
         <element type="Menu">
-            <size value="80 16" />
+            <layout mode="vertical" />
             <element type="Text">
             <element type="Text">
                 <text value="MenuItem3" />
                 <text value="MenuItem3" />
                 <font name="cour.ttf" size="12" />
                 <font name="cour.ttf" size="12" />
@@ -142,7 +141,7 @@
             </element>
             </element>
         </element>
         </element>
         <element type="Menu">
         <element type="Menu">
-            <size value="80 16" />
+            <layout mode="vertical" />
             <element type="Text">
             <element type="Text">
                 <text value="MenuItem4" />
                 <text value="MenuItem4" />
                 <font name="cour.ttf" size="12" />
                 <font name="cour.ttf" size="12" />
@@ -150,7 +149,7 @@
             </element>
             </element>
         </element>
         </element>
         <element type="Menu">
         <element type="Menu">
-            <size value="80 16" />
+            <layout mode="vertical" />
             <element type="Text">
             <element type="Text">
                 <text value="MenuItem5" />
                 <text value="MenuItem5" />
                 <font name="cour.ttf" size="12" />
                 <font name="cour.ttf" size="12" />

+ 2 - 2
Bin/Data/UI/TestLayout2.xml

@@ -2,11 +2,11 @@
     <position value="50 50" />
     <position value="50 50" />
     <size value="400 300" />
     <size value="400 300" />
     <resizable enable="true" />
     <resizable enable="true" />
-    <layout orientation="vertical" horizontal="resizechildren" vertical="resizechildren" border="4 4 4 4" spacing="2" />
+    <layout mode="vertical" border="4 4 4 4" spacing="2" />
     <clipborder value="4 4 4 4" />
     <clipborder value="4 4 4 4" />
     <element type="Element">
     <element type="Element">
         <clipchildren enable="true" />
         <clipchildren enable="true" />
-        <layout orientation="vertical" horizontal="resizechildren" vertical="resizechildren" />
+        <layout mode="vertical" />
         <element type="Text">
         <element type="Text">
             <font name="courier.ttf" size="15" />
             <font name="courier.ttf" size="15" />
             <text value="At some point the fire had started.\n  There was total chaos. The locks of the wooden barracks had been blown apart by gunfire from shotguns and assault rifles, and the trainees were pouring out in confusion. But the primary target still lay ahead.\n  The administrative building. Where the identities and evaluations of the trainees were stored.\n  That was first class knowledge. If the Agents could bring that knowledge to the public, and cross-reference the records - mostly boys of young age - with lists of known missing persons, then they could prove the existence of SCEPTRE." />
             <text value="At some point the fire had started.\n  There was total chaos. The locks of the wooden barracks had been blown apart by gunfire from shotguns and assault rifles, and the trainees were pouring out in confusion. But the primary target still lay ahead.\n  The administrative building. Where the identities and evaluations of the trainees were stored.\n  That was first class knowledge. If the Agents could bring that knowledge to the public, and cross-reference the records - mostly boys of young age - with lists of known missing persons, then they could prove the existence of SCEPTRE." />

+ 5 - 7
Bin/Data/UI/TestLayout3.xml

@@ -2,11 +2,11 @@
     <position value="50 50" />
     <position value="50 50" />
     <size value="400 300" />
     <size value="400 300" />
     <resizable enable="true" />
     <resizable enable="true" />
-    <layout orientation="vertical" horizontal="resizechildren" vertical="resizechildren" border="8 8 8 8" spacing="8" />
+    <layout mode="vertical" border="8 8 8 8" spacing="8" />
     <clipborder value="8 8 8 8" />
     <clipborder value="8 8 8 8" />
     <minsize value="60 60" />
     <minsize value="60 60" />
     <element type="Element">
     <element type="Element">
-        <layout orientation="horizontal" horizontal="resizechildren" vertical="resizechildren" spacing="8" />
+        <layout mode="horizontal" spacing="8" />
         <element type="Button">
         <element type="Button">
             <element type="Text">
             <element type="Text">
                 <text value="TEST1" />
                 <text value="TEST1" />
@@ -31,9 +31,10 @@
         </element>
         </element>
     </element>
     </element>
     <element type="Element">
     <element type="Element">
-        <layout orientation="horizontal" horizontal="resizechildren" vertical="resizechildren" spacing="8" />
+        <layout mode="horizontal" spacing="8" />
     	<element type="Text" name="ScrollViewText">
     	<element type="Text" name="ScrollViewText">
 	        <position value="1 0" />
 	        <position value="1 0" />
+	        <fixedwidth value="400" />
 	        <font name="times.ttf" size="15" />
 	        <font name="times.ttf" size="15" />
             <text value="At some point the fire had started.\n  There was total chaos. The locks of the wooden barracks had been blown apart by gunfire from shotguns and assault rifles, and the trainees were pouring out in confusion. But the primary target still lay ahead.\n  The administrative building. Where the identities and evaluations of the trainees were stored.\n  That was first class knowledge. If the Agents could bring that knowledge to the public, and cross-reference the records - mostly boys of young age - with lists of known missing persons, then they could prove the existence of SCEPTRE." />
             <text value="At some point the fire had started.\n  There was total chaos. The locks of the wooden barracks had been blown apart by gunfire from shotguns and assault rifles, and the trainees were pouring out in confusion. But the primary target still lay ahead.\n  The administrative building. Where the identities and evaluations of the trainees were stored.\n  That was first class knowledge. If the Agents could bring that knowledge to the public, and cross-reference the records - mostly boys of young age - with lists of known missing persons, then they could prove the existence of SCEPTRE." />
 	        <wordwrap enable="true" />
 	        <wordwrap enable="true" />
@@ -47,9 +48,6 @@
         </element>
         </element>
     	<element type="ScrollView">
     	<element type="ScrollView">
 	        <contentelement name="ScrollViewText" />
 	        <contentelement name="ScrollViewText" />
-	        <scrollpanel>
-	        	<layout orientation="vertical" horizontal="resizechildren" vertical="resizechildren" border="1 1 1 1" spacing="0" />
-	        </scrollpanel>
 	    </element>
 	    </element>
         <element type="Button">
         <element type="Button">
             <element type="Text">
             <element type="Text">
@@ -60,7 +58,7 @@
         </element>
         </element>
     </element>
     </element>
     <element type="Element">
     <element type="Element">
-        <layout orientation="horizontal" horizontal="resizechildren" vertical="resizechildren" spacing="8" />
+        <layout mode="horizontal" spacing="8" />
         <element type="Button">
         <element type="Button">
             <element type="Text">
             <element type="Text">
                 <text value="TEST6" />
                 <text value="TEST6" />

+ 5 - 4
Engine/Engine/Console.cpp

@@ -54,16 +54,17 @@ Console::Console(Engine* engine) :
             log->addListener(this);
             log->addListener(this);
         
         
         mBackground = new BorderImage();
         mBackground = new BorderImage();
-        mBackground->setWidth(uiRoot->getWidth());
+        mBackground->setFixedWidth(uiRoot->getWidth());
         mBackground->setColor(C_TOPLEFT, Color(0.0f, 0.25f, 0.0f, 0.75f));
         mBackground->setColor(C_TOPLEFT, Color(0.0f, 0.25f, 0.0f, 0.75f));
         mBackground->setColor(C_TOPRIGHT, Color(0.0f, 0.25f, 0.0f, 0.75f));
         mBackground->setColor(C_TOPRIGHT, Color(0.0f, 0.25f, 0.0f, 0.75f));
         mBackground->setColor(C_BOTTOMLEFT, Color(0.25f, 0.75f, 0.25f, 0.75f));
         mBackground->setColor(C_BOTTOMLEFT, Color(0.25f, 0.75f, 0.25f, 0.75f));
         mBackground->setColor(C_BOTTOMRIGHT, Color(0.25f, 0.75f, 0.25f, 0.75f));
         mBackground->setColor(C_BOTTOMRIGHT, Color(0.25f, 0.75f, 0.25f, 0.75f));
         mBackground->setBringToBack(false);
         mBackground->setBringToBack(false);
+        mBackground->setClipChildren(true);
         mBackground->setEnabled(true);
         mBackground->setEnabled(true);
         mBackground->setVisible(false);
         mBackground->setVisible(false);
         mBackground->setPriority(200); // Show on top of the debug HUD
         mBackground->setPriority(200); // Show on top of the debug HUD
-        mBackground->setLayout(O_VERTICAL, LM_RESIZECHILDREN, LM_RESIZEELEMENT, 0, IntRect(4, 4, 4, 4));
+        mBackground->setLayout(LM_VERTICAL, 0, IntRect(4, 4, 4, 4));
         
         
         mLineEdit = new LineEdit();
         mLineEdit = new LineEdit();
         mLineEdit->setColor(Color(0.0f, 0.0f, 0.0f, 0.5f));
         mLineEdit->setColor(Color(0.0f, 0.0f, 0.0f, 0.5f));
@@ -175,8 +176,8 @@ void Console::updateElements()
         mLineEdit->getTextElement()->setFont(mFont, mFontSize);
         mLineEdit->getTextElement()->setFont(mFont, mFontSize);
     }
     }
     
     
-    mLineEdit->setHeight(mLineEdit->getTextElement()->getRowHeight());
-    mBackground->setWidth(width);
+    mLineEdit->setFixedHeight(mLineEdit->getTextElement()->getRowHeight());
+    mBackground->setFixedWidth(width);
 }
 }
 
 
 void Console::handleTextFinished(StringHash eventType, VariantMap& eventData)
 void Console::handleTextFinished(StringHash eventType, VariantMap& eventData)

+ 4 - 4
Engine/Engine/RegisterTemplates.h

@@ -446,7 +446,9 @@ template <class T> void registerUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "void setVisible(bool)", asMETHOD(T, setVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setVisible(bool)", asMETHOD(T, setVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setUserData(const Variant& in)", asMETHOD(T, setUserData), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setUserData(const Variant& in)", asMETHOD(T, setUserData), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setStyleAuto(XMLFile@+)", asFUNCTION(UIElementSetStyleAuto<T>), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "void setStyleAuto(XMLFile@+)", asFUNCTION(UIElementSetStyleAuto<T>), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod(className, "void setLayout(Orientation, LayoutMode, LayoutMode, int, const IntRect&)", asMETHOD(T, setLayout), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void setLayout(LayoutMode, int, const IntRect&)", asMETHOD(T, setLayout), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void setLayoutSpacing(int)", asMETHOD(T, setLayoutSpacing), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void setLayoutBorder(const IntRect&)", asMETHOD(T, setLayoutBorder), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void updateLayout()", asMETHOD(T, updateLayout), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void updateLayout()", asMETHOD(T, updateLayout), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void bringToFront()", asMETHOD(T, bringToFront), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void bringToFront()", asMETHOD(T, bringToFront), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void addChild(UIElement@+)", asMETHOD(T, addChild), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void addChild(UIElement@+)", asMETHOD(T, addChild), asCALL_THISCALL);
@@ -481,9 +483,7 @@ template <class T> void registerUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "bool isHovering() const", asMETHOD(T, isHovering), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool isHovering() const", asMETHOD(T, isHovering), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool hasColorGradient() const", asMETHOD(T, hasColorGradient), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool hasColorGradient() const", asMETHOD(T, hasColorGradient), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const Variant& getUserData() const", asMETHOD(T, getUserData), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const Variant& getUserData() const", asMETHOD(T, getUserData), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "Orientation getLayoutOrientation() const", asMETHOD(T, getLayoutOrientation), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "LayoutMode getHorizontalLayoutMode() const", asMETHOD(T, getHorizontalLayoutMode), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "LayoutMode getVerticalLayoutMode() const", asMETHOD(T, getVerticalLayoutMode), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "LayoutMode getLayoutMode() const", asMETHOD(T, getLayoutMode), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "int getLayoutSpacing() const", asMETHOD(T, getLayoutSpacing), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "int getLayoutSpacing() const", asMETHOD(T, getLayoutSpacing), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const IntRect& getLayoutBorder() const", asMETHOD(T, getLayoutBorder), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const IntRect& getLayoutBorder() const", asMETHOD(T, getLayoutBorder), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint getNumChildren(bool) const", asMETHOD(T, getNumChildren), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint getNumChildren(bool) const", asMETHOD(T, getNumChildren), asCALL_THISCALL);

+ 33 - 2
Engine/Engine/RegisterUI.cpp

@@ -25,6 +25,7 @@
 #include "Button.h"
 #include "Button.h"
 #include "CheckBox.h"
 #include "CheckBox.h"
 #include "Cursor.h"
 #include "Cursor.h"
+#include "DropDownList.h"
 #include "Engine.h"
 #include "Engine.h"
 #include "Font.h"
 #include "Font.h"
 #include "LineEdit.h"
 #include "LineEdit.h"
@@ -74,8 +75,8 @@ static void registerUIElement(asIScriptEngine* engine)
     
     
     engine->RegisterEnum("LayoutMode");
     engine->RegisterEnum("LayoutMode");
     engine->RegisterEnumValue("LayoutMode", "LM_FREE", LM_FREE);
     engine->RegisterEnumValue("LayoutMode", "LM_FREE", LM_FREE);
-    engine->RegisterEnumValue("LayoutMode", "LM_RESIZECHILDREN", LM_RESIZECHILDREN);
-    engine->RegisterEnumValue("LayoutMode", "LM_RESIZEELEMENT", LM_RESIZEELEMENT);
+    engine->RegisterEnumValue("LayoutMode", "LM_HORIZONTAL", LM_HORIZONTAL);
+    engine->RegisterEnumValue("LayoutMode", "LM_VERTICAL", LM_VERTICAL);
     
     
     registerUIElement<UIElement>(engine, "UIElement");
     registerUIElement<UIElement>(engine, "UIElement");
     
     
@@ -284,6 +285,35 @@ static void registerMenu(asIScriptEngine* engine)
     registerRefCasts<UIElement, Menu>(engine, "UIElement", "Menu");
     registerRefCasts<UIElement, Menu>(engine, "UIElement", "Menu");
 }
 }
 
 
+static CScriptArray* DropDownListGetItems(DropDownList* ptr)
+{
+    std::vector<UIElement*> result = ptr->getItems();
+    return vectorToHandleArray<UIElement>(result, "array<UIElement@>");
+}
+
+static void registerDropDownList(asIScriptEngine* engine)
+{
+    registerButton<DropDownList>(engine, "DropDownList");
+    engine->RegisterObjectMethod("DropDownList", "void showPopup(bool)", asMETHOD(DropDownList, showPopup), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "void addItem(UIElement@+)", asMETHOD(DropDownList, addItem), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "void removeItem(UIElement@+)", asMETHODPR(DropDownList, removeItem, (UIElement*), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "void removeItem(uint)", asMETHODPR(DropDownList, removeItem, (unsigned), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "void removeAllItems()", asMETHOD(DropDownList, removeAllItems), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "void setSelection(uint)", asMETHOD(DropDownList, setSelection), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "void setResizePopup(bool)", asMETHOD(DropDownList, setResizePopup), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "UIElement@+ getPopup() const", asMETHOD(DropDownList, getPopup), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "bool getShowPopup() const", asMETHOD(DropDownList, getShowPopup), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "uint getNumItems() const", asMETHOD(DropDownList, getSelection), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "UIElement@+ getItem(uint) const", asMETHOD(DropDownList, getItem), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "array<UIElement@>@ getItems() const", asFUNCTION(DropDownListGetItems), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("DropDownList", "uint getSelection() const", asMETHOD(DropDownList, getSelection), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "UIElement@+ getSelectedItem() const", asMETHOD(DropDownList, getSelectedItem), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "ListView@+ getListView() const", asMETHOD(DropDownList, getListView), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "UIElement@+ getPlaceholder() const", asMETHOD(DropDownList, getPlaceholder), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DropDownList", "bool getResizePopup() const", asMETHOD(DropDownList, getResizePopup), asCALL_THISCALL);
+    registerRefCasts<UIElement, DropDownList>(engine, "UIElement", "DropDownList");
+}
+
 static void registerWindow(asIScriptEngine* engine)
 static void registerWindow(asIScriptEngine* engine)
 {
 {
     registerBorderImage<Window>(engine, "Window");
     registerBorderImage<Window>(engine, "Window");
@@ -401,6 +431,7 @@ void registerUILibrary(asIScriptEngine* engine)
     registerText(engine);
     registerText(engine);
     registerLineEdit(engine);
     registerLineEdit(engine);
     registerMenu(engine);
     registerMenu(engine);
+    registerDropDownList(engine);
     registerWindow(engine);
     registerWindow(engine);
     registerUI(engine);
     registerUI(engine);
 }
 }

+ 34 - 9
Engine/UI/DropDownList.cpp

@@ -27,21 +27,20 @@
 #include "UIEvents.h"
 #include "UIEvents.h"
 #include "Window.h"
 #include "Window.h"
 
 
+#include "DebugNew.h"
+
 DropDownList::DropDownList(const std::string& name) :
 DropDownList::DropDownList(const std::string& name) :
-    Menu(name)
+    Menu(name),
+    mResizePopup(false)
 {
 {
     Window* window = new Window();
     Window* window = new Window();
     setPopup(window);
     setPopup(window);
-    setResizePopup(true);
     
     
     mListView = new ListView();
     mListView = new ListView();
     mListView->setScrollBarsVisible(false, false);
     mListView->setScrollBarsVisible(false, false);
-    // By default grow the popup and listview according to the items
-    mListView->getScrollPanel()->setLayout(O_VERTICAL, LM_RESIZECHILDREN, LM_RESIZEELEMENT);
-    mListView->setLayout(O_VERTICAL, LM_RESIZECHILDREN, LM_RESIZEELEMENT);
     mListView->setFocusMode(FM_RESETFOCUS);
     mListView->setFocusMode(FM_RESETFOCUS);
+    mPopup->setLayout(LM_VERTICAL);
     mPopup->addChild(mListView);
     mPopup->addChild(mListView);
-    mPopup->setLayout(O_VERTICAL, LM_RESIZECHILDREN, LM_RESIZEELEMENT);
     mPlaceholder = new UIElement();
     mPlaceholder = new UIElement();
     addChild(mPlaceholder);
     addChild(mPlaceholder);
     
     
@@ -79,6 +78,8 @@ void DropDownList::setStyle(const XMLElement& element, ResourceCache* cache)
     }
     }
     if (element.hasChildElement("selection"))
     if (element.hasChildElement("selection"))
         setSelection(element.getChildElement("selection").getInt("value"));
         setSelection(element.getChildElement("selection").getInt("value"));
+    if (element.hasChildElement("resizepopup"))
+        setResizePopup(element.getChildElement("resizepopup").getBool("enable"));
 }
 }
 
 
 void DropDownList::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 void DropDownList::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
@@ -101,10 +102,29 @@ void DropDownList::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>
     }
     }
 }
 }
 
 
-void DropDownList::onResize()
+void DropDownList::onShowPopup()
 {
 {
-    Menu::onResize();
-    setPopupOffset(0, getHeight());
+    // Resize the popup to match the size of the list content, and optionally match the button width
+    UIElement* content = mListView->getContentElement();
+    content->updateLayout();
+    const IntVector2& contentSize = content->getSize();
+    const IntRect& border = mPopup->getLayoutBorder();
+    mPopup->setSize(mResizePopup ? getWidth() : contentSize.mX + border.mLeft + border.mRight, contentSize.mY + border.mTop + 
+        border.mBottom);
+    
+    // Check if popup fits below the button. If not, show above instead
+    bool showAbove = false;
+    UIElement* root = getRootElement();
+    if (root)
+    {
+        const IntVector2& screenPos = getScreenPosition();
+        if ((screenPos.mY + getHeight() + mPopup->getHeight() > root->getHeight()) && (screenPos.mY - mPopup->getHeight() >= 0))
+            showAbove = true;
+    }
+    if (!showAbove)
+        setPopupOffset(0, getHeight());
+    else
+        setPopupOffset(0, -mPopup->getHeight());
 }
 }
 
 
 void DropDownList::addItem(UIElement* item)
 void DropDownList::addItem(UIElement* item)
@@ -140,6 +160,11 @@ void DropDownList::setSelection(unsigned index)
     mListView->setSelection(index);
     mListView->setSelection(index);
 }
 }
 
 
+void DropDownList::setResizePopup(bool enable)
+{
+    mResizePopup = enable;
+}
+
 unsigned DropDownList::getNumItems() const
 unsigned DropDownList::getNumItems() const
 {
 {
     return mListView->getNumItems();
     return mListView->getNumItems();

+ 9 - 3
Engine/UI/DropDownList.h

@@ -32,7 +32,7 @@ class DropDownList : public Menu
     
     
 public:
 public:
     //! Construct with name
     //! Construct with name
-    DropDownList(const std::string& name);
+    DropDownList(const std::string& name = std::string());
     //! Destruct
     //! Destruct
     ~DropDownList();
     ~DropDownList();
     
     
@@ -40,8 +40,8 @@ public:
     virtual void setStyle(const XMLElement& element, ResourceCache* cache);
     virtual void setStyle(const XMLElement& element, ResourceCache* cache);
     //! Return UI rendering batches
     //! Return UI rendering batches
     virtual void getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor);
     virtual void getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor);
-    //! React to resize
-    virtual void onResize();
+    //! React to the popup being shown
+    virtual void onShowPopup();
     
     
     //! Add item to the end of the list
     //! Add item to the end of the list
     void addItem(UIElement* item);
     void addItem(UIElement* item);
@@ -53,6 +53,8 @@ public:
     void removeAllItems();
     void removeAllItems();
     //! Set selection
     //! Set selection
     void setSelection(unsigned index);
     void setSelection(unsigned index);
+    //! Set whether popup should be automatically resized to match the dropdown button width
+    void setResizePopup(bool enable);
     
     
     //! Return number of items
     //! Return number of items
     unsigned getNumItems() const;
     unsigned getNumItems() const;
@@ -68,12 +70,16 @@ public:
     ListView* getListView() const { return mListView; }
     ListView* getListView() const { return mListView; }
     //! Return selected item placeholder element
     //! Return selected item placeholder element
     UIElement* getPlaceholder() const { return mPlaceholder; }
     UIElement* getPlaceholder() const { return mPlaceholder; }
+    //! Return whether popup should be automatically resized
+    bool getResizePopup() const { return mResizePopup; }
     
     
 protected:
 protected:
     //! Listview element
     //! Listview element
     SharedPtr<ListView> mListView;
     SharedPtr<ListView> mListView;
     //! Selected item placeholder element
     //! Selected item placeholder element
     SharedPtr<UIElement> mPlaceholder;
     SharedPtr<UIElement> mPlaceholder;
+    //! Resize popup flag
+    bool mResizePopup;
     
     
 private:
 private:
     //! Handle listview item selected event
     //! Handle listview item selected event

+ 10 - 3
Engine/UI/ListView.cpp

@@ -36,9 +36,7 @@ ListView::ListView(const std::string& name) :
 {
 {
     UIElement* container = new UIElement();
     UIElement* container = new UIElement();
     container->setEnabled(true);
     container->setEnabled(true);
-    container->setLayout(O_VERTICAL, LM_RESIZECHILDREN, LM_RESIZEELEMENT);
-    
-    mScrollPanel->setLayout(O_HORIZONTAL, LM_RESIZECHILDREN, LM_FREE);
+    container->setLayout(LM_VERTICAL);
     setContentElement(container);
     setContentElement(container);
     
     
     subscribeToEvent(EVENT_TRYFOCUS, EVENT_HANDLER(ListView, handleTryFocus));
     subscribeToEvent(EVENT_TRYFOCUS, EVENT_HANDLER(ListView, handleTryFocus));
@@ -143,6 +141,15 @@ void ListView::onKey(int key, int buttons, int qualifiers)
     }
     }
 }
 }
 
 
+void ListView::onResize()
+{
+    ScrollView::onResize();
+    
+    // Set the content element width to match the scrollpanel
+    const IntRect& clipBorder = mScrollPanel->getClipBorder();
+    mContentElement->setWidth(mScrollPanel->getWidth() - clipBorder.mLeft - clipBorder.mRight);
+}
+
 void ListView::onFocus()
 void ListView::onFocus()
 {
 {
     updateSelectionEffect();
     updateSelectionEffect();

+ 2 - 0
Engine/UI/ListView.h

@@ -43,6 +43,8 @@ public:
     virtual void onWheel(int delta, int buttons, int qualifiers);
     virtual void onWheel(int delta, int buttons, int qualifiers);
     //! React to a key press
     //! React to a key press
     virtual void onKey(int key, int buttons, int qualifiers);
     virtual void onKey(int key, int buttons, int qualifiers);
+    //! React to resize
+    virtual void onResize();
     //! React to defocus
     //! React to defocus
     virtual void onDefocus();
     virtual void onDefocus();
     //! React to focus
     //! React to focus

+ 3 - 14
Engine/UI/Menu.cpp

@@ -54,8 +54,6 @@ void Menu::setStyle(const XMLElement& element, ResourceCache* cache)
             setPopup(root->getChild(element.getChildElement("popup").getString("name"), true));
             setPopup(root->getChild(element.getChildElement("popup").getString("name"), true));
     }
     }
     
     
-    if (element.hasChildElement("resizepopup"))
-        setResizePopup(element.getChildElement("resizepopup").getBool("enable"));
     if (element.hasChildElement("popupoffset"))
     if (element.hasChildElement("popupoffset"))
         setPopupOffset(element.getChildElement("popupoffset").getIntVector2("value"));
         setPopupOffset(element.getChildElement("popupoffset").getIntVector2("value"));
 }
 }
@@ -77,10 +75,8 @@ void Menu::onClick(const IntVector2& position, const IntVector2& screenPosition,
     }
     }
 }
 }
 
 
-void Menu::onResize()
+void Menu::onShowPopup()
 {
 {
-    if ((mPopup) && (mResizePopup))
-        mPopup->setWidth(getWidth());
 }
 }
 
 
 void Menu::setPopup(UIElement* popup)
 void Menu::setPopup(UIElement* popup)
@@ -112,15 +108,6 @@ void Menu::setPopupOffset(int x, int y)
     mPopupOffset = IntVector2(x, y);
     mPopupOffset = IntVector2(x, y);
 }
 }
 
 
-void Menu::setResizePopup(bool enable)
-{
-    if (enable != mResizePopup)
-    {
-        mResizePopup = enable;
-        onResize();
-    }
-}
-
 void Menu::showPopup(bool enable)
 void Menu::showPopup(bool enable)
 {
 {
     if (!mPopup)
     if (!mPopup)
@@ -133,6 +120,8 @@ void Menu::showPopup(bool enable)
     
     
     if (enable)
     if (enable)
     {
     {
+        onShowPopup();
+        
         mPopup->setPosition(getScreenPosition() + mPopupOffset);
         mPopup->setPosition(getScreenPosition() + mPopupOffset);
         mPopup->setVisible(true);
         mPopup->setVisible(true);
         mPopup->setOrigin(this);
         mPopup->setOrigin(this);

+ 2 - 8
Engine/UI/Menu.h

@@ -40,8 +40,8 @@ class Menu : public Button
     virtual void setStyle(const XMLElement& element, ResourceCache* cache);
     virtual void setStyle(const XMLElement& element, ResourceCache* cache);
     //! React to mouse click
     //! React to mouse click
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers);
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers);
-    //! React to resize
-    virtual void onResize();
+    //! React to the popup being shown
+    virtual void onShowPopup();
     
     
     //! Set popup element to show on selection
     //! Set popup element to show on selection
     void setPopup(UIElement* element);
     void setPopup(UIElement* element);
@@ -49,8 +49,6 @@ class Menu : public Button
     void setPopupOffset(const IntVector2& offset);
     void setPopupOffset(const IntVector2& offset);
     //! Set popup element offset
     //! Set popup element offset
     void setPopupOffset(int x, int y);
     void setPopupOffset(int x, int y);
-    //! Set whether automatically resizes the popup to match width
-    void setResizePopup(bool enable);
     //! Force the popup to show or hide
     //! Force the popup to show or hide
     void showPopup(bool enable);
     void showPopup(bool enable);
     
     
@@ -60,8 +58,6 @@ class Menu : public Button
     const IntVector2& getPopupOffset() const { return mPopupOffset; }
     const IntVector2& getPopupOffset() const { return mPopupOffset; }
     //! Return whether popup is open
     //! Return whether popup is open
     bool getShowPopup() const { return mShowPopup; }
     bool getShowPopup() const { return mShowPopup; }
-    //! Return whether automatically resizes the popup
-    bool getResizePopup() const { return mResizePopup; }
     
     
 protected:
 protected:
     //! Popup element
     //! Popup element
@@ -70,8 +66,6 @@ protected:
     IntVector2 mPopupOffset;
     IntVector2 mPopupOffset;
     //! Show popup flag
     //! Show popup flag
     bool mShowPopup;
     bool mShowPopup;
-    //! Resize popup automatically flag
-    bool mResizePopup;
     
     
 private:
 private:
     //! Handle focus change attempt in case the popup needs to be hidden
     //! Handle focus change attempt in case the popup needs to be hidden

+ 4 - 1
Engine/UI/ScrollBar.cpp

@@ -158,7 +158,10 @@ void ScrollBar::setOrientation(Orientation orientation)
     }
     }
     
     
     onResize();
     onResize();
-    setLayout(orientation, LM_RESIZECHILDREN, LM_RESIZECHILDREN);
+    if (orientation == O_HORIZONTAL)
+        setLayout(LM_HORIZONTAL);
+    else
+        setLayout(LM_VERTICAL);
 }
 }
 
 
 void ScrollBar::setRange(float range)
 void ScrollBar::setRange(float range)

+ 1 - 1
Engine/UI/ScrollView.cpp

@@ -102,7 +102,7 @@ void ScrollView::onWheel(int delta, int buttons, int qualifiers)
     if (delta > 0)
     if (delta > 0)
         mVerticalScrollBar->stepBack();
         mVerticalScrollBar->stepBack();
     if (delta < 0)
     if (delta < 0)
-        mHorizontalScrollBar->stepForward();
+        mVerticalScrollBar->stepForward();
 }
 }
 
 
 void ScrollView::onKey(int key, int buttons, int qualifiers)
 void ScrollView::onKey(int key, int buttons, int qualifiers)

+ 4 - 3
Engine/UI/Text.cpp

@@ -102,11 +102,12 @@ void Text::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads,
         batch.mBlendMode = BLEND_ALPHA;
         batch.mBlendMode = BLEND_ALPHA;
         batch.mScissor = currentScissor;
         batch.mScissor = currentScissor;
         batch.mTexture = 0;
         batch.mTexture = 0;
-        batch.addQuad(*this, 0, 0, getWidth(), getHeight(), 0, 0, 0, 0, mSelected ? mSelectionColor : mHoverColor);
+        batch.addQuad(*this, 0, 0, getWidth(), getHeight(), 0, 0, 0, 0, (mSelected && (mSelectionColor.mA > 0.0f)) ? mSelectionColor :
+            mHoverColor);
         UIBatch::addOrMerge(batch, batches);
         UIBatch::addOrMerge(batch, batches);
     }
     }
     
     
-    // Partial Selection batch
+    // Partial selection batch
     if ((!mSelected) && (mSelectionLength) && (mCharSizes.size() >= mSelectionStart + mSelectionLength) && (mSelectionColor.mA > 0.0f))
     if ((!mSelected) && (mSelectionLength) && (mCharSizes.size() >= mSelectionStart + mSelectionLength) && (mSelectionColor.mA > 0.0f))
     {
     {
         UIBatch batch;
         UIBatch batch;
@@ -434,7 +435,7 @@ void Text::updateText(bool inResize)
     if (!mWordwrap)
     if (!mWordwrap)
         setMinSize(width, height);
         setMinSize(width, height);
     else
     else
-        setMinSize(0, height);
+        setMinHeight(height);
 }
 }
 
 
 void Text::validateSelection()
 void Text::validateSelection()

+ 102 - 169
Engine/UI/UIElement.cpp

@@ -46,9 +46,7 @@ UIElement::UIElement(const std::string& name) :
     mSelected(false),
     mSelected(false),
     mVisible(true),
     mVisible(true),
     mHovering(false),
     mHovering(false),
-    mLayoutOrientation(O_VERTICAL),
-    mHorizontalLayoutMode(LM_FREE),
-    mVerticalLayoutMode(LM_FREE),
+    mLayoutMode(LM_FREE),
     mLayoutSpacing(0),
     mLayoutSpacing(0),
     mLayoutBorder(IntRect::sZero),
     mLayoutBorder(IntRect::sZero),
     mResizeNestingLevel(0),
     mResizeNestingLevel(0),
@@ -98,10 +96,22 @@ void UIElement::setStyle(const XMLElement& element, ResourceCache* cache)
         setHeight(element.getChildElement("height").getInt("value"));
         setHeight(element.getChildElement("height").getInt("value"));
     if (element.hasChildElement("minsize"))
     if (element.hasChildElement("minsize"))
         setMinSize(element.getChildElement("minsize").getIntVector2("value"));
         setMinSize(element.getChildElement("minsize").getIntVector2("value"));
+    if (element.hasChildElement("minwidth"))
+        setMinWidth(element.getChildElement("minwidth").getInt("value"));
+    if (element.hasChildElement("minheight"))
+        setMinHeight(element.getChildElement("minheight").getInt("value"));
     if (element.hasChildElement("maxsize"))
     if (element.hasChildElement("maxsize"))
         setMaxSize(element.getChildElement("maxsize").getIntVector2("value"));
         setMaxSize(element.getChildElement("maxsize").getIntVector2("value"));
+    if (element.hasChildElement("maxwidth"))
+        setMinWidth(element.getChildElement("maxwidth").getInt("value"));
+    if (element.hasChildElement("maxheight"))
+        setMinHeight(element.getChildElement("maxheight").getInt("value"));
     if (element.hasChildElement("fixedsize"))
     if (element.hasChildElement("fixedsize"))
         setFixedSize(element.getChildElement("fixedsize").getIntVector2("value"));
         setFixedSize(element.getChildElement("fixedsize").getIntVector2("value"));
+    if (element.hasChildElement("fixedwidth"))
+        setFixedWidth(element.getChildElement("fixedwidth").getInt("value"));
+    if (element.hasChildElement("fixedheight"))
+        setFixedHeight(element.getChildElement("fixedheight").getInt("value"));
     if (element.hasChildElement("alignment"))
     if (element.hasChildElement("alignment"))
     {
     {
         XMLElement alignElem = element.getChildElement("alignment");
         XMLElement alignElem = element.getChildElement("alignment");
@@ -176,41 +186,20 @@ void UIElement::setStyle(const XMLElement& element, ResourceCache* cache)
     if (element.hasChildElement("layout"))
     if (element.hasChildElement("layout"))
     {
     {
         XMLElement layoutElem = element.getChildElement("layout");
         XMLElement layoutElem = element.getChildElement("layout");
-        std::string orientation = layoutElem.getStringLower("orientation");
-        if ((orientation == "horizontal") || (orientation == "h"))
-            mLayoutOrientation = O_HORIZONTAL;
-        if ((orientation == "vertical") || (orientation == "v"))
-            mLayoutOrientation = O_VERTICAL;
-        
-        std::string horiz;
-        std::string vert;
-        if (layoutElem.hasAttribute("h"))
-            horiz = layoutElem.getStringLower("h");
-        if (layoutElem.hasAttribute("v"))
-            vert = layoutElem.getStringLower("v");
-        if (layoutElem.hasAttribute("horizontal"))
-            horiz = layoutElem.getStringLower("horizontal");
-        if (layoutElem.hasAttribute("vertical"))
-            vert = layoutElem.getStringLower("vertical");
-        if (horiz == "free")
-            mHorizontalLayoutMode = LM_FREE;
-        if ((horiz == "children") || (horiz == "resizechildren"))
-            mHorizontalLayoutMode = LM_RESIZECHILDREN;
-        if ((horiz == "element") || (horiz == "resizeelement"))
-            mHorizontalLayoutMode = LM_RESIZEELEMENT;
-        if (vert == "free")
-            mVerticalLayoutMode = LM_FREE;
-        if ((vert == "children") || (vert == "resizechildren"))
-            mVerticalLayoutMode = LM_RESIZECHILDREN;
-        if ((vert == "element") || (vert == "resizeelement"))
-            mVerticalLayoutMode = LM_RESIZEELEMENT;
+        std::string mode = layoutElem.getStringLower("mode");
+        if (mode == "free")
+            mLayoutMode = LM_FREE;
+        if ((mode == "horizontal") || (mode == "h"))
+            mLayoutMode = LM_HORIZONTAL;
+        if ((mode == "vertical") || (mode == "v"))
+            mLayoutMode = LM_VERTICAL;
         
         
         if (layoutElem.hasAttribute("spacing"))
         if (layoutElem.hasAttribute("spacing"))
             mLayoutSpacing = max(layoutElem.getInt("spacing"), 0);
             mLayoutSpacing = max(layoutElem.getInt("spacing"), 0);
         if (layoutElem.hasAttribute("border"))
         if (layoutElem.hasAttribute("border"))
-            mLayoutBorder = layoutElem.getIntRect("border");
-        
-        updateLayout();
+            setLayoutBorder(layoutElem.getIntRect("border"));
+        else
+            updateLayout();
     }
     }
 }
 }
 
 
@@ -624,20 +613,29 @@ void UIElement::setStyleAuto(XMLFile* file, ResourceCache* cache)
     setStyle(element, cache);
     setStyle(element, cache);
 }
 }
 
 
-void UIElement::setLayout(Orientation orientation, LayoutMode horizontal, LayoutMode vertical, int spacing, const IntRect& border)
+void UIElement::setLayout(LayoutMode mode, int spacing, const IntRect& border)
 {
 {
-    mLayoutOrientation = orientation;
-    mHorizontalLayoutMode = horizontal;
-    mVerticalLayoutMode = vertical;
+    mLayoutMode = mode;
     mLayoutSpacing = max(spacing, 0);
     mLayoutSpacing = max(spacing, 0);
-    mLayoutBorder = border;
-    
+    mLayoutBorder = IntRect(max(border.mLeft, 0), max(border.mTop, 0), max(border.mRight, 0), max(border.mBottom, 0));
+    updateLayout();
+}
+
+void UIElement::setLayoutSpacing(int spacing)
+{
+    mLayoutSpacing = max(spacing, 0);
+    updateLayout();
+}
+
+void UIElement::setLayoutBorder(const IntRect& border)
+{
+    mLayoutBorder = IntRect(max(border.mLeft, 0), max(border.mTop, 0), max(border.mRight, 0), max(border.mBottom, 0));
     updateLayout();
     updateLayout();
 }
 }
 
 
 void UIElement::updateLayout()
 void UIElement::updateLayout()
 {
 {
-    if ((mUpdateLayoutNestingLevel) || ((mHorizontalLayoutMode == LM_FREE) && (mVerticalLayoutMode == LM_FREE)))
+    if ((mLayoutMode == LM_FREE) || (mUpdateLayoutNestingLevel))
         return;
         return;
     
     
     ++mUpdateLayoutNestingLevel;
     ++mUpdateLayoutNestingLevel;
@@ -647,146 +645,78 @@ void UIElement::updateLayout()
     std::vector<int> minSizes;
     std::vector<int> minSizes;
     std::vector<int> maxSizes;
     std::vector<int> maxSizes;
     
     
-    if (mLayoutOrientation == O_HORIZONTAL)
+    if (mLayoutMode == LM_HORIZONTAL)
     {
     {
-        int maxChildHeight = 0;
-        int maxChildMinHeight = 0;
+        int minChildHeight = 0;
         
         
-        if (mHorizontalLayoutMode == LM_RESIZEELEMENT)
+        for (unsigned i = 0; i < mChildren.size(); ++i)
         {
         {
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                sizes.push_back(mChildren[i]->getWidth());
-                maxChildHeight = max(maxChildHeight, mChildren[i]->getHeight());
-                maxChildMinHeight = max(maxChildMinHeight, mChildren[i]->getMinHeight());
-            }
-            
-            if (mVerticalLayoutMode == LM_RESIZEELEMENT)
-                setMinHeight(maxChildMinHeight + mLayoutBorder.mTop + mLayoutBorder.mBottom);
-            setSize(calculateLayoutParentSize(sizes, mLayoutBorder.mLeft, mLayoutBorder.mRight, mLayoutSpacing), mVerticalLayoutMode ==
-                LM_RESIZEELEMENT ? maxChildHeight + mLayoutBorder.mTop + mLayoutBorder.mBottom : getHeight());
-            
-            int position = mLayoutBorder.mLeft;
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                mChildren[i]->setHorizontalAlignment(HA_LEFT);
-                mChildren[i]->setPosition(position, getLayoutChildPosition(mChildren[i]).mY);
-                if (mVerticalLayoutMode == LM_RESIZECHILDREN)
-                    mChildren[i]->setHeight(getHeight() - mLayoutBorder.mTop - mLayoutBorder.mBottom);
-                position += mChildren[i]->getWidth();
-                position += mLayoutSpacing;
-            }
+            if (!mChildren[i]->isVisible())
+                continue;
+            positions.push_back(0);
+            sizes.push_back(mChildren[i]->getWidth());
+            minSizes.push_back(mChildren[i]->getMinWidth());
+            maxSizes.push_back(mChildren[i]->getMaxWidth());
+            minChildHeight = max(minChildHeight, mChildren[i]->getMinHeight());
         }
         }
         
         
-        if (mHorizontalLayoutMode == LM_RESIZECHILDREN)
+        calculateLayout(positions, sizes, minSizes, maxSizes, getWidth(), mLayoutBorder.mLeft, mLayoutBorder.mRight,
+            mLayoutSpacing);
+        
+        int width = calculateLayoutParentSize(sizes, mLayoutBorder.mLeft, mLayoutBorder.mRight, mLayoutSpacing);
+        int height = max(getHeight(), minChildHeight + mLayoutBorder.mTop + mLayoutBorder.mBottom);
+        int minWidth = calculateLayoutParentSize(minSizes, mLayoutBorder.mLeft, mLayoutBorder.mRight, mLayoutSpacing);
+        int minHeight = minChildHeight + mLayoutBorder.mTop + mLayoutBorder.mBottom;
+        setMinSize(minWidth, minHeight);
+        setSize(width, height);
+        
+        unsigned j = 0;
+        for (unsigned i = 0; i < mChildren.size(); ++i)
         {
         {
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                positions.push_back(0);
-                sizes.push_back(mChildren[i]->getWidth());
-                minSizes.push_back(mChildren[i]->getMinWidth());
-                maxSizes.push_back(mChildren[i]->getMaxWidth());
-                maxChildHeight = max(maxChildHeight, mChildren[i]->getHeight());
-                maxChildMinHeight = max(maxChildMinHeight, mChildren[i]->getMinHeight());
-            }
-            
-            if (mVerticalLayoutMode == LM_RESIZEELEMENT)
-            {
-                setMinHeight(maxChildMinHeight + mLayoutBorder.mTop + mLayoutBorder.mBottom);
-                setHeight(maxChildHeight + mLayoutBorder.mTop + mLayoutBorder.mBottom);
-            }
-            
-            calculateLayout(positions, sizes, minSizes, maxSizes, getWidth(), mLayoutBorder.mLeft, mLayoutBorder.mRight,
-                mLayoutSpacing);
-            
-            unsigned j = 0;
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                mChildren[i]->setHorizontalAlignment(HA_LEFT);
-                mChildren[i]->setPosition(positions[j], getLayoutChildPosition(mChildren[i]).mY);
-                mChildren[i]->setSize(sizes[j], mVerticalLayoutMode == LM_RESIZECHILDREN ? getHeight() - mLayoutBorder.mTop -
-                    mLayoutBorder.mBottom : mChildren[i]->getHeight());
-                ++j;
-            }
+            if (!mChildren[i]->isVisible())
+                continue;
+            mChildren[i]->setHorizontalAlignment(HA_LEFT);
+            mChildren[i]->setPosition(positions[j], getLayoutChildPosition(mChildren[i]).mY);
+            mChildren[i]->setSize(sizes[j], height - mLayoutBorder.mTop - mLayoutBorder.mBottom);
+            ++j;
         }
         }
     }
     }
     
     
-    if (mLayoutOrientation == O_VERTICAL)
+    if (mLayoutMode == LM_VERTICAL)
     {
     {
-        int maxChildWidth = 0;
-        int maxChildMinWidth = 0;
+        int minChildWidth = 0;
+        int maxChildWidth = M_MAX_INT;
         
         
-        if (mVerticalLayoutMode == LM_RESIZEELEMENT)
+        for (unsigned i = 0; i < mChildren.size(); ++i)
         {
         {
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                sizes.push_back(mChildren[i]->getHeight());
-                maxChildWidth = max(maxChildWidth, mChildren[i]->getWidth());
-                maxChildMinWidth = max(maxChildMinWidth, mChildren[i]->getMinWidth());
-            }
-            
-            if (mHorizontalLayoutMode == LM_RESIZEELEMENT)
-                setMinWidth(maxChildMinWidth + mLayoutBorder.mLeft + mLayoutBorder.mRight);
-            setSize(mHorizontalLayoutMode == LM_RESIZEELEMENT ? maxChildWidth + mLayoutBorder.mLeft + mLayoutBorder.mRight : getWidth(),
-                calculateLayoutParentSize(sizes, mLayoutBorder.mTop, mLayoutBorder.mBottom, mLayoutSpacing));
-            
-            int position = mLayoutBorder.mTop;
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                mChildren[i]->setVerticalAlignment(VA_TOP);
-                mChildren[i]->setPosition(getLayoutChildPosition(mChildren[i]).mX, position);
-                if (mHorizontalLayoutMode == LM_RESIZECHILDREN)
-                    mChildren[i]->setWidth(getWidth() - mLayoutBorder.mLeft - mLayoutBorder.mRight);
-                position += mChildren[i]->getHeight();
-                position += mLayoutSpacing;
-            }
+            if (!mChildren[i]->isVisible())
+                continue;
+            positions.push_back(0);
+            sizes.push_back(mChildren[i]->getHeight());
+            minSizes.push_back(mChildren[i]->getMinHeight());
+            maxSizes.push_back(mChildren[i]->getMaxHeight());
+            minChildWidth = max(minChildWidth, mChildren[i]->getMinWidth());
         }
         }
-        else
+        
+        calculateLayout(positions, sizes, minSizes, maxSizes, getHeight(), mLayoutBorder.mTop, mLayoutBorder.mBottom,
+            mLayoutSpacing);
+        
+        int height = calculateLayoutParentSize(sizes, mLayoutBorder.mTop, mLayoutBorder.mBottom, mLayoutSpacing);
+        int width = max(getWidth(), minChildWidth + mLayoutBorder.mLeft + mLayoutBorder.mRight);
+        int minHeight = calculateLayoutParentSize(minSizes, mLayoutBorder.mTop, mLayoutBorder.mBottom, mLayoutSpacing);
+        int minWidth = minChildWidth + mLayoutBorder.mLeft + mLayoutBorder.mRight;
+        setMinSize(minWidth, minHeight);
+        setSize(width, height);
+        
+        unsigned j = 0;
+        for (unsigned i = 0; i < mChildren.size(); ++i)
         {
         {
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                positions.push_back(0);
-                sizes.push_back(mChildren[i]->getHeight());
-                minSizes.push_back(mChildren[i]->getMinHeight());
-                maxSizes.push_back(mChildren[i]->getMaxHeight());
-                maxChildWidth = max(maxChildWidth, mChildren[i]->getWidth());
-                maxChildMinWidth = max(maxChildMinWidth, mChildren[i]->getMinWidth());
-            }
-            
-            if (mHorizontalLayoutMode == LM_RESIZEELEMENT)
-            {
-                setMinWidth(maxChildMinWidth + mLayoutBorder.mLeft + mLayoutBorder.mRight);
-                setWidth(maxChildWidth + mLayoutBorder.mLeft + mLayoutBorder.mRight);
-            }
-            
-            calculateLayout(positions, sizes, minSizes, maxSizes, getHeight(), mLayoutBorder.mTop, mLayoutBorder.mBottom,
-                mLayoutSpacing);
-            
-            unsigned j = 0;
-            for (unsigned i = 0; i < mChildren.size(); ++i)
-            {
-                if (!mChildren[i]->isVisible())
-                    continue;
-                mChildren[i]->setVerticalAlignment(VA_TOP);
-                mChildren[i]->setPosition(getLayoutChildPosition(mChildren[i]).mX, positions[j]);
-                mChildren[i]->setSize(mHorizontalLayoutMode == LM_RESIZECHILDREN ? getWidth() - mLayoutBorder.mLeft -
-                    mLayoutBorder.mRight : mChildren[i]->getWidth(), sizes[j]);
-                ++j;
-            }
+            if (!mChildren[i]->isVisible())
+                continue;
+            mChildren[i]->setVerticalAlignment(VA_TOP);
+            mChildren[i]->setPosition(getLayoutChildPosition(mChildren[i]).mX, positions[j]);
+            mChildren[i]->setSize(width - mLayoutBorder.mLeft - mLayoutBorder.mRight, sizes[j]);
+            ++j;
         }
         }
     }
     }
     
     
@@ -1100,6 +1030,9 @@ int UIElement::calculateLayoutParentSize(const std::vector<int>& sizes, int begi
     int width = begin + end;
     int width = begin + end;
     for (unsigned i = 0; i < sizes.size(); ++i)
     for (unsigned i = 0; i < sizes.size(); ++i)
     {
     {
+        // If we are calculating maximum size, and the default is specified, do not overflow it
+        if (sizes[i] == M_MAX_INT)
+            return M_MAX_INT;
         width += sizes[i];
         width += sizes[i];
         if (i < sizes.size() - 1)
         if (i < sizes.size() - 1)
             width += spacing;
             width += spacing;
@@ -1108,12 +1041,12 @@ int UIElement::calculateLayoutParentSize(const std::vector<int>& sizes, int begi
 }
 }
 
 
 void UIElement::calculateLayout(std::vector<int>& positions, std::vector<int>& sizes, const std::vector<int>& minSizes,
 void UIElement::calculateLayout(std::vector<int>& positions, std::vector<int>& sizes, const std::vector<int>& minSizes,
-        const std::vector<int>& maxSizes, int targetWidth, int begin, int end, int spacing)
+        const std::vector<int>& maxSizes, int targetSize, int begin, int end, int spacing)
 {
 {
     unsigned numChildren = sizes.size();
     unsigned numChildren = sizes.size();
     if (!numChildren)
     if (!numChildren)
         return;
         return;
-    int targetTotalSize = targetWidth - begin - end - (numChildren - 1) * spacing;
+    int targetTotalSize = targetSize - begin - end - (numChildren - 1) * spacing;
     if (targetTotalSize < 0)
     if (targetTotalSize < 0)
         targetTotalSize = 0;
         targetTotalSize = 0;
     int targetChildSize = targetTotalSize / numChildren;
     int targetChildSize = targetTotalSize / numChildren;

+ 14 - 16
Engine/UI/UIElement.h

@@ -80,9 +80,12 @@ enum FocusMode
 //! Layout operation mode
 //! Layout operation mode
 enum LayoutMode
 enum LayoutMode
 {
 {
+    //! No layout operations will be performed
     LM_FREE = 0,
     LM_FREE = 0,
-    LM_RESIZECHILDREN,
-    LM_RESIZEELEMENT
+    //! Layout child elements horizontally and resize them to fit. Resize element if necessary
+    LM_HORIZONTAL,
+    //! Layout child elements vertically and resize them to fit. Resize element if necessary
+    LM_VERTICAL
 };
 };
 
 
 class ResourceCache;
 class ResourceCache;
@@ -209,8 +212,11 @@ public:
     //! Set style from an XML file. Find the style element automatically
     //! Set style from an XML file. Find the style element automatically
     void setStyleAuto(XMLFile* file, ResourceCache* cache);
     void setStyleAuto(XMLFile* file, ResourceCache* cache);
     //! Set layout
     //! Set layout
-    void setLayout(Orientation orientation, LayoutMode horizontal, LayoutMode vertical, int spacing = 0,
-        const IntRect& border = IntRect::sZero);
+    void setLayout(LayoutMode mode, int spacing = 0, const IntRect& border = IntRect::sZero);
+    //! Set layout spacing
+    void setLayoutSpacing(int spacing);
+    //! Set layout border
+    void setLayoutBorder(const IntRect& border);
     //! Manually update layout. Should not be necessary in most cases, but is provided for completeness
     //! Manually update layout. Should not be necessary in most cases, but is provided for completeness
     void updateLayout();
     void updateLayout();
     //! Bring UI element to front
     //! Bring UI element to front
@@ -280,12 +286,8 @@ public:
     bool hasColorGradient() const { return mHasColorGradient; }
     bool hasColorGradient() const { return mHasColorGradient; }
     //! Return userdata
     //! Return userdata
     Variant getUserData() const { return mUserData; }
     Variant getUserData() const { return mUserData; }
-    //! Return layout orientation
-    Orientation getLayoutOrientation() const { return mLayoutOrientation; }
-    //! Return horizontal layout mode
-    LayoutMode getHorizontalLayoutMode() const { return mHorizontalLayoutMode; }
-    //! Return vertical layout mode
-    LayoutMode getVerticalLayoutMode() const { return mVerticalLayoutMode; }
+    //! Return layout mode
+    LayoutMode getLayoutMode() const { return mLayoutMode; }
     //! Return layout spacing
     //! Return layout spacing
     int getLayoutSpacing() const { return mLayoutSpacing; }
     int getLayoutSpacing() const { return mLayoutSpacing; }
     //! Return layout border
     //! Return layout border
@@ -371,12 +373,8 @@ protected:
     bool mHovering;
     bool mHovering;
     //! Userdata
     //! Userdata
     Variant mUserData;
     Variant mUserData;
-    //! Layout orientation
-    Orientation mLayoutOrientation;
-    //! Horizontal layout mode
-    LayoutMode mHorizontalLayoutMode;
-    //! Vertical layout mode
-    LayoutMode mVerticalLayoutMode;
+    //! Layout mode
+    LayoutMode mLayoutMode;
     //! Layout spacing
     //! Layout spacing
     int mLayoutSpacing;
     int mLayoutSpacing;
     //! Layout borders
     //! Layout borders