rework ui layouts, now it is more flexible and modular
This commit is contained in:
parent
6d871b305f
commit
51fe97644d
|
@ -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
|
||||
|
|
|
@ -4,8 +4,7 @@ function onEnterMenuState()
|
|||
end
|
||||
|
||||
function onLeaveMenuState()
|
||||
mainMenu:destroy()
|
||||
mainMenu = nil
|
||||
|
||||
end
|
||||
|
||||
function onApplicationClose()
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<UIElement>(g_lua.popClassInstance()))
|
||||
element->destroy();
|
||||
element->destroyLater();
|
||||
g_dispatcher.addTask(boost::bind(&LuaScript::collectGarbage, &g_lua));
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <prerequisites.h>
|
||||
#include <ui/uianchorlayout.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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 <prerequisites.h>
|
||||
#include <ui/uiconstants.h>
|
||||
#include <ui/uilayout.h>
|
||||
#include <ui/uielement.h>
|
||||
|
||||
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<Anchor> m_anchors;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<UIAnchorLayout> UIAnchorLayoutPtr;
|
||||
|
||||
#endif // UIANCHORLAYOUT_H
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -35,22 +35,29 @@ typedef boost::shared_ptr<UIButton> 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <prerequisites.h>
|
||||
#include <ui/uicheckbox.h>
|
||||
|
||||
UICheckBox::UICheckBox(UI::EElementType type): UIElement(type)
|
||||
UICheckBox::UICheckBox(UI::ElementType type): UIElement(type)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -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"; }
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
#include <prerequisites.h>
|
||||
#include <core/resources.h>
|
||||
#include <ui/uicontainer.h>
|
||||
#include <ui/uianchorlayout.h>
|
||||
#include <core/dispatcher.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -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<UIContainer>(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<UIElementPtr> m_children;
|
||||
std::list<UIElementPtr> m_lockedElements;
|
||||
|
|
|
@ -30,11 +30,15 @@
|
|||
#include <ui/uielementskin.h>
|
||||
#include <ui/uicontainer.h>
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -27,9 +27,10 @@
|
|||
|
||||
#include <prerequisites.h>
|
||||
#include <core/input.h>
|
||||
#include <script/scriptable.h>
|
||||
#include <ui/uiconstants.h>
|
||||
#include <ui/uilayout.h>
|
||||
#include <ui/uielementskin.h>
|
||||
#include <ui/uilayout.h>
|
||||
|
||||
class UIElementSkin;
|
||||
|
||||
|
@ -41,18 +42,15 @@ class UIElement;
|
|||
typedef boost::shared_ptr<UIElement> UIElementPtr;
|
||||
typedef boost::weak_ptr<UIElement> UIElementWeakPtr;
|
||||
|
||||
typedef boost::function<void(UIElementPtr)> UIElementCallback;
|
||||
|
||||
class UIElement : public UILayout
|
||||
class UIElement : public Scriptable
|
||||
{
|
||||
public:
|
||||
UIElement(UI::EElementType type = UI::Element);
|
||||
UIElement(UI::ElementType type = UI::Element);
|
||||
virtual ~UIElement();
|
||||
|
||||
/// Destroy this element by removing it from its parent
|
||||
void destroy();
|
||||
virtual void internalOnDestroy();
|
||||
virtual void internalDestroyCheck();
|
||||
void destroyLater();
|
||||
virtual void destroy();
|
||||
virtual void destroyCheck();
|
||||
|
||||
/// Draw element
|
||||
virtual void render();
|
||||
|
@ -61,11 +59,15 @@ public:
|
|||
virtual void onLoad();
|
||||
virtual void onInputEvent(const InputEvent& event) { }
|
||||
virtual void onFocusChange() { }
|
||||
virtual void onRectUpdate() { }
|
||||
|
||||
UIElementPtr backwardsGetElementById(const std::string& id);
|
||||
|
||||
void moveTo(Point pos);
|
||||
|
||||
void setLayout(const UILayoutPtr& layout) { m_layout = layout; }
|
||||
UILayoutPtr getLayout() const;
|
||||
|
||||
void setSkin(const UIElementSkinPtr& skin);
|
||||
UIElementSkinPtr getSkin() const { return m_skin; }
|
||||
|
||||
|
@ -85,19 +87,48 @@ public:
|
|||
bool isVisible() const { return m_visible; }
|
||||
|
||||
virtual bool isFocusable() const { return false; }
|
||||
UI::EElementType getElementType() const { return m_type; }
|
||||
UI::ElementType getElementType() const { return m_type; }
|
||||
|
||||
UIElementPtr asUIElement() { return boost::static_pointer_cast<UIElement>(shared_from_this()); }
|
||||
virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); }
|
||||
virtual const char *getScriptableName() const { return "UIElement"; }
|
||||
|
||||
void setSize(const Size& size);
|
||||
Size getSize() { return m_rect.size(); }
|
||||
|
||||
/// Set the layout rect, always absolute position
|
||||
void setRect(const Rect& rect);
|
||||
/// Get layout size, it always return the absolute position
|
||||
Rect getRect() const { return m_rect; }
|
||||
|
||||
// margins
|
||||
void setMargin(int top, int left, int bottom, int right) { m_marginLeft = left; m_marginRight = right; m_marginTop = top; m_marginBottom = bottom; getLayout()->recalculateElementLayout(asUIElement()); }
|
||||
void setMargin(int horizontal, int vertical) { m_marginLeft = m_marginRight = horizontal; m_marginTop = m_marginBottom = vertical; getLayout()->recalculateElementLayout(asUIElement()); }
|
||||
void setMargin(int margin) { m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = margin; getLayout()->recalculateElementLayout(asUIElement()); }
|
||||
void setMarginLeft(int margin) { m_marginLeft = margin; getLayout()->recalculateElementLayout(asUIElement()); }
|
||||
void setMarginRight(int margin) { m_marginRight = margin; getLayout()->recalculateElementLayout(asUIElement()); }
|
||||
void setMarginTop(int margin) { m_marginTop = margin; getLayout()->recalculateElementLayout(asUIElement()); }
|
||||
void setMarginBottom(int margin) { m_marginBottom = margin; getLayout()->recalculateElementLayout(asUIElement()); }
|
||||
|
||||
int getMarginLeft() const { return m_marginLeft; }
|
||||
int getMarginRight() const { return m_marginRight; }
|
||||
int getMarginTop() const { return m_marginTop; }
|
||||
int getMarginBottom() const { return m_marginBottom; }
|
||||
|
||||
private:
|
||||
UI::EElementType m_type;
|
||||
UI::ElementType m_type;
|
||||
UIContainerWeakPtr m_parent;
|
||||
UIElementSkinPtr m_skin;
|
||||
UILayoutPtr m_layout;
|
||||
std::string m_id;
|
||||
bool m_visible;
|
||||
bool m_enabled;
|
||||
|
||||
Rect m_rect;
|
||||
int m_marginLeft;
|
||||
int m_marginRight;
|
||||
int m_marginTop;
|
||||
int m_marginBottom;
|
||||
};
|
||||
|
||||
#endif // UIELEMENT_H
|
||||
|
|
|
@ -34,7 +34,7 @@ class UIElement;
|
|||
class UIElementSkin
|
||||
{
|
||||
public:
|
||||
UIElementSkin(const std::string& name, UI::EElementType elementType) :
|
||||
UIElementSkin(const std::string& name, UI::ElementType elementType) :
|
||||
m_name(name),
|
||||
m_elementType(elementType) { }
|
||||
UIElementSkin() : m_elementType(UI::Element) { }
|
||||
|
@ -49,7 +49,7 @@ public:
|
|||
|
||||
const std::string& getName() const { return m_name; }
|
||||
const Size& getDefaultSize() const { return m_defaultSize; }
|
||||
UI::EElementType getElementType() const { return m_elementType; }
|
||||
UI::ElementType getElementType() const { return m_elementType; }
|
||||
ImagePtr getDefaultImage() const { return m_defaultImage; }
|
||||
|
||||
protected:
|
||||
|
@ -57,7 +57,7 @@ protected:
|
|||
|
||||
private:
|
||||
std::string m_name;
|
||||
UI::EElementType m_elementType;
|
||||
UI::ElementType m_elementType;
|
||||
Size m_defaultSize;
|
||||
ImagePtr m_defaultImage;
|
||||
};
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
/* 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 <prerequisites.h>
|
||||
#include <ui/uielement.h>
|
||||
#include <ui/uilayout.h>
|
||||
|
||||
int AnchorLine::getPos() const
|
||||
{
|
||||
UILayoutPtr element = m_relativeElement.lock();
|
||||
if(element) {
|
||||
switch(m_anchorType) {
|
||||
case ANCHOR_LEFT:
|
||||
return element->getRect().left();
|
||||
case ANCHOR_RIGHT:
|
||||
return element->getRect().right();
|
||||
case ANCHOR_TOP:
|
||||
return element->getRect().top();
|
||||
case ANCHOR_BOTTOM:
|
||||
return element->getRect().bottom();
|
||||
case ANCHOR_HORIZONTAL_CENTER:
|
||||
return element->getRect().horizontalCenter();
|
||||
case ANCHOR_VERTICAL_CENTER:
|
||||
return element->getRect().verticalCenter();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
logError("ERROR: anchor line of an element has expired, your UI is missconfigured");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UILayout::setSize(const Size& size)
|
||||
{
|
||||
if(m_rect.isValid())
|
||||
m_rect.setSize(size);
|
||||
else
|
||||
m_rect = Rect(0, 0, size);
|
||||
|
||||
// rect updated, recalculate itself and anchored elements positions
|
||||
recalculateLayout();
|
||||
}
|
||||
|
||||
void UILayout::setRect(const Rect& rect)
|
||||
{
|
||||
m_rect = rect;
|
||||
|
||||
// rect updated, recalculate itself and anchored elements positions
|
||||
recalculateAnchoredLayout();
|
||||
}
|
||||
|
||||
bool UILayout::addAnchor(EAnchorType type, const AnchorLine& anchorLine)
|
||||
{
|
||||
// we can never anchor with itself
|
||||
if(anchorLine.getRelativeElement() == asUILayout()) {
|
||||
logError("ERROR: anchoring with itself is not possible");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if this layout is already anchored with the relative element
|
||||
// this only happens in missconfigurations
|
||||
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
|
||||
if((*it).lock() == anchorLine.getRelativeElement()) {
|
||||
logError("ERROR: anchoring elements with each other is not possible");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// setup the anchor
|
||||
m_anchors[type] = anchorLine;
|
||||
anchorLine.getRelativeElement()->addAnchoredElement(asUILayout());
|
||||
|
||||
// recalculate itself and anchored elements
|
||||
recalculateLayout();
|
||||
return true;
|
||||
}
|
||||
|
||||
void UILayout::addAnchoredElement(UILayoutPtr anchoredElement)
|
||||
{
|
||||
// check if is already anchored
|
||||
bool found = false;
|
||||
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
|
||||
if((*it).lock() == anchoredElement) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if not, anchor it
|
||||
if(!found)
|
||||
m_anchoredElements.push_back(anchoredElement);
|
||||
}
|
||||
|
||||
void UILayout::recalculateLayout()
|
||||
{
|
||||
// recalculate horizontal position
|
||||
if(m_anchors[ANCHOR_HORIZONTAL_CENTER].isValid()) {
|
||||
m_rect.moveHorizontalCenter(m_anchors[ANCHOR_HORIZONTAL_CENTER].getPos() + m_marginLeft - m_marginRight);
|
||||
} else {
|
||||
if(m_anchors[ANCHOR_LEFT].isValid() && m_anchors[ANCHOR_RIGHT].isValid()) {
|
||||
m_rect.setLeft(m_anchors[ANCHOR_LEFT].getPos() + m_marginLeft);
|
||||
m_rect.setRight(m_anchors[ANCHOR_RIGHT].getPos() - m_marginRight);
|
||||
} else if(m_anchors[ANCHOR_LEFT].isValid()) {
|
||||
m_rect.moveLeft(m_anchors[ANCHOR_LEFT].getPos() + m_marginLeft);
|
||||
} else if(m_anchors[ANCHOR_RIGHT].isValid()) {
|
||||
m_rect.moveRight(m_anchors[ANCHOR_RIGHT].getPos() - m_marginRight);
|
||||
}
|
||||
}
|
||||
|
||||
// recalculate vertical position
|
||||
if(m_anchors[ANCHOR_VERTICAL_CENTER].isValid()) {
|
||||
m_rect.moveVerticalCenter(m_anchors[ANCHOR_VERTICAL_CENTER].getPos() + m_marginTop - m_marginBottom);
|
||||
} else {
|
||||
if(m_anchors[ANCHOR_TOP].isValid() && m_anchors[ANCHOR_BOTTOM].isValid()) {
|
||||
m_rect.setTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
|
||||
m_rect.setBottom(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom);
|
||||
} else if(m_anchors[ANCHOR_TOP].isValid()) {
|
||||
m_rect.moveTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
|
||||
} else if(m_anchors[ANCHOR_BOTTOM].isValid()) {
|
||||
m_rect.moveBottom(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom);
|
||||
}
|
||||
}
|
||||
|
||||
recalculateAnchoredLayout();
|
||||
|
||||
// fire layout update event
|
||||
onLayoutRectChange(m_rect);
|
||||
}
|
||||
|
||||
void UILayout::recalculateAnchoredLayout()
|
||||
{
|
||||
// recalculate anchored elements positions
|
||||
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
|
||||
UILayoutPtr element = (*it).lock();
|
||||
if(element)
|
||||
element->recalculateLayout();
|
||||
}
|
||||
}
|
||||
|
|
@ -26,109 +26,20 @@
|
|||
#define UILAYOUT_H
|
||||
|
||||
#include <prerequisites.h>
|
||||
#include <ui/uiconstants.h>
|
||||
#include <script/scriptable.h>
|
||||
|
||||
enum EAnchorType {
|
||||
ANCHOR_LEFT = 0,
|
||||
ANCHOR_RIGHT,
|
||||
ANCHOR_TOP,
|
||||
ANCHOR_BOTTOM,
|
||||
ANCHOR_HORIZONTAL_CENTER,
|
||||
ANCHOR_VERTICAL_CENTER,
|
||||
ANCHOR_NONE
|
||||
};
|
||||
class UIElement;
|
||||
typedef boost::shared_ptr<UIElement> UIElementPtr;
|
||||
|
||||
class UILayout;
|
||||
typedef boost::shared_ptr<UILayout> UILayoutPtr;
|
||||
typedef boost::weak_ptr<UILayout> UILayoutWeakPtr;
|
||||
|
||||
class AnchorLine
|
||||
class UILayout : public boost::enable_shared_from_this<UILayout>
|
||||
{
|
||||
public:
|
||||
AnchorLine() : m_anchorType(ANCHOR_NONE) { }
|
||||
AnchorLine(const AnchorLine& other) :
|
||||
m_relativeElement(other.m_relativeElement), m_anchorType(other.m_anchorType) { }
|
||||
AnchorLine(UILayoutPtr relativeElement, EAnchorType anchorType) :
|
||||
m_relativeElement(relativeElement), m_anchorType(anchorType) { }
|
||||
bool isValid() const { return (m_anchorType != ANCHOR_NONE && !m_relativeElement.expired()); }
|
||||
UILayout() { }
|
||||
|
||||
/// Get the position relative to this anchor line
|
||||
int getPos() const;
|
||||
EAnchorType getAnchorType() const { return m_anchorType; }
|
||||
UILayoutPtr getRelativeElement() const { return m_relativeElement.lock(); }
|
||||
|
||||
private:
|
||||
UILayoutWeakPtr m_relativeElement;
|
||||
EAnchorType m_anchorType;
|
||||
};
|
||||
|
||||
class UILayout : public Scriptable
|
||||
{
|
||||
public:
|
||||
UILayout() : Scriptable(),
|
||||
m_marginLeft(0),
|
||||
m_marginRight(0),
|
||||
m_marginTop(0),
|
||||
m_marginBottom(0) { }
|
||||
virtual ~UILayout() { }
|
||||
|
||||
void setSize(const Size& size);
|
||||
Size getSize() { return m_rect.size(); }
|
||||
|
||||
/// Set the layout rect, always absolute position
|
||||
void setRect(const Rect& rect);
|
||||
/// Get layout size, it always return the absolute position
|
||||
Rect getRect() const { return m_rect; }
|
||||
|
||||
// anchors add methods
|
||||
bool addAnchor(EAnchorType type, const AnchorLine& anchorLine);
|
||||
void anchorLeft(const AnchorLine& anchorLine) { addAnchor(ANCHOR_LEFT, anchorLine); }
|
||||
void anchorRight(const AnchorLine& anchorLine) { addAnchor(ANCHOR_RIGHT, anchorLine); }
|
||||
void anchorTop(const AnchorLine& anchorLine) { addAnchor(ANCHOR_TOP, anchorLine); }
|
||||
void anchorBottom(const AnchorLine& anchorLine) { addAnchor(ANCHOR_BOTTOM, anchorLine); }
|
||||
void anchorHorizontalCenter(const AnchorLine& anchorLine) { addAnchor(ANCHOR_HORIZONTAL_CENTER, anchorLine); }
|
||||
void anchorVerticalCenter(const AnchorLine& anchorLine) { addAnchor(ANCHOR_VERTICAL_CENTER, anchorLine); }
|
||||
|
||||
// anchor lines
|
||||
AnchorLine left() { return AnchorLine(asUILayout(), ANCHOR_LEFT); }
|
||||
AnchorLine right() { return AnchorLine(asUILayout(), ANCHOR_RIGHT); }
|
||||
AnchorLine top() { return AnchorLine(asUILayout(), ANCHOR_TOP); }
|
||||
AnchorLine bottom() { return AnchorLine(asUILayout(), ANCHOR_BOTTOM); }
|
||||
AnchorLine horizontalCenter() { return AnchorLine(asUILayout(), ANCHOR_HORIZONTAL_CENTER); }
|
||||
AnchorLine verticalCenter() { return AnchorLine(asUILayout(), ANCHOR_VERTICAL_CENTER); }
|
||||
|
||||
// margins
|
||||
void setMargin(int top, int left, int bottom, int right) { m_marginLeft = left; m_marginRight = right; m_marginTop = top; m_marginBottom = bottom; recalculateLayout(); }
|
||||
void setMargin(int horizontal, int vertical) { m_marginLeft = m_marginRight = horizontal; m_marginTop = m_marginBottom = vertical; recalculateLayout(); }
|
||||
void setMargin(int margin) { m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = margin; recalculateLayout(); }
|
||||
void setMarginLeft(int margin) { m_marginLeft = margin; recalculateLayout(); }
|
||||
void setMarginRight(int margin) { m_marginRight = margin; recalculateLayout(); }
|
||||
void setMarginTop(int margin) { m_marginTop = margin; recalculateLayout(); }
|
||||
void setMarginBottom(int margin) { m_marginBottom = margin; recalculateLayout(); }
|
||||
|
||||
UILayoutPtr asUILayout() { return boost::static_pointer_cast<UILayout>(shared_from_this()); }
|
||||
|
||||
virtual const char *getScriptableName() const { return "UILayout"; }
|
||||
|
||||
protected:
|
||||
virtual void onLayoutRectChange(const Rect& newRect) { }
|
||||
|
||||
private:
|
||||
/// Recalculate itself and anchored elements positions
|
||||
void recalculateLayout();
|
||||
/// Recalculate anchored elements positions
|
||||
void recalculateAnchoredLayout();
|
||||
void addAnchoredElement(UILayoutPtr anchoredElement);
|
||||
|
||||
AnchorLine m_anchors[6];
|
||||
|
||||
Rect m_rect;
|
||||
int m_marginLeft;
|
||||
int m_marginRight;
|
||||
int m_marginTop;
|
||||
int m_marginBottom;
|
||||
std::list<UILayoutWeakPtr> m_anchoredElements;
|
||||
virtual void recalculateElementLayout(const UIElementPtr& element) = 0;
|
||||
virtual void recalculateChildrenLayout(const UIElementPtr& parent) = 0;
|
||||
};
|
||||
|
||||
#endif // UILAYOUT_H
|
|
@ -28,6 +28,7 @@
|
|||
#include <ui/uiloader.h>
|
||||
#include <script/luascript.h>
|
||||
#include <script/luafunctions.h>
|
||||
#include "uianchorlayout.h"
|
||||
|
||||
UIElementPtr UILoader::createElementFromId(const std::string& id)
|
||||
{
|
||||
|
@ -206,22 +207,22 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
|
|||
}
|
||||
|
||||
if(node.FindValue("anchors.left"))
|
||||
loadElementAnchor(element, ANCHOR_LEFT, node["anchors.left"]);
|
||||
loadElementAnchor(element, UI::AnchorLeft, node["anchors.left"]);
|
||||
|
||||
if(node.FindValue("anchors.right"))
|
||||
loadElementAnchor(element, ANCHOR_RIGHT, node["anchors.right"]);
|
||||
loadElementAnchor(element, UI::AnchorRight, node["anchors.right"]);
|
||||
|
||||
if(node.FindValue("anchors.top"))
|
||||
loadElementAnchor(element, ANCHOR_TOP, node["anchors.top"]);
|
||||
loadElementAnchor(element, UI::AnchorTop, node["anchors.top"]);
|
||||
|
||||
if(node.FindValue("anchors.bottom"))
|
||||
loadElementAnchor(element, ANCHOR_BOTTOM, node["anchors.bottom"]);
|
||||
loadElementAnchor(element, UI::AnchorBottom, node["anchors.bottom"]);
|
||||
|
||||
if(node.FindValue("anchors.horizontalCenter"))
|
||||
loadElementAnchor(element, ANCHOR_HORIZONTAL_CENTER, node["anchors.horizontalCenter"]);
|
||||
loadElementAnchor(element, UI::AnchorHorizontalCenter, node["anchors.horizontalCenter"]);
|
||||
|
||||
if(node.FindValue("anchors.verticalCenter"))
|
||||
loadElementAnchor(element, ANCHOR_VERTICAL_CENTER, node["anchors.verticalCenter"]);
|
||||
loadElementAnchor(element, UI::AnchorVerticalCenter, node["anchors.verticalCenter"]);
|
||||
|
||||
// load events
|
||||
if(node.FindValue("onLoad")) {
|
||||
|
@ -261,8 +262,14 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
|
|||
}
|
||||
}
|
||||
|
||||
void UILoader::loadElementAnchor(const UIElementPtr& element, EAnchorType type, const YAML::Node& node)
|
||||
void UILoader::loadElementAnchor(const UIElementPtr& anchoredElement, UI::AnchorPoint anchoredEdge, const YAML::Node& node)
|
||||
{
|
||||
UIAnchorLayoutPtr layout = boost::dynamic_pointer_cast<UIAnchorLayout>(anchoredElement->getLayout());
|
||||
if(!layout) {
|
||||
logError(YAML::Exception(node.GetMark(), "could not add anchor, because this element does not participate of an anchor layout").what());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string anchorDescription;
|
||||
node >> anchorDescription;
|
||||
|
||||
|
@ -273,44 +280,16 @@ void UILoader::loadElementAnchor(const UIElementPtr& element, EAnchorType type,
|
|||
return;
|
||||
}
|
||||
|
||||
std::string relativeElementId = split[0];
|
||||
std::string relativeAnchorTypeId = split[1];
|
||||
EAnchorType relativeAnchorType;
|
||||
std::string anchorLineElementId = split[0];
|
||||
UI::AnchorPoint anchorLineEdge = UIAnchorLayout::parseAnchorPoint(split[1]);
|
||||
|
||||
if(relativeAnchorTypeId == "left")
|
||||
relativeAnchorType = ANCHOR_LEFT;
|
||||
else if(relativeAnchorTypeId == "right")
|
||||
relativeAnchorType = ANCHOR_RIGHT;
|
||||
else if(relativeAnchorTypeId == "top")
|
||||
relativeAnchorType = ANCHOR_TOP;
|
||||
else if(relativeAnchorTypeId == "bottom")
|
||||
relativeAnchorType = ANCHOR_BOTTOM;
|
||||
else if(relativeAnchorTypeId == "horizontalCenter")
|
||||
relativeAnchorType = ANCHOR_HORIZONTAL_CENTER;
|
||||
else if(relativeAnchorTypeId == "verticalCenter")
|
||||
relativeAnchorType = ANCHOR_VERTICAL_CENTER;
|
||||
else {
|
||||
if(anchorLineEdge == UI::AnchorNone) {
|
||||
logError(YAML::Exception(node.GetMark(), "invalid anchor type").what());
|
||||
return;
|
||||
}
|
||||
|
||||
UILayoutPtr relativeElement;
|
||||
if(relativeElementId == "parent" && element->getParent()) {
|
||||
relativeElement = element->getParent()->asUILayout();
|
||||
} else if(relativeElementId == "root") {
|
||||
relativeElement = UIContainer::getRoot();
|
||||
} else {
|
||||
UIElementPtr tmp = element->backwardsGetElementById(relativeElementId);
|
||||
if(tmp)
|
||||
relativeElement = tmp->asUILayout();
|
||||
}
|
||||
|
||||
if(relativeElement) {
|
||||
if(!element->addAnchor(type, AnchorLine(relativeElement, relativeAnchorType)))
|
||||
if(!layout->addAnchor(anchoredElement, anchoredEdge, AnchorLine(anchorLineElementId, anchorLineEdge)))
|
||||
logError(YAML::Exception(node.GetMark(), "anchoring failed").what());
|
||||
} else {
|
||||
logError(YAML::Exception(node.GetMark(), "anchoring failed, does the relative element really exists?").what());
|
||||
}
|
||||
}
|
||||
|
||||
void UILoader::loadButton(const UIButtonPtr& button, const YAML::Node& node)
|
||||
|
|
|
@ -50,7 +50,7 @@ private:
|
|||
static void loadElement(const UIElementPtr& element, const YAML::Node& node);
|
||||
|
||||
/// Load anchor from a YAML node
|
||||
static void loadElementAnchor(const UIElementPtr& element, EAnchorType type, const YAML::Node& node);
|
||||
static void loadElementAnchor(const UIElementPtr& anchoredElement, UI::AnchorPoint anchoredEdge, const YAML::Node& node);
|
||||
|
||||
// specific elements loading
|
||||
static void loadButton(const UIButtonPtr& button, const YAML::Node& node);
|
||||
|
|
|
@ -136,7 +136,7 @@ void UISkins::terminate()
|
|||
}
|
||||
|
||||
|
||||
UIElementSkinPtr UISkins::getElementSkin(UI::EElementType elementType, const std::string& name)
|
||||
UIElementSkinPtr UISkins::getElementSkin(UI::ElementType elementType, const std::string& name)
|
||||
{
|
||||
for(auto it = m_elementSkins.begin(); it != m_elementSkins.end(); ++it) {
|
||||
const UIElementSkinPtr& skin = (*it);
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
void load(const std::string& skinsFile);
|
||||
void terminate();
|
||||
|
||||
UIElementSkinPtr getElementSkin(UI::EElementType elementType, const std::string& name = "default");
|
||||
UIElementSkinPtr getElementSkin(UI::ElementType elementType, const std::string& name = "default");
|
||||
TexturePtr getDefaultTexture() { return m_defaultTexture; }
|
||||
|
||||
private:
|
||||
|
|
|
@ -60,10 +60,10 @@ void UITextEdit::onInputEvent(const InputEvent& event)
|
|||
}
|
||||
}
|
||||
|
||||
void UITextEdit::onLayoutRectChange(const Rect& rect)
|
||||
void UITextEdit::onRectUpdate()
|
||||
{
|
||||
UITextEditSkin *skin = static_cast<UITextEditSkin*>(getSkin().get());
|
||||
Rect textRect = rect;
|
||||
Rect textRect = getRect();
|
||||
int margin = skin->getTextMargin();
|
||||
textRect.setLeft(textRect.left()+margin);
|
||||
textRect.setRight(textRect.right()-margin);
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
UITextEdit();
|
||||
|
||||
void onInputEvent(const InputEvent& event);
|
||||
void onLayoutRectChange(const Rect& rect);
|
||||
void onRectUpdate();
|
||||
void onFocusChange();
|
||||
|
||||
void setText(const std::string& text);
|
||||
|
|
|
@ -38,7 +38,7 @@ template <class T>
|
|||
class TSize
|
||||
{
|
||||
public:
|
||||
inline TSize() : wd(0), ht(0) {};
|
||||
inline TSize() : wd(-1), ht(-1) {};
|
||||
inline TSize(T width, T height) : wd(width), ht(height) { };
|
||||
inline TSize(const TSize<T>& other) : wd(other.wd), ht(other.ht) { };
|
||||
|
||||
|
|
Loading…
Reference in New Issue