Merge branch 'master' of github.com:edubart/otclient
This commit is contained in:
commit
a3a96f78e8
|
@ -128,7 +128,6 @@ SET(SOURCES
|
||||||
src/framework/ui/uibutton.cpp
|
src/framework/ui/uibutton.cpp
|
||||||
src/framework/ui/uilineedit.cpp
|
src/framework/ui/uilineedit.cpp
|
||||||
src/framework/ui/uiwindow.cpp
|
src/framework/ui/uiwindow.cpp
|
||||||
src/framework/ui/uianchorlayout.cpp
|
|
||||||
src/framework/ui/uianchor.cpp
|
src/framework/ui/uianchor.cpp
|
||||||
src/framework/ui/uilist.cpp
|
src/framework/ui/uilist.cpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-- AnchorPoint
|
-- AnchorEdge
|
||||||
AnchorNone = 0
|
AnchorNone = 0
|
||||||
AnchorTop = 1
|
AnchorTop = 1
|
||||||
AnchorBottom = 2
|
AnchorBottom = 2
|
||||||
|
|
|
@ -29,7 +29,7 @@ enum AlignmentFlag {
|
||||||
AlignCenter = AlignVerticalCenter | AlignHorizontalCenter
|
AlignCenter = AlignVerticalCenter | AlignHorizontalCenter
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AnchorPoint {
|
enum AnchorEdge {
|
||||||
AnchorNone = 0,
|
AnchorNone = 0,
|
||||||
AnchorTop,
|
AnchorTop,
|
||||||
AnchorBottom,
|
AnchorBottom,
|
||||||
|
|
|
@ -5,27 +5,23 @@
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
|
||||||
class UIManager;
|
class UIManager;
|
||||||
class UILayout;
|
class UIAnchor;
|
||||||
class UIAnchorLayout;
|
|
||||||
class UIStyle;
|
|
||||||
class UIWidget;
|
class UIWidget;
|
||||||
class UILabel;
|
class UILabel;
|
||||||
class UIButton;
|
class UIButton;
|
||||||
class UILineEdit;
|
class UILineEdit;
|
||||||
class UIWindow;
|
class UIWindow;
|
||||||
class UIConsole;
|
|
||||||
|
|
||||||
typedef std::shared_ptr<UIWidget> UIWidgetPtr;
|
typedef std::shared_ptr<UIWidget> UIWidgetPtr;
|
||||||
typedef std::weak_ptr<UIWidget> UIWidgetWeakPtr;
|
typedef std::weak_ptr<UIWidget> UIWidgetWeakPtr;
|
||||||
typedef std::deque<UIWidgetPtr> UIWidgetList;
|
|
||||||
|
|
||||||
typedef std::shared_ptr<UILayout> UILayoutPtr;
|
|
||||||
typedef std::shared_ptr<UIAnchorLayout> UIAnchorLayoutPtr;
|
|
||||||
typedef std::shared_ptr<UIStyle> UIStylePtr;
|
|
||||||
typedef std::shared_ptr<UILabel> UILabelPtr;
|
typedef std::shared_ptr<UILabel> UILabelPtr;
|
||||||
typedef std::shared_ptr<UIButton> UIButtonPtr;
|
typedef std::shared_ptr<UIButton> UIButtonPtr;
|
||||||
typedef std::shared_ptr<UILineEdit> UILineEditPtr;
|
typedef std::shared_ptr<UILineEdit> UILineEditPtr;
|
||||||
typedef std::shared_ptr<UIWindow> UIWindowPtr;
|
typedef std::shared_ptr<UIWindow> UIWindowPtr;
|
||||||
typedef std::shared_ptr<UIConsole> UIConsolePtr;
|
|
||||||
|
typedef std::vector<UIAnchor> UIAnchorList;
|
||||||
|
typedef std::deque<UIWidgetPtr> UIWidgetList;
|
||||||
|
typedef std::deque<UIWidgetWeakPtr> UIWeakWidgetList;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "uiwidget.h"
|
#include "uiwidget.h"
|
||||||
#include "uibutton.h"
|
#include "uibutton.h"
|
||||||
#include "uilabel.h"
|
#include "uilabel.h"
|
||||||
#include "uilayout.h"
|
|
||||||
#include "uilineedit.h"
|
#include "uilineedit.h"
|
||||||
#include "uiwindow.h"
|
#include "uiwindow.h"
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,31 @@
|
||||||
#include "uianchor.h"
|
#include "uianchor.h"
|
||||||
#include "uiwidget.h"
|
#include "uiwidget.h"
|
||||||
|
|
||||||
UIAnchor::UIAnchor(const UIWidgetPtr& anchoredWidget, AnchorPoint anchoredEdge, const AnchorLine& anchorLine)
|
UIAnchor::UIAnchor(AnchorEdge anchoredEdge, const std::string& hookedWidgetId, AnchorEdge hookedEdge) :
|
||||||
: m_anchoredWidget(anchoredWidget), m_anchoredEdge(anchoredEdge), m_anchorLine(anchorLine) {
|
m_anchoredEdge(anchoredEdge), m_hookedWidgetId(hookedWidgetId), m_hookedEdge(hookedEdge) {
|
||||||
}
|
}
|
||||||
|
|
||||||
UIWidgetPtr UIAnchor::getAnchorLineWidget() const {
|
int UIAnchor::getHookedPoint() const {
|
||||||
UIWidgetPtr anchoredWidget = m_anchoredWidget.lock();
|
UIWidgetPtr hookedWidget = getHookedWidget();
|
||||||
if(anchoredWidget && !anchoredWidget->isDestroyed())
|
|
||||||
return anchoredWidget->backwardsGetWidgetById(m_anchorLine.widgetId);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if(hookedWidget) {
|
||||||
UIWidgetPtr UIAnchor::getAnchoredWidget() const {
|
switch(m_hookedEdge) {
|
||||||
return m_anchoredWidget.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
AnchorPoint UIAnchor::getAnchoredEdge() const {
|
|
||||||
return m_anchoredEdge;
|
|
||||||
}
|
|
||||||
|
|
||||||
int UIAnchor::getAnchorLinePoint() const {
|
|
||||||
UIWidgetPtr anchorLineWidget = getAnchorLineWidget();
|
|
||||||
if(anchorLineWidget) {
|
|
||||||
switch(m_anchorLine.edge) {
|
|
||||||
case AnchorLeft:
|
case AnchorLeft:
|
||||||
return anchorLineWidget->getGeometry().left();
|
return hookedWidget->getRect().left();
|
||||||
case AnchorRight:
|
case AnchorRight:
|
||||||
return anchorLineWidget->getGeometry().right();
|
return hookedWidget->getRect().right();
|
||||||
case AnchorTop:
|
case AnchorTop:
|
||||||
return anchorLineWidget->getGeometry().top();
|
return hookedWidget->getRect().top();
|
||||||
case AnchorBottom:
|
case AnchorBottom:
|
||||||
return anchorLineWidget->getGeometry().bottom();
|
return hookedWidget->getRect().bottom();
|
||||||
case AnchorHorizontalCenter:
|
case AnchorHorizontalCenter:
|
||||||
return anchorLineWidget->getGeometry().horizontalCenter();
|
return hookedWidget->getRect().horizontalCenter();
|
||||||
case AnchorVerticalCenter:
|
case AnchorVerticalCenter:
|
||||||
return anchorLineWidget->getGeometry().verticalCenter();
|
return hookedWidget->getRect().verticalCenter();
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -9999;
|
|
||||||
|
return INVALID_POINT;
|
||||||
}
|
}
|
|
@ -3,25 +3,27 @@
|
||||||
|
|
||||||
#include "declarations.h"
|
#include "declarations.h"
|
||||||
|
|
||||||
struct AnchorLine {
|
|
||||||
AnchorLine(std::string widgetId, AnchorPoint edge) : widgetId(widgetId), edge(edge) { }
|
|
||||||
std::string widgetId;
|
|
||||||
AnchorPoint edge;
|
|
||||||
};
|
|
||||||
|
|
||||||
class UIAnchor
|
class UIAnchor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
UIAnchor(const UIWidgetPtr& anchoredWidget, AnchorPoint anchoredEdge, const AnchorLine& anchorLine);
|
enum {
|
||||||
UIWidgetPtr getAnchorLineWidget() const;
|
INVALID_POINT = -999999
|
||||||
UIWidgetPtr getAnchoredWidget() const;
|
};
|
||||||
AnchorPoint getAnchoredEdge() const;
|
|
||||||
int getAnchorLinePoint() const;
|
UIAnchor(AnchorEdge anchoredEdge, const std::string& hookedWidgetId, AnchorEdge hookedEdge);
|
||||||
|
|
||||||
|
AnchorEdge getAnchoredEdge() const { return m_anchoredEdge; }
|
||||||
|
UIWidgetPtr getHookedWidget() const { return m_hookedWidget.lock(); }
|
||||||
|
std::string getHookedWidgetId() const { return m_hookedWidgetId; }
|
||||||
|
int getHookedPoint() const;
|
||||||
|
|
||||||
|
void setHookedWidget(const UIWidgetPtr hookedWidget) { m_hookedWidget = hookedWidget; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UIWidgetWeakPtr m_anchoredWidget;
|
AnchorEdge m_anchoredEdge;
|
||||||
AnchorPoint m_anchoredEdge;
|
UIWidgetWeakPtr m_hookedWidget;
|
||||||
AnchorLine m_anchorLine;
|
std::string m_hookedWidgetId;
|
||||||
|
AnchorEdge m_hookedEdge;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
#include "uianchorlayout.h"
|
|
||||||
#include "uiwidget.h"
|
|
||||||
|
|
||||||
bool UIAnchorLayout::addAnchor(const UIWidgetPtr& anchoredWidget, AnchorPoint anchoredEdge, const AnchorLine& anchorLine)
|
|
||||||
{
|
|
||||||
UIAnchor anchor(anchoredWidget, anchoredEdge, anchorLine);
|
|
||||||
UIWidgetPtr anchorLineWidget = anchor.getAnchorLineWidget();
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(!anchorLineWidget) {
|
|
||||||
logError("could not find the widget to anchor on, wrong id?");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// we can never anchor with itself
|
|
||||||
if(anchoredWidget == anchorLineWidget) {
|
|
||||||
logError("anchoring with itself is not possible");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we must never anchor to an anchor child
|
|
||||||
if(anchoredWidget && hasWidgetInAnchorTree(anchorLineWidget, anchoredWidget)) {
|
|
||||||
logError("anchors is miss configured, you must never make an anchor chains in loops");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid duplicated anchors
|
|
||||||
for(auto it = m_anchors.begin(); it != m_anchors.end(); ++it) {
|
|
||||||
const UIAnchor& otherAnchor = *it;
|
|
||||||
if(otherAnchor.getAnchoredWidget() == anchoredWidget && otherAnchor.getAnchoredEdge() == anchoredEdge) {
|
|
||||||
m_anchors.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup the anchor
|
|
||||||
m_anchors.push_back(anchor);
|
|
||||||
|
|
||||||
// recalculate anchored widget layout
|
|
||||||
updateWidget(anchoredWidget);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIAnchorLayout::updateWidget(const UIWidgetPtr& widget)
|
|
||||||
{
|
|
||||||
Rect rect = widget->getGeometry();
|
|
||||||
bool verticalMoved = false;
|
|
||||||
bool horizontalMoved = false;
|
|
||||||
|
|
||||||
// FIXME: release expired anchors
|
|
||||||
for(const UIAnchor& anchor : m_anchors) {
|
|
||||||
if(anchor.getAnchoredWidget() == widget && anchor.getAnchorLineWidget()) {
|
|
||||||
int point = anchor.getAnchorLinePoint();
|
|
||||||
switch(anchor.getAnchoredEdge()) {
|
|
||||||
case AnchorHorizontalCenter:
|
|
||||||
rect.moveHorizontalCenter(point + widget->getMarginLeft() - widget->getMarginRight());
|
|
||||||
horizontalMoved = true;
|
|
||||||
break;
|
|
||||||
case AnchorLeft:
|
|
||||||
if(!horizontalMoved) {
|
|
||||||
rect.moveLeft(point + widget->getMarginLeft());
|
|
||||||
horizontalMoved = true;
|
|
||||||
} else
|
|
||||||
rect.setLeft(point + widget->getMarginLeft());
|
|
||||||
break;
|
|
||||||
case AnchorRight:
|
|
||||||
if(!horizontalMoved) {
|
|
||||||
rect.moveRight(point - widget->getMarginRight());
|
|
||||||
horizontalMoved = true;
|
|
||||||
} else
|
|
||||||
rect.setRight(point - widget->getMarginRight());
|
|
||||||
break;
|
|
||||||
case AnchorVerticalCenter:
|
|
||||||
rect.moveVerticalCenter(point + widget->getMarginTop() - widget->getMarginBottom());
|
|
||||||
verticalMoved = true;
|
|
||||||
break;
|
|
||||||
case AnchorTop:
|
|
||||||
if(!verticalMoved) {
|
|
||||||
rect.moveTop(point + widget->getMarginTop());
|
|
||||||
verticalMoved = true;
|
|
||||||
} else
|
|
||||||
rect.setTop(point + widget->getMarginTop());
|
|
||||||
break;
|
|
||||||
case AnchorBottom:
|
|
||||||
if(!verticalMoved) {
|
|
||||||
rect.moveBottom(point - widget->getMarginBottom());
|
|
||||||
verticalMoved = true;
|
|
||||||
} else
|
|
||||||
rect.setBottom(point - widget->getMarginBottom());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rect != widget->getGeometry())
|
|
||||||
widget->setGeometry(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIAnchorLayout::updateWidgetChildren(const UIWidgetPtr& parent)
|
|
||||||
{
|
|
||||||
for(const UIAnchor& anchor : m_anchors) {
|
|
||||||
if(anchor.getAnchorLineWidget() == parent) {
|
|
||||||
UIWidgetPtr child = anchor.getAnchoredWidget();
|
|
||||||
if(child)
|
|
||||||
updateWidget(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIAnchorLayout::hasWidgetInAnchorTree(const UIWidgetPtr& widget, const UIWidgetPtr& treeAnchor)
|
|
||||||
{
|
|
||||||
for(const UIAnchor& anchor : m_anchors) {
|
|
||||||
if(anchor.getAnchorLineWidget() == treeAnchor) {
|
|
||||||
if(anchor.getAnchoredWidget() == widget || hasWidgetInAnchorTree(widget, anchor.getAnchoredWidget()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
#ifndef UIANCHORLAYOUT_H
|
|
||||||
#define UIANCHORLAYOUT_H
|
|
||||||
|
|
||||||
#include "uilayout.h"
|
|
||||||
#include "uianchor.h"
|
|
||||||
|
|
||||||
class UIAnchorLayout : public UILayout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool addAnchor(const UIWidgetPtr& anchoredWidget, AnchorPoint anchoredEdge, const AnchorLine& anchorLine);
|
|
||||||
void updateWidget(const UIWidgetPtr& widget);
|
|
||||||
void updateWidgetChildren(const UIWidgetPtr& parent);
|
|
||||||
|
|
||||||
bool hasWidgetInAnchorTree(const UIWidgetPtr& widget, const UIWidgetPtr& treeAnchor);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::list<UIAnchor> m_anchors;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -63,7 +63,7 @@ void UIButton::render()
|
||||||
UIWidget::render();
|
UIWidget::render();
|
||||||
|
|
||||||
const ButtonStateStyle& currentStyle = m_statesStyle[m_state];
|
const ButtonStateStyle& currentStyle = m_statesStyle[m_state];
|
||||||
Rect textRect = getGeometry();
|
Rect textRect = getRect();
|
||||||
|
|
||||||
if(currentStyle.image) {
|
if(currentStyle.image) {
|
||||||
g_graphics.bindColor(currentStyle.color);
|
g_graphics.bindColor(currentStyle.color);
|
||||||
|
@ -93,7 +93,7 @@ void UIButton::onMousePress(UIMouseEvent& event)
|
||||||
void UIButton::onMouseRelease(UIMouseEvent& event)
|
void UIButton::onMouseRelease(UIMouseEvent& event)
|
||||||
{
|
{
|
||||||
if(m_state == ButtonDown) {
|
if(m_state == ButtonDown) {
|
||||||
if(m_onClick && getGeometry().contains(event.pos()))
|
if(m_onClick && getRect().contains(event.pos()))
|
||||||
m_onClick();
|
m_onClick();
|
||||||
m_state = (isHovered() && isEnabled()) ? ButtonHover : ButtonUp;
|
m_state = (isHovered() && isEnabled()) ? ButtonHover : ButtonUp;
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -88,10 +88,10 @@ private:
|
||||||
bool m_hovered;
|
bool m_hovered;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UIGeometryUpdateEvent : public UIEvent
|
class UIRectUpdateEvent : public UIEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
UIGeometryUpdateEvent(const Rect& oldRect, const Rect& rect)
|
UIRectUpdateEvent(const Rect& oldRect, const Rect& rect)
|
||||||
: m_oldRect(oldRect), m_rect(rect) { }
|
: m_oldRect(oldRect), m_rect(rect) { }
|
||||||
|
|
||||||
Point pos() const { return m_rect.topLeft(); }
|
Point pos() const { return m_rect.topLeft(); }
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "uilayout.h"
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef UILAYOUT_H
|
|
||||||
#define UILAYOUT_H
|
|
||||||
|
|
||||||
#include "declarations.h"
|
|
||||||
|
|
||||||
class UILayout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void updateWidget(const UIWidgetPtr& widget) = 0;
|
|
||||||
virtual void updateWidgetChildren(const UIWidgetPtr& widget) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -18,7 +18,6 @@ UILineEdit::UILineEdit() : UIWidget(UITypeLabel)
|
||||||
UILineEditPtr UILineEdit::create()
|
UILineEditPtr UILineEdit::create()
|
||||||
{
|
{
|
||||||
UILineEditPtr lineEdit(new UILineEdit);
|
UILineEditPtr lineEdit(new UILineEdit);
|
||||||
lineEdit->setStyle("LineEdit");
|
|
||||||
return lineEdit;
|
return lineEdit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,13 +37,16 @@ void UILineEdit::render()
|
||||||
{
|
{
|
||||||
UIWidget::render();
|
UIWidget::render();
|
||||||
|
|
||||||
|
if(!m_rect.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
//TODO: text rendering could be much optimized by using vertex buffer or caching the render into a texture
|
//TODO: text rendering could be much optimized by using vertex buffer or caching the render into a texture
|
||||||
|
|
||||||
int textLength = m_text.length();
|
int textLength = m_text.length();
|
||||||
const TexturePtr& texture = m_font->getTexture();
|
const TexturePtr& texture = m_font->getTexture();
|
||||||
for(int i=0;i<textLength;++i) {
|
|
||||||
|
for(int i=0;i<textLength;++i)
|
||||||
g_graphics.drawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]);
|
g_graphics.drawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]);
|
||||||
}
|
|
||||||
|
|
||||||
// render cursor
|
// render cursor
|
||||||
if(isExplicitlyEnabled() && hasFocus() && m_cursorPos >= 0) {
|
if(isExplicitlyEnabled() && hasFocus() && m_cursorPos >= 0) {
|
||||||
|
@ -334,7 +336,7 @@ int UILineEdit::getTextPos(Point pos)
|
||||||
return candidatePos;
|
return candidatePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UILineEdit::onGeometryUpdate(UIGeometryUpdateEvent& event)
|
void UILineEdit::onRectUpdate(UIRectUpdateEvent& event)
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
int getTextPos(Point pos);
|
int getTextPos(Point pos);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onGeometryUpdate(UIGeometryUpdateEvent& event);
|
virtual void onRectUpdate(UIRectUpdateEvent& event);
|
||||||
virtual void onFocusChange(UIFocusEvent& event);
|
virtual void onFocusChange(UIFocusEvent& event);
|
||||||
virtual void onKeyPress(UIKeyEvent& event);
|
virtual void onKeyPress(UIKeyEvent& event);
|
||||||
virtual void onMousePress(UIMouseEvent& event);
|
virtual void onMousePress(UIMouseEvent& event);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "uimanager.h"
|
#include "uimanager.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "uianchorlayout.h"
|
|
||||||
|
|
||||||
#include <framework/otml/otml.h>
|
#include <framework/otml/otml.h>
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
|
@ -13,9 +12,6 @@ void UIManager::init()
|
||||||
m_rootWidget = UIWidgetPtr(new UIWidget);
|
m_rootWidget = UIWidgetPtr(new UIWidget);
|
||||||
m_rootWidget->setId("root");
|
m_rootWidget->setId("root");
|
||||||
m_rootWidget->setHovered(true);
|
m_rootWidget->setHovered(true);
|
||||||
|
|
||||||
UIAnchorLayoutPtr anchorLayout(new UIAnchorLayout);
|
|
||||||
m_rootWidget->setLayout(anchorLayout);
|
|
||||||
m_rootWidget->resize(g_graphics.getScreenSize());
|
m_rootWidget->resize(g_graphics.getScreenSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +183,7 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode)
|
||||||
throw OTMLException(styleNode, "cannot determine widget type");
|
throw OTMLException(styleNode, "cannot determine widget type");
|
||||||
|
|
||||||
widget->loadStyleFromOTML(styleNode);
|
widget->loadStyleFromOTML(styleNode);
|
||||||
widget->updateGeometry();
|
widget->updateLayout();
|
||||||
|
|
||||||
for(const OTMLNodePtr& childNode : widgetNode->children()) {
|
for(const OTMLNodePtr& childNode : widgetNode->children()) {
|
||||||
if(!childNode->isUnique())
|
if(!childNode->isUnique())
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#include "uiwidget.h"
|
#include "uiwidget.h"
|
||||||
#include "uimanager.h"
|
#include "uimanager.h"
|
||||||
#include "uilayout.h"
|
|
||||||
#include "uianchorlayout.h"
|
|
||||||
|
|
||||||
#include <framework/core/eventdispatcher.h>
|
#include <framework/core/eventdispatcher.h>
|
||||||
#include <framework/graphics/image.h>
|
#include <framework/graphics/image.h>
|
||||||
|
@ -9,6 +7,7 @@
|
||||||
#include <framework/graphics/fontmanager.h>
|
#include <framework/graphics/fontmanager.h>
|
||||||
#include <framework/otml/otmlnode.h>
|
#include <framework/otml/otmlnode.h>
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
|
#include "uianchor.h"
|
||||||
|
|
||||||
UIWidget::UIWidget(UIWidgetType type)
|
UIWidget::UIWidget(UIWidgetType type)
|
||||||
{
|
{
|
||||||
|
@ -18,7 +17,10 @@ UIWidget::UIWidget(UIWidgetType type)
|
||||||
m_hovered = false;
|
m_hovered = false;
|
||||||
m_focusable = true;
|
m_focusable = true;
|
||||||
m_destroyed = false;
|
m_destroyed = false;
|
||||||
m_updateScheduled = false;
|
m_layoutUpdated = true;
|
||||||
|
m_updateEventScheduled = false;
|
||||||
|
m_layoutUpdateScheduled = false;
|
||||||
|
m_childrenLayoutUpdateScheduled = false;
|
||||||
m_opacity = 255;
|
m_opacity = 255;
|
||||||
m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = 0;
|
m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = 0;
|
||||||
m_backgroundColor = Color::white;
|
m_backgroundColor = Color::white;
|
||||||
|
@ -158,7 +160,7 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
|
||||||
} else if(what == "centerIn") {
|
} else if(what == "centerIn") {
|
||||||
centerIn(node->value());
|
centerIn(node->value());
|
||||||
} else {
|
} else {
|
||||||
AnchorPoint myEdge = fw::translateAnchorPoint(what);
|
AnchorEdge myEdge = fw::translateAnchorEdge(what);
|
||||||
|
|
||||||
std::string anchorDescription = node->value();
|
std::string anchorDescription = node->value();
|
||||||
std::vector<std::string> split;
|
std::vector<std::string> split;
|
||||||
|
@ -167,15 +169,15 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
|
||||||
throw OTMLException(node, "invalid anchor description");
|
throw OTMLException(node, "invalid anchor description");
|
||||||
|
|
||||||
std::string target = split[0];
|
std::string target = split[0];
|
||||||
AnchorPoint targetEdge = fw::translateAnchorPoint(split[1]);
|
AnchorEdge hookedEdge = fw::translateAnchorEdge(split[1]);
|
||||||
|
|
||||||
if(myEdge == AnchorNone)
|
if(myEdge == AnchorNone)
|
||||||
throw OTMLException(node, "invalid anchor edge");
|
throw OTMLException(node, "invalid anchor edge");
|
||||||
|
|
||||||
if(targetEdge == AnchorNone)
|
if(hookedEdge == AnchorNone)
|
||||||
throw OTMLException(node, "invalid anchor target edge");
|
throw OTMLException(node, "invalid anchor target edge");
|
||||||
|
|
||||||
addAnchor(myEdge, target, targetEdge);
|
addAnchor(myEdge, target, hookedEdge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(node->tag() == "onLoad") {
|
else if(node->tag() == "onLoad") {
|
||||||
|
@ -190,7 +192,7 @@ void UIWidget::render()
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
if(m_image)
|
if(m_image)
|
||||||
m_image->draw(getGeometry());
|
m_image->draw(getRect());
|
||||||
|
|
||||||
for(const UIWidgetPtr& child : m_children) {
|
for(const UIWidgetPtr& child : m_children) {
|
||||||
if(child->isExplicitlyVisible()) {
|
if(child->isExplicitlyVisible()) {
|
||||||
|
@ -203,23 +205,13 @@ void UIWidget::render()
|
||||||
|
|
||||||
// debug draw box
|
// debug draw box
|
||||||
//g_graphics.bindColor(Color::green);
|
//g_graphics.bindColor(Color::green);
|
||||||
//g_graphics.drawBoundingRect(child->getGeometry());
|
//g_graphics.drawBoundingRect(child->getRect());
|
||||||
|
|
||||||
g_graphics.setOpacity(oldOpacity);
|
g_graphics.setOpacity(oldOpacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::updateGeometry()
|
|
||||||
{
|
|
||||||
assert(!m_destroyed);
|
|
||||||
|
|
||||||
if(UILayoutPtr layout = getLayout()) {
|
|
||||||
layout->updateWidget(asUIWidget());
|
|
||||||
layout->updateWidgetChildren(asUIWidget());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIWidget::setParent(const UIWidgetPtr& parent)
|
void UIWidget::setParent(const UIWidgetPtr& parent)
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
@ -247,32 +239,33 @@ void UIWidget::setStyle(const std::string& styleName)
|
||||||
loadStyleFromOTML(styleNode);
|
loadStyleFromOTML(styleNode);
|
||||||
|
|
||||||
// forces layout recalculation
|
// forces layout recalculation
|
||||||
updateGeometry();
|
updateLayout();
|
||||||
} catch(std::exception& e) {
|
} catch(std::exception& e) {
|
||||||
logError("couldn't change widget '", m_id, "' style: ", e.what());
|
logError("couldn't change widget '", m_id, "' style: ", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::setGeometry(const Rect& rect)
|
void UIWidget::setRect(const Rect& rect)
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
Rect oldRect = m_rect;
|
Rect oldRect = m_rect;
|
||||||
m_rect = rect;
|
m_rect = rect;
|
||||||
if(UILayoutPtr layout = getLayout())
|
|
||||||
layout->updateWidgetChildren(asUIWidget());
|
|
||||||
|
|
||||||
// avoid massive updates
|
// updates children geometry
|
||||||
if(!m_updateScheduled) {
|
updateChildrenLayout();
|
||||||
|
|
||||||
|
// avoid massive update events
|
||||||
|
if(!m_updateEventScheduled) {
|
||||||
UIWidgetPtr self = asUIWidget();
|
UIWidgetPtr self = asUIWidget();
|
||||||
g_dispatcher.addEvent([self, oldRect]() {
|
g_dispatcher.addEvent([self, oldRect]() {
|
||||||
self->m_updateScheduled = false;
|
self->m_updateEventScheduled = false;
|
||||||
UIGeometryUpdateEvent e(oldRect, self->getGeometry());
|
UIRectUpdateEvent e(oldRect, self->getRect());
|
||||||
// this widget could be destroyed before the event happens
|
// this widget could be destroyed before the event happens
|
||||||
if(!self->isDestroyed())
|
if(!self->isDestroyed())
|
||||||
self->onGeometryUpdate(e);
|
self->onRectUpdate(e);
|
||||||
});
|
});
|
||||||
m_updateScheduled = true;
|
m_updateEventScheduled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,16 +303,12 @@ bool UIWidget::hasChild(const UIWidgetPtr& child)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UILayoutPtr UIWidget::getLayout() const
|
UIWidgetPtr UIWidget::getRootParent()
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
if(UIWidgetPtr parent = getParent())
|
||||||
|
return parent->getRootParent();
|
||||||
if(m_layout)
|
else
|
||||||
return m_layout;
|
return asUIWidget();
|
||||||
else if(getParent() && getParent()->getLayout())
|
|
||||||
return getParent()->getLayout();
|
|
||||||
// fallback to root layout
|
|
||||||
return g_ui.getRootWidget()->getLayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UIWidgetPtr UIWidget::getChildAfter(const UIWidgetPtr& relativeChild)
|
UIWidgetPtr UIWidget::getChildAfter(const UIWidgetPtr& relativeChild)
|
||||||
|
@ -383,7 +372,7 @@ UIWidgetPtr UIWidget::getChildByPos(const Point& childPos)
|
||||||
|
|
||||||
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
||||||
const UIWidgetPtr& widget = (*it);
|
const UIWidgetPtr& widget = (*it);
|
||||||
if(widget->isExplicitlyVisible() && widget->getGeometry().contains(childPos))
|
if(widget->isExplicitlyVisible() && widget->getRect().contains(childPos))
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,35 +388,19 @@ UIWidgetPtr UIWidget::getChildByIndex(int childIndex)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UIWidgetPtr UIWidget::recursiveGetChildById(const std::string& childId)
|
UIWidgetPtr UIWidget::recursiveGetChildById(const std::string& id)
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
if(getId() == childId || childId == "self")
|
UIWidgetPtr widget = getChildById(id);
|
||||||
return asUIWidget();
|
if(!widget) {
|
||||||
else if(childId == "parent")
|
|
||||||
return getParent();
|
|
||||||
else if(childId == "root")
|
|
||||||
return g_ui.getRootWidget();
|
|
||||||
else if(childId == "prev") {
|
|
||||||
if(UIWidgetPtr parent = getParent())
|
|
||||||
return parent->getChildBefore(asUIWidget());
|
|
||||||
} else if(childId == "next") {
|
|
||||||
if(UIWidgetPtr parent = getParent())
|
|
||||||
return parent->getChildAfter(asUIWidget());
|
|
||||||
} else {
|
|
||||||
for(const UIWidgetPtr& child : m_children) {
|
for(const UIWidgetPtr& child : m_children) {
|
||||||
if(child->getId() == childId)
|
widget = child->recursiveGetChildById(id);
|
||||||
return child;
|
if(widget)
|
||||||
}
|
break;
|
||||||
for(const UIWidgetPtr& child : m_children) {
|
|
||||||
if(UIWidgetPtr subChild = child->recursiveGetChildById(childId)) {
|
|
||||||
if(subChild->getId() == childId)
|
|
||||||
return subChild;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos)
|
UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos)
|
||||||
|
@ -435,7 +408,7 @@ UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos)
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
for(const UIWidgetPtr& child : m_children) {
|
for(const UIWidgetPtr& child : m_children) {
|
||||||
if(child->getGeometry().contains(childPos)) {
|
if(child->getRect().contains(childPos)) {
|
||||||
if(UIWidgetPtr subChild = child->recursiveGetChildByPos(childPos))
|
if(UIWidgetPtr subChild = child->recursiveGetChildByPos(childPos))
|
||||||
return subChild;
|
return subChild;
|
||||||
return child;
|
return child;
|
||||||
|
@ -449,27 +422,12 @@ UIWidgetPtr UIWidget::backwardsGetWidgetById(const std::string& id)
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
UIWidgetPtr widget;
|
UIWidgetPtr widget = getChildById(id);
|
||||||
if(getId() == id || id == "self")
|
if(!widget) {
|
||||||
widget = asUIWidget();
|
|
||||||
else if(id == "parent")
|
|
||||||
widget = getParent();
|
|
||||||
else if(id == "root")
|
|
||||||
widget = g_ui.getRootWidget();
|
|
||||||
else if(id == "prev") {
|
|
||||||
if(UIWidgetPtr parent = getParent())
|
|
||||||
widget = parent->getChildBefore(asUIWidget());
|
|
||||||
} else if(id == "next") {
|
|
||||||
if(UIWidgetPtr parent = getParent())
|
|
||||||
widget = parent->getChildAfter(asUIWidget());
|
|
||||||
} else {
|
|
||||||
widget = recursiveGetChildById(id);
|
|
||||||
if(widget)
|
|
||||||
return widget;
|
|
||||||
|
|
||||||
if(UIWidgetPtr parent = getParent())
|
if(UIWidgetPtr parent = getParent())
|
||||||
widget = parent->backwardsGetWidgetById(id);
|
widget = parent->backwardsGetWidgetById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,8 +461,11 @@ void UIWidget::addChild(const UIWidgetPtr& childToAdd)
|
||||||
m_children.push_back(childToAdd);
|
m_children.push_back(childToAdd);
|
||||||
childToAdd->setParent(asUIWidget());
|
childToAdd->setParent(asUIWidget());
|
||||||
|
|
||||||
// updates geometry
|
// recalculate anchors
|
||||||
updateGeometry();
|
getRootParent()->recalculateAnchoredWidgets();
|
||||||
|
|
||||||
|
// may need to update children layout
|
||||||
|
updateChildrenLayout();
|
||||||
|
|
||||||
// always focus new children
|
// always focus new children
|
||||||
if(childToAdd->isFocusable())
|
if(childToAdd->isFocusable())
|
||||||
|
@ -529,8 +490,11 @@ void UIWidget::insertChild(const UIWidgetPtr& childToInsert, int index)
|
||||||
m_children.insert(it, childToInsert);
|
m_children.insert(it, childToInsert);
|
||||||
childToInsert->setParent(asUIWidget());
|
childToInsert->setParent(asUIWidget());
|
||||||
|
|
||||||
// updates geometry
|
// recalculate anchors
|
||||||
updateGeometry();
|
getRootParent()->recalculateAnchoredWidgets();
|
||||||
|
|
||||||
|
// may need to update children layout
|
||||||
|
updateChildrenLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
|
void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
|
||||||
|
@ -555,6 +519,13 @@ void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
|
||||||
// reset child parent
|
// reset child parent
|
||||||
assert(childToRemove->getParent() == asUIWidget());
|
assert(childToRemove->getParent() == asUIWidget());
|
||||||
childToRemove->setParent(nullptr);
|
childToRemove->setParent(nullptr);
|
||||||
|
|
||||||
|
// recalculate anchors
|
||||||
|
UIWidgetPtr parent = getRootParent();
|
||||||
|
parent->recalculateAnchoredWidgets();
|
||||||
|
|
||||||
|
// may need to update children layout
|
||||||
|
updateChildrenLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::focusNextChild(FocusReason reason)
|
void UIWidget::focusNextChild(FocusReason reason)
|
||||||
|
@ -633,32 +604,227 @@ void UIWidget::unlockChild(const UIWidgetPtr& childToUnlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::addAnchor(AnchorPoint edge, const std::string& targetId, AnchorPoint targetEdge)
|
void UIWidget::updateLayout()
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
UIAnchorLayoutPtr layout = std::dynamic_pointer_cast<UIAnchorLayout>(getLayout());
|
if(!m_layoutUpdateScheduled) {
|
||||||
assert(layout);
|
m_layoutUpdateScheduled = true;
|
||||||
if(layout)
|
UIWidgetPtr self = asUIWidget();
|
||||||
layout->addAnchor(asUIWidget(), edge, AnchorLine(targetId, targetEdge));
|
g_dispatcher.addEvent([self] {
|
||||||
|
self->m_layoutUpdateScheduled = false;
|
||||||
|
if(!self->isDestroyed())
|
||||||
|
self->internalUpdateLayout();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::centerIn(const std::string& targetId)
|
void UIWidget::updateChildrenLayout()
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
addAnchor(AnchorHorizontalCenter, targetId, AnchorHorizontalCenter);
|
if(!m_childrenLayoutUpdateScheduled) {
|
||||||
addAnchor(AnchorVerticalCenter, targetId, AnchorVerticalCenter);
|
m_childrenLayoutUpdateScheduled = true;
|
||||||
|
UIWidgetPtr self = asUIWidget();
|
||||||
|
g_dispatcher.addEvent([self] {
|
||||||
|
self->m_childrenLayoutUpdateScheduled = false;
|
||||||
|
if(!self->isDestroyed())
|
||||||
|
self->internalUpdateChildrenLayout();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::fill(const std::string& targetId)
|
bool UIWidget::addAnchor(AnchorEdge edge, const std::string& hookedWidgetId, AnchorEdge hookedEdge)
|
||||||
{
|
{
|
||||||
assert(!m_destroyed);
|
assert(!m_destroyed);
|
||||||
|
|
||||||
addAnchor(AnchorLeft, targetId, AnchorLeft);
|
UIAnchor anchor(edge, hookedWidgetId, hookedEdge);
|
||||||
addAnchor(AnchorRight, targetId, AnchorRight);
|
|
||||||
addAnchor(AnchorTop, targetId, AnchorTop);
|
UIWidgetPtr hookedWidget = backwardsGetWidgetById(hookedWidgetId);
|
||||||
addAnchor(AnchorBottom, targetId, AnchorBottom);
|
anchor.setHookedWidget(hookedWidget);
|
||||||
|
|
||||||
|
// we can never anchor with itself
|
||||||
|
if(hookedWidget == asUIWidget()) {
|
||||||
|
logError("anchoring with itself is not possible");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we must never anchor to an anchor child
|
||||||
|
//TODO: this check
|
||||||
|
|
||||||
|
// duplicated anchors must be replaced
|
||||||
|
for(auto it = m_anchors.begin(); it != m_anchors.end(); ++it) {
|
||||||
|
const UIAnchor& otherAnchor = *it;
|
||||||
|
if(otherAnchor.getAnchoredEdge() == edge) {
|
||||||
|
m_anchors.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_anchors.push_back(anchor);
|
||||||
|
|
||||||
|
updateLayout();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::centerIn(const std::string& hookedWidgetId)
|
||||||
|
{
|
||||||
|
assert(!m_destroyed);
|
||||||
|
|
||||||
|
addAnchor(AnchorHorizontalCenter, hookedWidgetId, AnchorHorizontalCenter);
|
||||||
|
addAnchor(AnchorVerticalCenter, hookedWidgetId, AnchorVerticalCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::fill(const std::string& hookedWidgetId)
|
||||||
|
{
|
||||||
|
assert(!m_destroyed);
|
||||||
|
|
||||||
|
addAnchor(AnchorLeft, hookedWidgetId, AnchorLeft);
|
||||||
|
addAnchor(AnchorRight, hookedWidgetId, AnchorRight);
|
||||||
|
addAnchor(AnchorTop, hookedWidgetId, AnchorTop);
|
||||||
|
addAnchor(AnchorBottom, hookedWidgetId, AnchorBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::internalUpdateLayout()
|
||||||
|
{
|
||||||
|
assert(!m_destroyed);
|
||||||
|
|
||||||
|
for(const UIAnchor& anchor : m_anchors) {
|
||||||
|
// ignore invalid anchors
|
||||||
|
if(!anchor.getHookedWidget())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// the update should only happens if the hooked widget is already updated
|
||||||
|
if(!anchor.getHookedWidget()->m_layoutUpdated)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect newRect = m_rect;
|
||||||
|
bool verticalMoved = false;
|
||||||
|
bool horizontalMoved = false;
|
||||||
|
|
||||||
|
// calculate new rect based on anchors
|
||||||
|
for(const UIAnchor& anchor : m_anchors) {
|
||||||
|
int point = anchor.getHookedPoint();
|
||||||
|
|
||||||
|
// ignore invalid anchors
|
||||||
|
if(point == UIAnchor::INVALID_POINT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch(anchor.getAnchoredEdge()) {
|
||||||
|
case AnchorHorizontalCenter:
|
||||||
|
newRect.moveHorizontalCenter(point + getMarginLeft() - getMarginRight());
|
||||||
|
horizontalMoved = true;
|
||||||
|
break;
|
||||||
|
case AnchorLeft:
|
||||||
|
if(!horizontalMoved) {
|
||||||
|
newRect.moveLeft(point + getMarginLeft());
|
||||||
|
horizontalMoved = true;
|
||||||
|
} else
|
||||||
|
newRect.setLeft(point + getMarginLeft());
|
||||||
|
break;
|
||||||
|
case AnchorRight:
|
||||||
|
if(!horizontalMoved) {
|
||||||
|
newRect.moveRight(point - getMarginRight());
|
||||||
|
horizontalMoved = true;
|
||||||
|
} else
|
||||||
|
newRect.setRight(point - getMarginRight());
|
||||||
|
break;
|
||||||
|
case AnchorVerticalCenter:
|
||||||
|
newRect.moveVerticalCenter(point + getMarginTop() - getMarginBottom());
|
||||||
|
verticalMoved = true;
|
||||||
|
break;
|
||||||
|
case AnchorTop:
|
||||||
|
if(!verticalMoved) {
|
||||||
|
newRect.moveTop(point + getMarginTop());
|
||||||
|
verticalMoved = true;
|
||||||
|
} else
|
||||||
|
newRect.setTop(point + getMarginTop());
|
||||||
|
break;
|
||||||
|
case AnchorBottom:
|
||||||
|
if(!verticalMoved) {
|
||||||
|
newRect.moveBottom(point - getMarginBottom());
|
||||||
|
verticalMoved = true;
|
||||||
|
} else
|
||||||
|
newRect.setBottom(point - getMarginBottom());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_layoutUpdated = true;
|
||||||
|
|
||||||
|
// changes the rect only if really needed
|
||||||
|
if(newRect != m_rect) {
|
||||||
|
// setRect will update children layout too
|
||||||
|
setRect(newRect);
|
||||||
|
} else {
|
||||||
|
// update children
|
||||||
|
internalUpdateChildrenLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::internalUpdateChildrenLayout()
|
||||||
|
{
|
||||||
|
assert(!m_destroyed);
|
||||||
|
|
||||||
|
// reset all children anchors update state
|
||||||
|
resetLayoutUpdateState(false);
|
||||||
|
|
||||||
|
// update children layouts
|
||||||
|
for(const UIWidgetWeakPtr& anchoredWidgetWeak : m_anchoredWidgets) {
|
||||||
|
if(UIWidgetPtr anchoredWidget = anchoredWidgetWeak.lock())
|
||||||
|
anchoredWidget->updateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::resetLayoutUpdateState(bool resetOwn)
|
||||||
|
{
|
||||||
|
if(resetOwn)
|
||||||
|
m_layoutUpdated = false;
|
||||||
|
|
||||||
|
// resets children layout update state too
|
||||||
|
for(const UIWidgetWeakPtr& anchoredWidgetWeak : m_anchoredWidgets) {
|
||||||
|
if(UIWidgetPtr anchoredWidget = anchoredWidgetWeak.lock())
|
||||||
|
anchoredWidget->resetLayoutUpdateState(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::addAnchoredWidget(const UIWidgetPtr& widget)
|
||||||
|
{
|
||||||
|
// prevent duplicated anchored widgets
|
||||||
|
for(const UIWidgetWeakPtr& anchoredWidget : m_anchoredWidgets)
|
||||||
|
if(anchoredWidget.lock() == widget)
|
||||||
|
return;
|
||||||
|
m_anchoredWidgets.push_back(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::recalculateAnchoredWidgets()
|
||||||
|
{
|
||||||
|
clearAnchoredWidgets();
|
||||||
|
computeAnchoredWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::clearAnchoredWidgets()
|
||||||
|
{
|
||||||
|
m_anchoredWidgets.clear();
|
||||||
|
for(const UIWidgetPtr& child : m_children)
|
||||||
|
child->clearAnchoredWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIWidget::computeAnchoredWidgets()
|
||||||
|
{
|
||||||
|
// update anchors's hooked widget
|
||||||
|
for(UIAnchor& anchor : m_anchors) {
|
||||||
|
UIWidgetPtr hookedWidget = backwardsGetWidgetById(anchor.getHookedWidgetId());
|
||||||
|
anchor.setHookedWidget(hookedWidget);
|
||||||
|
if(hookedWidget)
|
||||||
|
hookedWidget->addAnchoredWidget(asUIWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const UIWidgetPtr& child : m_children)
|
||||||
|
child->computeAnchoredWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWidget::onFocusChange(UIFocusEvent& event)
|
void UIWidget::onFocusChange(UIFocusEvent& event)
|
||||||
|
@ -726,7 +892,7 @@ void UIWidget::onMousePress(UIMouseEvent& event)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// mouse press events only go to children that contains the mouse position
|
// mouse press events only go to children that contains the mouse position
|
||||||
if(child->getGeometry().contains(event.pos()) && child == getChildByPos(event.pos())) {
|
if(child->getRect().contains(event.pos()) && child == getChildByPos(event.pos())) {
|
||||||
// focus it
|
// focus it
|
||||||
if(child->isFocusable())
|
if(child->isFocusable())
|
||||||
focusChild(child, MouseFocusReason);
|
focusChild(child, MouseFocusReason);
|
||||||
|
@ -775,7 +941,7 @@ void UIWidget::onMouseMove(UIMouseEvent& event)
|
||||||
|
|
||||||
// check if the mouse is relally over this child
|
// check if the mouse is relally over this child
|
||||||
bool overChild = (isHovered() &&
|
bool overChild = (isHovered() &&
|
||||||
child->getGeometry().contains(event.pos()) &&
|
child->getRect().contains(event.pos()) &&
|
||||||
child == getChildByPos(event.pos()));
|
child == getChildByPos(event.pos()));
|
||||||
if(overChild != child->isHovered()) {
|
if(overChild != child->isHovered()) {
|
||||||
child->setHovered(overChild);
|
child->setHovered(overChild);
|
||||||
|
@ -806,7 +972,7 @@ void UIWidget::onMouseWheel(UIMouseEvent& event)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// mouse wheel events only go to children that contains the mouse position
|
// mouse wheel events only go to children that contains the mouse position
|
||||||
if(child->getGeometry().contains(event.pos()) && child == getChildByPos(event.pos())) {
|
if(child->getRect().contains(event.pos()) && child == getChildByPos(event.pos())) {
|
||||||
event.accept();
|
event.accept();
|
||||||
child->onMouseWheel(event);
|
child->onMouseWheel(event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,34 +27,30 @@ public:
|
||||||
/// Draw widget on screen
|
/// Draw widget on screen
|
||||||
virtual void render();
|
virtual void render();
|
||||||
|
|
||||||
/// Notifies the layout system that this widget has changed and may need to change geometry
|
|
||||||
void updateGeometry();
|
|
||||||
|
|
||||||
void setEnabled(bool enable) { m_enabled = enable; }
|
void setEnabled(bool enable) { m_enabled = enable; }
|
||||||
void setLayout(const UILayoutPtr& layout) { m_layout = layout; }
|
|
||||||
void setId(const std::string& id) { m_id = id; }
|
void setId(const std::string& id) { m_id = id; }
|
||||||
void setFocusable(bool focusable) { m_focusable = focusable; }
|
void setFocusable(bool focusable) { m_focusable = focusable; }
|
||||||
void setHovered(bool hovered) { m_hovered = hovered; }
|
void setHovered(bool hovered) { m_hovered = hovered; }
|
||||||
void setVisible(bool visible) { m_visible = visible; }
|
void setVisible(bool visible) { m_visible = visible; }
|
||||||
void setParent(const UIWidgetPtr& parent);
|
void setParent(const UIWidgetPtr& parent);
|
||||||
void setStyle(const std::string& styleName);
|
void setStyle(const std::string& styleName);
|
||||||
void setGeometry(const Rect& rect);
|
void setRect(const Rect& rect);
|
||||||
void setX(int x) { move(Point(x, getY())); }
|
void setX(int x) { move(Point(x, getY())); }
|
||||||
void setY(int y) { move(Point(getX(), y)); }
|
void setY(int y) { move(Point(getX(), y)); }
|
||||||
void setWidth(int width) { resize(Size(width, getHeight())); }
|
void setWidth(int width) { resize(Size(width, getHeight())); }
|
||||||
void setHeight(int height) { resize(Size(getWidth(), height)); }
|
void setHeight(int height) { resize(Size(getWidth(), height)); }
|
||||||
void resize(const Size& size) { setGeometry(Rect(getPosition(), size)); updateGeometry(); }
|
void resize(const Size& size) { setRect(Rect(getPosition(), size)); }
|
||||||
void move(const Point& pos) { setGeometry(Rect(pos, getSize())); }
|
void move(const Point& pos) { setRect(Rect(pos, getSize())); }
|
||||||
|
|
||||||
void setImage(const ImagePtr& image) { m_image = image; }
|
void setImage(const ImagePtr& image) { m_image = image; }
|
||||||
virtual void setFont(const FontPtr& font) { m_font = font; }
|
virtual void setFont(const FontPtr& font) { m_font = font; }
|
||||||
void setOpacity(int opacity) { m_opacity = opacity; }
|
void setOpacity(int opacity) { m_opacity = opacity; }
|
||||||
void setBackgroundColor(const Color& color) { m_backgroundColor = color; }
|
void setBackgroundColor(const Color& color) { m_backgroundColor = color; }
|
||||||
void setForegroundColor(const Color& color) { m_foregroundColor = color; }
|
void setForegroundColor(const Color& color) { m_foregroundColor = color; }
|
||||||
void setMarginLeft(int margin) { m_marginLeft = margin; updateGeometry(); }
|
void setMarginLeft(int margin) { m_marginLeft = margin; updateLayout(); }
|
||||||
void setMarginRight(int margin) { m_marginRight = margin; updateGeometry(); }
|
void setMarginRight(int margin) { m_marginRight = margin; updateLayout(); }
|
||||||
void setMarginTop(int margin) { m_marginTop = margin; updateGeometry(); }
|
void setMarginTop(int margin) { m_marginTop = margin; updateLayout(); }
|
||||||
void setMarginBottom(int margin) { m_marginBottom = margin; updateGeometry(); }
|
void setMarginBottom(int margin) { m_marginBottom = margin; updateLayout(); }
|
||||||
|
|
||||||
void hide() { setVisible(false); }
|
void hide() { setVisible(false); }
|
||||||
void show() { setVisible(true); }
|
void show() { setVisible(true); }
|
||||||
|
@ -72,13 +68,13 @@ public:
|
||||||
bool hasChild(const UIWidgetPtr& child);
|
bool hasChild(const UIWidgetPtr& child);
|
||||||
|
|
||||||
UIWidgetType getWidgetType() const { return m_type; }
|
UIWidgetType getWidgetType() const { return m_type; }
|
||||||
UILayoutPtr getLayout() const;
|
|
||||||
std::string getId() const { return m_id; }
|
std::string getId() const { return m_id; }
|
||||||
int getChildCount() const { return m_children.size(); }
|
int getChildCount() const { return m_children.size(); }
|
||||||
UIWidgetPtr getParent() const { return m_parent.lock(); }
|
UIWidgetPtr getParent() const { return m_parent.lock(); }
|
||||||
|
UIWidgetPtr getRootParent();
|
||||||
Point getPosition() const { return m_rect.topLeft(); }
|
Point getPosition() const { return m_rect.topLeft(); }
|
||||||
Size getSize() const { return m_rect.size(); }
|
Size getSize() const { return m_rect.size(); }
|
||||||
Rect getGeometry() const { return m_rect; }
|
Rect getRect() const { return m_rect; }
|
||||||
int getX() const { return m_rect.x(); }
|
int getX() const { return m_rect.x(); }
|
||||||
int getY() const { return m_rect.y(); }
|
int getY() const { return m_rect.y(); }
|
||||||
int getWidth() const { return m_rect.width(); }
|
int getWidth() const { return m_rect.width(); }
|
||||||
|
@ -101,7 +97,7 @@ public:
|
||||||
UIWidgetPtr getChildById(const std::string& childId);
|
UIWidgetPtr getChildById(const std::string& childId);
|
||||||
UIWidgetPtr getChildByPos(const Point& childPos);
|
UIWidgetPtr getChildByPos(const Point& childPos);
|
||||||
UIWidgetPtr getChildByIndex(int childIndex);
|
UIWidgetPtr getChildByIndex(int childIndex);
|
||||||
UIWidgetPtr recursiveGetChildById(const std::string& childId);
|
UIWidgetPtr recursiveGetChildById(const std::string& id);
|
||||||
UIWidgetPtr recursiveGetChildByPos(const Point& childPos);
|
UIWidgetPtr recursiveGetChildByPos(const Point& childPos);
|
||||||
UIWidgetPtr backwardsGetWidgetById(const std::string& id);
|
UIWidgetPtr backwardsGetWidgetById(const std::string& id);
|
||||||
|
|
||||||
|
@ -114,16 +110,33 @@ public:
|
||||||
void lockChild(const UIWidgetPtr& childToLock);
|
void lockChild(const UIWidgetPtr& childToLock);
|
||||||
void unlockChild(const UIWidgetPtr& childToUnlock);
|
void unlockChild(const UIWidgetPtr& childToUnlock);
|
||||||
|
|
||||||
// for using only with anchor layouts
|
void updateLayout();
|
||||||
void addAnchor(AnchorPoint edge, const std::string& targetId, AnchorPoint targetEdge);
|
void updateChildrenLayout();
|
||||||
void centerIn(const std::string& targetId);
|
|
||||||
void fill(const std::string& targetId);
|
bool addAnchor(AnchorEdge edge, const std::string& hookedWidgetId, AnchorEdge hookedEdge);
|
||||||
|
void centerIn(const std::string& hookedWidgetId);
|
||||||
|
void fill(const std::string& hookedWidgetId);
|
||||||
|
|
||||||
UIWidgetPtr asUIWidget() { return std::static_pointer_cast<UIWidget>(shared_from_this()); }
|
UIWidgetPtr asUIWidget() { return std::static_pointer_cast<UIWidget>(shared_from_this()); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void internalUpdateLayout();
|
||||||
|
void internalUpdateChildrenLayout();
|
||||||
|
|
||||||
|
void addAnchoredWidget(const UIWidgetPtr& widget);
|
||||||
|
void recalculateAnchoredWidgets();
|
||||||
|
void clearAnchoredWidgets();
|
||||||
|
void computeAnchoredWidgets();
|
||||||
|
void resetLayoutUpdateState(bool resetOwn);
|
||||||
|
|
||||||
|
bool m_layoutUpdated;
|
||||||
|
bool m_updateEventScheduled;
|
||||||
|
bool m_layoutUpdateScheduled;
|
||||||
|
bool m_childrenLayoutUpdateScheduled;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Triggered when widget is moved or resized
|
/// Triggered when widget is moved or resized
|
||||||
virtual void onGeometryUpdate(UIGeometryUpdateEvent& event) { }
|
virtual void onRectUpdate(UIRectUpdateEvent& event) { }
|
||||||
// Triggered when widget change visibility/enabled/style/children/parent/layout/...
|
// Triggered when widget change visibility/enabled/style/children/parent/layout/...
|
||||||
//virtual void onChange(const UIEvent& event);
|
//virtual void onChange(const UIEvent& event);
|
||||||
/// Triggered when widget gets or loses focus
|
/// Triggered when widget gets or loses focus
|
||||||
|
@ -155,9 +168,9 @@ protected:
|
||||||
bool m_hovered;
|
bool m_hovered;
|
||||||
bool m_focusable;
|
bool m_focusable;
|
||||||
bool m_destroyed;
|
bool m_destroyed;
|
||||||
bool m_updateScheduled;
|
|
||||||
Rect m_rect;
|
Rect m_rect;
|
||||||
UILayoutPtr m_layout;
|
UIAnchorList m_anchors;
|
||||||
|
UIWeakWidgetList m_anchoredWidgets;
|
||||||
UIWidgetWeakPtr m_parent;
|
UIWidgetWeakPtr m_parent;
|
||||||
UIWidgetList m_children;
|
UIWidgetList m_children;
|
||||||
UIWidgetList m_lockedWidgets;
|
UIWidgetList m_lockedWidgets;
|
||||||
|
|
|
@ -42,7 +42,7 @@ void UIWindow::loadStyleFromOTML(const OTMLNodePtr& styleNode)
|
||||||
void UIWindow::render()
|
void UIWindow::render()
|
||||||
{
|
{
|
||||||
// draw window head
|
// draw window head
|
||||||
Rect headRect = getGeometry();
|
Rect headRect = getRect();
|
||||||
headRect.setHeight(m_headHeight);
|
headRect.setHeight(m_headHeight);
|
||||||
|
|
||||||
if(m_headImage && m_headHeight > 0) {
|
if(m_headImage && m_headHeight > 0) {
|
||||||
|
@ -58,7 +58,7 @@ void UIWindow::render()
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw window body
|
// draw window body
|
||||||
Rect bodyRect = getGeometry();
|
Rect bodyRect = getRect();
|
||||||
bodyRect.setTop(headRect.bottom() + 1);
|
bodyRect.setTop(headRect.bottom() + 1);
|
||||||
if(m_bodyImage)
|
if(m_bodyImage)
|
||||||
m_bodyImage->draw(bodyRect);
|
m_bodyImage->draw(bodyRect);
|
||||||
|
@ -67,13 +67,13 @@ void UIWindow::render()
|
||||||
UIWidget::render();
|
UIWidget::render();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWindow::onGeometryUpdate(UIGeometryUpdateEvent& event)
|
void UIWindow::onRectUpdate(UIRectUpdateEvent& event)
|
||||||
{
|
{
|
||||||
// bind window rect to parent rect
|
// bind window rect to parent rect
|
||||||
Rect boundRect = event.rect();
|
Rect boundRect = event.rect();
|
||||||
UIWidgetPtr parent = getParent();
|
UIWidgetPtr parent = getParent();
|
||||||
if(parent) {
|
if(parent) {
|
||||||
Rect parentRect = parent->getGeometry();
|
Rect parentRect = parent->getRect();
|
||||||
if(boundRect.left() < parentRect.left())
|
if(boundRect.left() < parentRect.left())
|
||||||
boundRect.moveLeft(parentRect.left());
|
boundRect.moveLeft(parentRect.left());
|
||||||
if(boundRect.top() < parentRect.top())
|
if(boundRect.top() < parentRect.top())
|
||||||
|
@ -85,7 +85,7 @@ void UIWindow::onGeometryUpdate(UIGeometryUpdateEvent& event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(boundRect != event.rect())
|
if(boundRect != event.rect())
|
||||||
setGeometry(boundRect);
|
setRect(boundRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWindow::onFocusChange(UIFocusEvent& event)
|
void UIWindow::onFocusChange(UIFocusEvent& event)
|
||||||
|
@ -97,11 +97,11 @@ void UIWindow::onFocusChange(UIFocusEvent& event)
|
||||||
|
|
||||||
void UIWindow::onMousePress(UIMouseEvent& event)
|
void UIWindow::onMousePress(UIMouseEvent& event)
|
||||||
{
|
{
|
||||||
Rect headRect = getGeometry();
|
Rect headRect = getRect();
|
||||||
headRect.setHeight(m_headHeight);
|
headRect.setHeight(m_headHeight);
|
||||||
if(headRect.contains(event.pos())) {
|
if(headRect.contains(event.pos())) {
|
||||||
m_moving = true;
|
m_moving = true;
|
||||||
m_movingReference = event.pos() - getGeometry().topLeft();
|
m_movingReference = event.pos() - getRect().topLeft();
|
||||||
} else
|
} else
|
||||||
UIWidget::onMousePress(event);
|
UIWidget::onMousePress(event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ public:
|
||||||
std::string getTitle() const { return m_title; }
|
std::string getTitle() const { return m_title; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onGeometryUpdate(UIGeometryUpdateEvent& event);
|
virtual void onRectUpdate(UIRectUpdateEvent& event);
|
||||||
virtual void onFocusChange(UIFocusEvent& event);
|
virtual void onFocusChange(UIFocusEvent& event);
|
||||||
virtual void onMousePress(UIMouseEvent& event);
|
virtual void onMousePress(UIMouseEvent& event);
|
||||||
virtual void onMouseRelease(UIMouseEvent& event);
|
virtual void onMouseRelease(UIMouseEvent& event);
|
||||||
|
|
|
@ -25,7 +25,7 @@ AlignmentFlag fw::translateAlignment(std::string aligment)
|
||||||
return AlignCenter;
|
return AlignCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnchorPoint fw::translateAnchorPoint(const std::string& anchorPoint)
|
AnchorEdge fw::translateAnchorEdge(const std::string& anchorPoint)
|
||||||
{
|
{
|
||||||
if(anchorPoint == "left")
|
if(anchorPoint == "left")
|
||||||
return AnchorLeft;
|
return AnchorLeft;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
namespace fw {
|
namespace fw {
|
||||||
|
|
||||||
AlignmentFlag translateAlignment(std::string aligment);
|
AlignmentFlag translateAlignment(std::string aligment);
|
||||||
AnchorPoint translateAnchorPoint(const std::string& anchorPoint);
|
AnchorEdge translateAnchorEdge(const std::string& anchorPoint);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue