diff --git a/CMakeLists.txt b/CMakeLists.txt index 34bbc3de..dbf61041 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,7 @@ SET(SOURCES src/framework/graphics/textarea.cpp # framework ui - src/framework/ui/uilayout.cpp + src/framework/ui/uianchorlayout.cpp src/framework/ui/uielement.cpp src/framework/ui/uielementskin.cpp src/framework/ui/uibuttonskin.cpp diff --git a/data/modules/mainmenu/menustate.lua b/data/modules/mainmenu/menustate.lua index 629bd3af..2c7070ba 100644 --- a/data/modules/mainmenu/menustate.lua +++ b/data/modules/mainmenu/menustate.lua @@ -4,8 +4,7 @@ function onEnterMenuState() end function onLeaveMenuState() - mainMenu:destroy() - mainMenu = nil + end function onApplicationClose() diff --git a/data/skins/tibiaskin.yml b/data/skins/tibiaskin.yml index f95511e3..fae37292 100644 --- a/data/skins/tibiaskin.yml +++ b/data/skins/tibiaskin.yml @@ -34,7 +34,6 @@ panels: # the default panel is empty roundedGridPanel: - default size: [117, 171] bordered image: left border: [0,214,5,32] right border: [6,214,5,32] diff --git a/src/framework/core/engine.cpp b/src/framework/core/engine.cpp index f6b4dae0..618aad58 100644 --- a/src/framework/core/engine.cpp +++ b/src/framework/core/engine.cpp @@ -39,6 +39,7 @@ void Engine::init() // initialize stuff g_graphics.init(); g_fonts.init("tibia-12px-rounded"); + g_lua.init(); } void Engine::terminate() @@ -46,6 +47,14 @@ void Engine::terminate() // terminate stuff g_fonts.terminate(); g_graphics.terminate(); + + // destroy root ui + UIContainer::getRoot()->destroy(); + + g_lua.terminate(); + + // poll remaning events + g_engine.poll(); } void Engine::poll() @@ -116,14 +125,6 @@ void Engine::run() m_stopping = false; m_running = false; - - g_lua.collectGarbage(); - - // destroy root ui - rootContainer->destroy(); - - // poll remaning events - g_engine.poll(); } void Engine::stop() diff --git a/src/framework/script/luafunctions.cpp b/src/framework/script/luafunctions.cpp index 8736d8ee..853196ee 100644 --- a/src/framework/script/luafunctions.cpp +++ b/src/framework/script/luafunctions.cpp @@ -41,11 +41,8 @@ void registerLuaFunctions() g_lua.registerMemberFunction("load", &lua_UI_load); g_lua.registerMemberFunction("getRootContainer", &lua_UI_getRootContainer); - // UILayout - g_lua.registerClass("UILayout"); - // UIElement - g_lua.registerClass("UIElement", "UILayout"); + g_lua.registerClass("UIElement"); g_lua.registerMemberField("id", &lua_UIElement_getId, &lua_UIElement_setId); g_lua.registerMemberField("enabled", &lua_UIElement_isEnabled, &lua_UIElement_setEnabled); g_lua.registerMemberField("visible", &lua_UIElement_isVisible, &lua_UIElement_setVisible); @@ -224,7 +221,7 @@ int lua_UIElement_setLocked() int lua_UIElement_destroy() { if(UIElementPtr element = boost::dynamic_pointer_cast(g_lua.popClassInstance())) - element->destroy(); + element->destroyLater(); g_dispatcher.addTask(boost::bind(&LuaScript::collectGarbage, &g_lua)); return 1; } diff --git a/src/framework/script/luascript.cpp b/src/framework/script/luascript.cpp index c95dd853..406ddff9 100644 --- a/src/framework/script/luascript.cpp +++ b/src/framework/script/luascript.cpp @@ -30,7 +30,7 @@ LuaScript g_lua; -LuaScript::LuaScript() +void LuaScript::init() { L = luaL_newstate(); if(!L) @@ -45,9 +45,11 @@ LuaScript::LuaScript() registerLuaFunctions(); } -LuaScript::~LuaScript() +void LuaScript::terminate() { + collectGarbage(); lua_close(L); + L = NULL; } void LuaScript::loadAllModules() diff --git a/src/framework/script/luascript.h b/src/framework/script/luascript.h index cdbac6c5..2c933cb1 100644 --- a/src/framework/script/luascript.h +++ b/src/framework/script/luascript.h @@ -36,8 +36,10 @@ struct lua_State; class LuaScript { public: - LuaScript(); - virtual ~LuaScript(); + LuaScript() : L(NULL) { } + + void init(); + void terminate(); void loadAllModules(); bool loadFile(const std::string& fileName); diff --git a/src/framework/ui/uianchorlayout.cpp b/src/framework/ui/uianchorlayout.cpp new file mode 100644 index 00000000..33979ac3 --- /dev/null +++ b/src/framework/ui/uianchorlayout.cpp @@ -0,0 +1,162 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include +#include + +UIElementPtr Anchor::getAnchorLineElement() const +{ + if(!m_anchoredElement.expired()) + return m_anchoredElement.lock()->backwardsGetElementById(m_anchorLine.getElementId()); + return UIElementPtr(); +} + +int Anchor::getAnchorLinePoint() const +{ + UIElementPtr anchorLineElement = getAnchorLineElement(); + if(anchorLineElement) { + switch(m_anchorLine.getEdge()) { + case UI::AnchorLeft: + return anchorLineElement->getRect().left(); + case UI::AnchorRight: + return anchorLineElement->getRect().right(); + case UI::AnchorTop: + return anchorLineElement->getRect().top(); + case UI::AnchorBottom: + return anchorLineElement->getRect().bottom(); + case UI::AnchorHorizontalCenter: + return anchorLineElement->getRect().horizontalCenter(); + case UI::AnchorVerticalCenter: + return anchorLineElement->getRect().verticalCenter(); + default: + break; + } + } + return -9999; +} + +bool UIAnchorLayout::addAnchor(const UIElementPtr& anchoredElement, UI::AnchorPoint anchoredEdge, const AnchorLine& anchorLine) +{ + Anchor anchor(anchoredElement, anchoredEdge, anchorLine); + UIElementPtr anchorLineElement = anchor.getAnchorLineElement(); + + // we can never anchor with itself + if(anchoredElement == anchorLineElement) { + logError("ERROR: anchoring with itself is not possible"); + return false; + } + + // TODO: check if itself is already anchored on the anchor element + + // setup the anchor + m_anchors.push_back(anchor); + + // recalculate anchored element layout + recalculateElementLayout(anchoredElement); + return true; +} + +void UIAnchorLayout::recalculateElementLayout(const UIElementPtr& element) +{ + Rect rect = element->getRect(); + bool verticalMoved = false; + bool horizontalMoved = false; + + foreach(const Anchor& anchor, m_anchors) { + if(anchor.getAnchoredElement() == element && anchor.getAnchorLineElement()) { + int point = anchor.getAnchorLinePoint(); + switch(anchor.getAnchoredEdge()) { + case UI::AnchorHorizontalCenter: + rect.moveHorizontalCenter(point + element->getMarginLeft() - element->getMarginRight()); + horizontalMoved = true; + break; + case UI::AnchorLeft: + if(!horizontalMoved) { + rect.moveLeft(point + element->getMarginLeft()); + horizontalMoved = true; + } else + rect.setLeft(point + element->getMarginLeft()); + break; + case UI::AnchorRight: + if(!horizontalMoved) { + rect.moveRight(point - element->getMarginRight()); + horizontalMoved = true; + } else + rect.setRight(point - element->getMarginRight()); + break; + case UI::AnchorVerticalCenter: + rect.moveVerticalCenter(point + element->getMarginTop() - element->getMarginBottom()); + verticalMoved = true; + break; + case UI::AnchorTop: + if(!verticalMoved) { + rect.moveTop(point + element->getMarginTop()); + verticalMoved = true; + } else + rect.setTop(point + element->getMarginTop()); + break; + case UI::AnchorBottom: + if(!verticalMoved) { + rect.moveBottom(point - element->getMarginBottom()); + verticalMoved = true; + } else + rect.setBottom(point - element->getMarginBottom()); + break; + default: + break; + } + } + } + + if(rect != element->getRect()) + element->setRect(rect); +} + +void UIAnchorLayout::recalculateChildrenLayout(const UIElementPtr& parent) +{ + foreach(const Anchor& anchor, m_anchors) { + if(anchor.getAnchorLineElement() == parent) { + UIElementPtr child = anchor.getAnchoredElement(); + if(child) + recalculateElementLayout(child); + } + } +} + +UI::AnchorPoint UIAnchorLayout::parseAnchorPoint(const std::string& anchorPointStr) +{ + if(anchorPointStr == "left") + return UI::AnchorLeft; + else if(anchorPointStr == "right") + return UI::AnchorRight; + else if(anchorPointStr == "top") + return UI::AnchorTop; + else if(anchorPointStr == "bottom") + return UI::AnchorBottom; + else if(anchorPointStr == "horizontalCenter") + return UI::AnchorHorizontalCenter; + else if(anchorPointStr == "verticalCenter") + return UI::AnchorVerticalCenter; + return UI::AnchorNone; +} diff --git a/src/framework/ui/uianchorlayout.h b/src/framework/ui/uianchorlayout.h new file mode 100644 index 00000000..f99d4e98 --- /dev/null +++ b/src/framework/ui/uianchorlayout.h @@ -0,0 +1,77 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef UIANCHORLAYOUT_H +#define UIANCHORLAYOUT_H + +#include +#include +#include +#include + +class AnchorLine +{ +public: + AnchorLine(const std::string& elementId, UI::AnchorPoint edge) : m_elementId(elementId), m_edge(edge) { } + AnchorLine(const AnchorLine& other) : m_elementId(other.m_elementId), m_edge(other.m_edge) { } + UI::AnchorPoint getEdge() const { return m_edge; } + const std::string& getElementId() const { return m_elementId; } + +private: + std::string m_elementId; + UI::AnchorPoint m_edge; +}; + +class Anchor +{ +public: + Anchor(const UIElementPtr& anchoredElement, UI::AnchorPoint anchoredEdge, const AnchorLine& anchorLine) + : m_anchoredElement(anchoredElement), m_anchoredEdge(anchoredEdge), m_anchorLine(anchorLine) { } + UIElementPtr getAnchorLineElement() const ; + UIElementPtr getAnchoredElement() const { return m_anchoredElement.lock(); } + UI::AnchorPoint getAnchoredEdge() const { return m_anchoredEdge; } + int getAnchorLinePoint() const; + +private: + UIElementWeakPtr m_anchoredElement; + UI::AnchorPoint m_anchoredEdge; + AnchorLine m_anchorLine; +}; + +class UIAnchorLayout : public UILayout +{ +public: + bool addAnchor(const UIElementPtr& anchoredElement, UI::AnchorPoint anchoredEdge, const AnchorLine& anchorLine); + void recalculateElementLayout(const UIElementPtr& element); + void recalculateChildrenLayout(const UIElementPtr& parent); + + static UI::AnchorPoint parseAnchorPoint(const std::string& anchorPointStr); + +private: + std::vector m_anchors; +}; + +typedef boost::shared_ptr UIAnchorLayoutPtr; + +#endif // UIANCHORLAYOUT_H diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index 4b448473..8195876f 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -29,9 +29,9 @@ void UIButton::onInputEvent(const InputEvent& event) { if(event.type == EV_MOUSE_LDOWN && getRect().contains(event.mousePos)) { - m_state = UI::ButtonDown; - } else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) { - m_state = UI::ButtonUp; + m_state = ButtonDown; + } else if(event.type == EV_MOUSE_LUP && m_state == ButtonDown) { + m_state = ButtonUp; if(getRect().contains(event.mousePos)) { g_dispatcher.addTask(boost::bind(&Scriptable::callLuaTableField, shared_from_this(), "onClick")); } diff --git a/src/framework/ui/uibutton.h b/src/framework/ui/uibutton.h index 19298191..f2081eeb 100644 --- a/src/framework/ui/uibutton.h +++ b/src/framework/ui/uibutton.h @@ -35,22 +35,29 @@ typedef boost::shared_ptr UIButtonPtr; class UIButton : public UIElement { public: + enum ButtonState + { + ButtonUp, + ButtonDown, + ButtonMouseOver + }; + UIButton() : UIElement(UI::Button), - m_state(UI::ButtonUp) { } + m_state(ButtonUp) { } void onInputEvent(const InputEvent& event); void setText(const std::string& text) { m_text = text; } std::string getText() const { return m_text; } - UI::EButtonState getState() { return m_state; } + ButtonState getState() { return m_state; } virtual const char *getScriptableName() const { return "UIButton"; } private: std::string m_text; - UI::EButtonState m_state; + ButtonState m_state; }; #endif // UIBUTTON_H diff --git a/src/framework/ui/uibuttonskin.cpp b/src/framework/ui/uibuttonskin.cpp index aef76f54..3dadf50a 100644 --- a/src/framework/ui/uibuttonskin.cpp +++ b/src/framework/ui/uibuttonskin.cpp @@ -50,10 +50,10 @@ void UIButtonSkin::draw(UIElement *element) Rect textRect = button->getRect(); - if(button->getState() == UI::ButtonDown && m_buttonDownImage) { + if(button->getState() == UIButton::ButtonDown && m_buttonDownImage) { m_buttonDownImage->draw(element->getRect()); textRect.translate(m_buttonDownTranslate); - } else if(button->getState() == UI::ButtonMouseOver && m_buttonHoverImage) { + } else if(button->getState() == UIButton::ButtonMouseOver && m_buttonHoverImage) { m_buttonHoverImage->draw(element->getRect()); } else { UIElementSkin::draw(element); diff --git a/src/framework/ui/uicheckbox.cpp b/src/framework/ui/uicheckbox.cpp index cb9ebada..b55ecaed 100644 --- a/src/framework/ui/uicheckbox.cpp +++ b/src/framework/ui/uicheckbox.cpp @@ -25,7 +25,7 @@ #include #include -UICheckBox::UICheckBox(UI::EElementType type): UIElement(type) +UICheckBox::UICheckBox(UI::ElementType type): UIElement(type) { } diff --git a/src/framework/ui/uicheckbox.h b/src/framework/ui/uicheckbox.h index 59972ca5..d5def390 100644 --- a/src/framework/ui/uicheckbox.h +++ b/src/framework/ui/uicheckbox.h @@ -31,7 +31,7 @@ class UICheckBox : public UIElement { public: - UICheckBox(UI::EElementType type = UI::Element); + UICheckBox(UI::ElementType type = UI::Element); virtual const char *getScriptableName() const { return "UICheckBox"; } }; diff --git a/src/framework/ui/uiconstants.h b/src/framework/ui/uiconstants.h index 7c596d96..54bfa826 100644 --- a/src/framework/ui/uiconstants.h +++ b/src/framework/ui/uiconstants.h @@ -26,33 +26,7 @@ #define UICONSTANTS_H namespace UI { - enum EButtonState - { - ButtonUp, - ButtonDown, - ButtonMouseOver - }; - - enum EButtonEvent - { - ButtonPressUp, - ButtonPressDown, - ButtonEnterMouseOver, - ButtonLeaveMouseOver - }; - - enum EMessageBoxFlags - { - MessageBoxOk = 1 << 0, - MessageBoxCancel = 1 << 1, - MessageBoxYes = 1 << 2, - MessageBoxNo = 1 << 3, - MessageBoxOkCancel = MessageBoxOk | MessageBoxCancel, - MessageBoxYesNo = MessageBoxYes | MessageBoxNo - }; - - enum EElementType - { + enum ElementType { Element = 0, Container, Panel, @@ -63,6 +37,16 @@ namespace UI { CheckBox, LineDecoration }; + + enum AnchorPoint { + AnchorLeft = 0, + AnchorHorizontalCenter, + AnchorRight, + AnchorTop, + AnchorVerticalCenter, + AnchorBottom, + AnchorNone + }; } #endif // UICONSTANTS_H diff --git a/src/framework/ui/uicontainer.cpp b/src/framework/ui/uicontainer.cpp index 184aa403..304e3b23 100644 --- a/src/framework/ui/uicontainer.cpp +++ b/src/framework/ui/uicontainer.cpp @@ -25,9 +25,10 @@ #include #include #include +#include #include -void UIContainer::internalOnDestroy() +void UIContainer::destroy() { //logTraceDebug(getId()); @@ -37,11 +38,11 @@ void UIContainer::internalOnDestroy() // destroy children while(m_children.size() > 0) { - UIElementPtr element = m_children.back(); //hold reference - element->internalOnDestroy(); + UIElementPtr element = m_children.front(); //hold reference + element->destroy(); } - UIElement::internalOnDestroy(); + UIElement::destroy(); } UIContainerPtr& UIContainer::getRoot() @@ -50,6 +51,7 @@ UIContainerPtr& UIContainer::getRoot() if(!rootContainer) { rootContainer = UIContainerPtr(new UIContainer); rootContainer->setId("root"); + rootContainer->setLayout(UILayoutPtr(new UIAnchorLayout)); } return rootContainer; } @@ -87,9 +89,15 @@ bool UIContainer::hasChild(const UIElementPtr& child) UIElementPtr UIContainer::getChildById(const std::string& id) { - if(getId() == id) + if(getId() == id || id == "self") return asUIElement(); + if(id == "parent") + return getParent(); + + if(id == "root") + return getRoot(); + foreach(const UIElementPtr& child, m_children) { if(child->getId() == id) return child; @@ -111,9 +119,15 @@ UIElementPtr UIContainer::getChildByPos(const Point& pos) UIElementPtr UIContainer::recursiveGetChildById(const std::string& id) { - if(getId() == id) + if(getId() == id || id == "self") return asUIElement(); + if(id == "parent") + return getParent(); + + if(id == "root") + return getRoot(); + foreach(const UIElementPtr& element, m_children) { if(element->getId() == id) return element; diff --git a/src/framework/ui/uicontainer.h b/src/framework/ui/uicontainer.h index 441df42f..781bc55e 100644 --- a/src/framework/ui/uicontainer.h +++ b/src/framework/ui/uicontainer.h @@ -31,10 +31,11 @@ class UIContainer : public UIElement { public: - UIContainer(UI::EElementType type = UI::Container) : + UIContainer(UI::ElementType type = UI::Container) : UIElement(type) { } virtual ~UIContainer() { } + virtual void destroy(); virtual void onLoad(); virtual void render(); virtual void onInputEvent(const InputEvent& event); @@ -70,7 +71,7 @@ public: /// Get focused element UIElementPtr getFocusedElement() const { return m_focusedElement; } - virtual UI::EElementType getElementType() const { return UI::Container; } + virtual UI::ElementType getElementType() const { return UI::Container; } UIContainerPtr asUIContainer() { return boost::static_pointer_cast(shared_from_this()); } virtual const char *getScriptableName() const { return "UIContainer"; } @@ -78,9 +79,6 @@ public: /// Get root container (the container that contains everything) static UIContainerPtr& getRoot(); -protected: - virtual void internalOnDestroy(); - private: std::list m_children; std::list m_lockedElements; diff --git a/src/framework/ui/uielement.cpp b/src/framework/ui/uielement.cpp index 7a2c01e3..feefad5a 100644 --- a/src/framework/ui/uielement.cpp +++ b/src/framework/ui/uielement.cpp @@ -30,11 +30,15 @@ #include #include -UIElement::UIElement(UI::EElementType type) : - UILayout(), +UIElement::UIElement(UI::ElementType type) : + Scriptable(), m_type(type), m_visible(true), - m_enabled(true) + m_enabled(true), + m_marginLeft(0), + m_marginRight(0), + m_marginTop(0), + m_marginBottom(0) { } @@ -44,13 +48,13 @@ UIElement::~UIElement() //logTraceDebug(getId()); } -void UIElement::destroy() +void UIElement::destroyLater() { //logTraceDebug(getId()); - g_dispatcher.addTask(boost::bind(&UIElement::internalOnDestroy, asUIElement())); + g_dispatcher.addTask(boost::bind(&UIElement::destroy, asUIElement())); } -void UIElement::internalOnDestroy() +void UIElement::destroy() { //logTraceDebug(getId()); @@ -58,17 +62,16 @@ void UIElement::internalOnDestroy() callLuaTableField("onDestroy"); // remove from parent - if(getParent()) { + if(getParent()) getParent()->removeChild(me); - } // free script stuff releaseLuaTableRef(); - g_dispatcher.addTask(boost::bind(&UIElement::internalDestroyCheck, asUIElement())); + g_dispatcher.addTask(boost::bind(&UIElement::destroyCheck, me)); } -void UIElement::internalDestroyCheck() +void UIElement::destroyCheck() { //logTraceDebug(getId()); @@ -79,6 +82,29 @@ void UIElement::internalDestroyCheck() } } +void UIElement::setSize(const Size& size) +{ + Rect rect = getRect(); + if(rect.isValid()) + rect.setSize(size); + else + rect = Rect(0, 0, size); + setRect(rect); + getLayout()->recalculateElementLayout(asUIElement()); +} + +void UIElement::setRect(const Rect& rect) +{ + if(rect != m_rect) { + m_rect = rect; + + // rect updated, recalculate children layout + getLayout()->recalculateChildrenLayout(asUIElement()); + + onRectUpdate(); + } +} + void UIElement::setSkin(const UIElementSkinPtr& skin) { m_skin = skin; @@ -100,11 +126,16 @@ void UIElement::render() UIElementPtr UIElement::backwardsGetElementById(const std::string& id) { - if(getId() == id) + if(getId() == id || id == "self") return asUIElement(); - UIElementPtr element; + if(id == "parent") + return getParent(); + + if(id == "root") + return UIContainer::getRoot(); + UIElementPtr element; if(asUIContainer()) { element = asUIContainer()->recursiveGetChildById(id); if(element) @@ -169,3 +200,12 @@ void UIElement::setFocused(bool focused) } } } + +UILayoutPtr UIElement::getLayout() const +{ + if(m_layout) + return m_layout; + else if(getParent()) + return getParent()->getLayout(); + return UILayoutPtr(); +} diff --git a/src/framework/ui/uielement.h b/src/framework/ui/uielement.h index 2b393324..514e43ec 100644 --- a/src/framework/ui/uielement.h +++ b/src/framework/ui/uielement.h @@ -27,9 +27,10 @@ #include #include +#include