mirror of
https://github.com/edubart/otclient.git
synced 2025-10-19 05:53:26 +02:00
ui anchoring
This commit is contained in:
@@ -30,11 +30,6 @@ void UIContainer::addChild(UIElementPtr child)
|
||||
{
|
||||
m_children.push_back(child);
|
||||
child->setParent(asUIContainer());
|
||||
|
||||
// adjust child rect
|
||||
Rect childRect = child->getRect();
|
||||
childRect.translate(m_rect.topLeft());
|
||||
child->setRect(childRect);
|
||||
}
|
||||
|
||||
void UIContainer::removeChild(UIElementPtr child)
|
||||
@@ -42,12 +37,14 @@ void UIContainer::removeChild(UIElementPtr child)
|
||||
if(m_activeElement == child)
|
||||
setActiveElement(UIElementPtr());
|
||||
m_children.remove(child);
|
||||
if(child->getParent() == shared_from_this())
|
||||
child->setParent(UIContainerPtr());
|
||||
}
|
||||
|
||||
UIElementPtr UIContainer::getChildByName(const std::string& name) const
|
||||
UIElementPtr UIContainer::getChildById(const std::string& id) const
|
||||
{
|
||||
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
|
||||
if((*it)->getName() == name) {
|
||||
if((*it)->getId() == id) {
|
||||
return (*it);
|
||||
break;
|
||||
}
|
||||
@@ -55,45 +52,6 @@ UIElementPtr UIContainer::getChildByName(const std::string& name) const
|
||||
return UIElementPtr();
|
||||
}
|
||||
|
||||
|
||||
void UIContainer::setRect(const Rect& rect)
|
||||
{
|
||||
// update children rect
|
||||
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
|
||||
const UIElementPtr& child = (*it);
|
||||
|
||||
// transforme child rect
|
||||
Rect childRect = child->getRect();
|
||||
childRect.translate(-m_rect.topLeft());
|
||||
childRect.translate(rect.topLeft());
|
||||
child->setRect(childRect);
|
||||
}
|
||||
|
||||
m_rect = rect;
|
||||
}
|
||||
|
||||
void UIContainer::resize(const Size& size)
|
||||
{
|
||||
Rect newRect = m_rect;
|
||||
newRect.setSize(size);
|
||||
setRect(newRect);
|
||||
}
|
||||
|
||||
void UIContainer::move(const Point& trans)
|
||||
{
|
||||
Rect newRect = m_rect;
|
||||
newRect.translate(trans);
|
||||
setRect(newRect);
|
||||
}
|
||||
|
||||
void UIContainer::moveTo(const Point& pos)
|
||||
{
|
||||
Rect newRect = m_rect;
|
||||
newRect.moveTo(pos);
|
||||
setRect(newRect);
|
||||
|
||||
}
|
||||
|
||||
void UIContainer::render()
|
||||
{
|
||||
UIElement::render();
|
||||
@@ -103,11 +61,6 @@ void UIContainer::render()
|
||||
}
|
||||
}
|
||||
|
||||
void UIContainer::update(int ticks, int elapsedTicks)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool UIContainer::onInputEvent(InputEvent* event)
|
||||
{
|
||||
return false;
|
||||
|
@@ -36,20 +36,14 @@ public:
|
||||
UIContainer(UI::EElementType type = UI::Container) : UIElement(type) { }
|
||||
virtual ~UIContainer() { }
|
||||
|
||||
virtual void addChild(UIElementPtr child);
|
||||
virtual void removeChild(UIElementPtr child);
|
||||
virtual UIElementPtr getChildByName(const std::string& name) const;
|
||||
|
||||
virtual void setRect(const Rect& rect);
|
||||
virtual void resize(const Size& size);
|
||||
virtual void move(const Point& trans);
|
||||
virtual void moveTo(const Point& pos);
|
||||
void addChild(UIElementPtr child);
|
||||
void removeChild(UIElementPtr child);
|
||||
UIElementPtr getChildById(const std::string& id) const;
|
||||
|
||||
virtual void render();
|
||||
virtual void update(int ticks, int elapsedTicks);
|
||||
virtual bool onInputEvent(InputEvent *event);
|
||||
|
||||
virtual void setActiveElement(UIElementPtr activeElement);
|
||||
void setActiveElement(UIElementPtr activeElement);
|
||||
UIElementPtr getActiveElement() const { return m_activeElement; }
|
||||
|
||||
virtual UI::EElementType getElementType() const { return UI::Container; }
|
||||
|
@@ -24,9 +24,39 @@
|
||||
|
||||
#include "uielement.h"
|
||||
#include "uiskins.h"
|
||||
#include "uielementskin.h"
|
||||
|
||||
int AnchorLine::getPos() const
|
||||
{
|
||||
UIElementPtr 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("anchor line of an element have expired");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UIElement::UIElement(UI::EElementType type) :
|
||||
m_type(type)
|
||||
m_type(type),
|
||||
m_marginLeft(0),
|
||||
m_marginRight(0),
|
||||
m_marginTop(0),
|
||||
m_marginBottom(0)
|
||||
{
|
||||
// set default skin
|
||||
setSkin(g_uiSkins.getElementSkin(type));
|
||||
@@ -42,7 +72,7 @@ bool UIElement::setSkin(const std::string& skinName)
|
||||
void UIElement::setSkin(UIElementSkin* skin)
|
||||
{
|
||||
if(skin && !m_rect.isValid()) {
|
||||
m_rect.setSize(skin->getDefaultSize());
|
||||
setSize(skin->getDefaultSize());
|
||||
}
|
||||
m_skin = skin;
|
||||
}
|
||||
@@ -53,3 +83,75 @@ void UIElement::render()
|
||||
m_skin->draw(this);
|
||||
}
|
||||
|
||||
void UIElement::setSize(const Size& size)
|
||||
{
|
||||
m_rect.setSize(size);
|
||||
recalculateAnchors();
|
||||
}
|
||||
|
||||
void UIElement::setRect(const Rect& rect)
|
||||
{
|
||||
m_rect = rect;
|
||||
recalculateAnchors();
|
||||
}
|
||||
|
||||
void UIElement::addAnchor(EAnchorType type, const AnchorLine& anchorLine)
|
||||
{
|
||||
if(!anchorLine.isValid()) {
|
||||
logError("anchoring for an element has failed, got an invalid anchor line");
|
||||
return;
|
||||
}
|
||||
m_anchors[type] = anchorLine;
|
||||
anchorLine.getRelativeElement()->addAnchoredElement(asUIElement());
|
||||
recalculateAnchors();
|
||||
}
|
||||
|
||||
void UIElement::addAnchoredElement(UIElementPtr anchoredElement)
|
||||
{
|
||||
bool found = false;
|
||||
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
|
||||
if((*it).lock() == anchoredElement) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
m_anchoredElements.push_back(anchoredElement);
|
||||
}
|
||||
|
||||
void UIElement::recalculateAnchors()
|
||||
{
|
||||
// horizontal
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// vertical
|
||||
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.setLeft(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
|
||||
m_rect.setRight(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);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
|
||||
UIElementPtr element = (*it).lock();
|
||||
if(element)
|
||||
element->recalculateAnchors();
|
||||
}
|
||||
}
|
||||
|
@@ -29,13 +29,45 @@
|
||||
#include "../input.h"
|
||||
#include "../rect.h"
|
||||
#include "uiconstants.h"
|
||||
#include "uielementskin.h"
|
||||
|
||||
class UIElementSkin;
|
||||
|
||||
class UIContainer;
|
||||
typedef std::shared_ptr<UIContainer> UIContainerPtr;
|
||||
typedef std::weak_ptr<UIContainer> UIContainerWeakPtr;
|
||||
|
||||
class UIElement;
|
||||
typedef std::shared_ptr<UIElement> UIElementPtr;
|
||||
typedef std::weak_ptr<UIElement> UIElementWeakPtr;
|
||||
|
||||
enum EAnchorType {
|
||||
ANCHOR_LEFT = 0,
|
||||
ANCHOR_RIGHT,
|
||||
ANCHOR_TOP,
|
||||
ANCHOR_BOTTOM,
|
||||
ANCHOR_HORIZONTAL_CENTER,
|
||||
ANCHOR_VERTICAL_CENTER,
|
||||
ANCHOR_NONE
|
||||
};
|
||||
|
||||
class AnchorLine
|
||||
{
|
||||
public:
|
||||
AnchorLine() : m_anchorType(ANCHOR_NONE) { }
|
||||
AnchorLine(const AnchorLine& other) :
|
||||
m_relativeElement(other.m_relativeElement), m_anchorType(other.m_anchorType) { }
|
||||
AnchorLine(UIElementPtr relativeElement, EAnchorType anchorType) :
|
||||
m_relativeElement(relativeElement), m_anchorType(anchorType) { }
|
||||
bool isValid() const { return (m_anchorType != ANCHOR_NONE && !m_relativeElement.expired()); }
|
||||
|
||||
int getPos() const;
|
||||
EAnchorType getAnchorType() const { return m_anchorType; }
|
||||
UIElementPtr getRelativeElement() const { return m_relativeElement.lock(); }
|
||||
|
||||
private:
|
||||
UIElementWeakPtr m_relativeElement;
|
||||
EAnchorType m_anchorType;
|
||||
};
|
||||
|
||||
class UIElement : public std::enable_shared_from_this<UIElement>
|
||||
{
|
||||
@@ -44,7 +76,6 @@ public:
|
||||
virtual ~UIElement() { }
|
||||
|
||||
virtual void render();
|
||||
virtual void update(int ticks, int elapsedTicks) { }
|
||||
virtual bool onInputEvent(InputEvent *event) { return false; }
|
||||
|
||||
bool setSkin(const std::string& skinName);
|
||||
@@ -52,32 +83,67 @@ public:
|
||||
UIElementSkin *getSkin() { return m_skin; }
|
||||
|
||||
virtual void setParent(UIContainerPtr parent) { m_parent = parent; }
|
||||
UIContainerPtr getParent() const { return m_parent; }
|
||||
UIContainerPtr getParent() const { return m_parent.lock(); }
|
||||
|
||||
virtual void setName(const std::string& name) { m_name = name; }
|
||||
const std::string& getName() const { return m_name; }
|
||||
void setId(const std::string& id) { m_id = id; }
|
||||
const std::string& getId() const { return m_id; }
|
||||
|
||||
virtual void setRect(const Rect& rect) { m_rect = rect; }
|
||||
void setSize(const Size& size);
|
||||
Size getSize() { return m_rect.size(); }
|
||||
|
||||
void setRect(const Rect& rect);
|
||||
const Rect& getRect() const{ return m_rect; }
|
||||
|
||||
virtual void setActive(bool active) { m_active = active; }
|
||||
void setActive(bool active) { m_active = active; }
|
||||
bool isActive() const { return m_active; }
|
||||
|
||||
virtual void setVisible(bool visible) { m_visible = visible; }
|
||||
void setVisible(bool visible) { m_visible = visible; }
|
||||
bool isVisible() const { return m_visible; }
|
||||
|
||||
UI::EElementType getElementType() const { return m_type; }
|
||||
|
||||
UIElementPtr asUIElement() { return shared_from_this(); }
|
||||
|
||||
void recalculateAnchors();
|
||||
|
||||
void 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); }
|
||||
|
||||
AnchorLine left() { return AnchorLine(asUIElement(), ANCHOR_LEFT); }
|
||||
AnchorLine right() { return AnchorLine(asUIElement(), ANCHOR_RIGHT); }
|
||||
AnchorLine top() { return AnchorLine(asUIElement(), ANCHOR_TOP); }
|
||||
AnchorLine bottom() { return AnchorLine(asUIElement(), ANCHOR_BOTTOM); }
|
||||
AnchorLine horizontalCenter() { return AnchorLine(asUIElement(), ANCHOR_HORIZONTAL_CENTER); }
|
||||
AnchorLine verticalCenter() { return AnchorLine(asUIElement(), ANCHOR_VERTICAL_CENTER); }
|
||||
|
||||
void setMargin(int top, int left, int bottom, int right) { m_marginLeft = left; m_marginRight = right; m_marginTop = top; m_marginBottom = bottom; recalculateAnchors(); }
|
||||
void setMargin(int horizontal, int vertical) { m_marginLeft = m_marginRight = horizontal; m_marginTop = m_marginBottom = vertical; recalculateAnchors(); }
|
||||
void setMargin(int margin) { m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = margin; recalculateAnchors(); }
|
||||
|
||||
protected:
|
||||
void addAnchoredElement(UIElementPtr anchoredElement);
|
||||
|
||||
UI::EElementType m_type;
|
||||
UIContainerPtr m_parent;
|
||||
UIContainerWeakPtr m_parent;
|
||||
UIElementSkin *m_skin;
|
||||
Rect m_rect;
|
||||
std::string m_name;
|
||||
std::string m_id;
|
||||
bool m_visible;
|
||||
bool m_active;
|
||||
|
||||
private:
|
||||
AnchorLine m_anchors[6];
|
||||
|
||||
int m_marginLeft;
|
||||
int m_marginRight;
|
||||
int m_marginTop;
|
||||
int m_marginBottom;
|
||||
std::list<UIElementWeakPtr> m_anchoredElements;
|
||||
};
|
||||
|
||||
#endif // UIELEMENT_H
|
||||
|
@@ -29,6 +29,12 @@
|
||||
|
||||
UISkins g_uiSkins;
|
||||
|
||||
UISkins::~UISkins()
|
||||
{
|
||||
for(auto it = m_elementSkins.begin(); it != m_elementSkins.end(); ++it)
|
||||
delete (*it);
|
||||
}
|
||||
|
||||
bool UISkins::load(const std::string& file)
|
||||
{
|
||||
std::string fileContents = g_resources.loadTextFile(file);
|
||||
|
@@ -35,6 +35,7 @@ class UISkins
|
||||
{
|
||||
public:
|
||||
UISkins() { }
|
||||
~UISkins();
|
||||
|
||||
bool load(const std::string& file);
|
||||
|
||||
|
Reference in New Issue
Block a user