ui anchoring

master
Eduardo Bart 13 years ago
parent e94024de67
commit a5cd0bed74

@ -33,8 +33,6 @@
#include "net/connections.h"
#include "ui/uicontainer.h"
#define MINIMUN_UPDATE_DELAY 50
Engine g_engine;
void Engine::init()
@ -57,17 +55,11 @@ void Engine::terminate()
void Engine::run()
{
int ticks = Platform::getTicks();
int lastUpdateTicks = ticks;
int lastFpsTicks = ticks;
int updateElapsedTicks = ticks;
int frameCount = 0;
int fps = 0;
m_running = true;
// before redering do the first update
update(ticks, 0);
lastUpdateTicks = ticks;
while(!m_stopping) {
// poll platform events
Platform::poll();
@ -75,18 +67,11 @@ void Engine::run()
// poll network events
g_connections.poll();
// update before redering
ticks = Platform::getTicks();
// poll diaptcher tasks
g_dispatcher.poll(ticks);
updateElapsedTicks = ticks - lastUpdateTicks;
if(updateElapsedTicks >= MINIMUN_UPDATE_DELAY) {
update(ticks, updateElapsedTicks);
lastUpdateTicks = ticks;
}
// render only when visible
if(Platform::isWindowVisible()) {
// calculate and fps
@ -140,13 +125,6 @@ void Engine::render()
g_graphics.endRender();
}
void Engine::update(int ticks, int elapsedTicks)
{
if(m_currentState)
m_currentState->update(ticks, elapsedTicks);
g_ui->update(ticks, elapsedTicks);
}
void Engine::onClose()
{
if(m_currentState)
@ -156,7 +134,7 @@ void Engine::onClose()
void Engine::onResize(const Size& size)
{
g_graphics.resize(size);
g_ui->resize(size);
g_ui->setSize(size);
if(m_currentState)
m_currentState->onResize(size);

@ -68,8 +68,6 @@ public:
private:
/// Called to render every frame
void render();
/// Called between renders
void update(int ticks, int elapsedTicks);
bool m_stopping;
bool m_running;

@ -43,7 +43,6 @@ public:
virtual void onResize(const Size& size) = 0;
virtual void render() = 0;
virtual void update(int ticks, int elapsedTicks) = 0;
};
#endif // GAMESTATE_H

@ -72,7 +72,7 @@ namespace Platform
void swapBuffers();
/// Get the app user directory, the place to save files configurations files
const char *getAppUserDir();
std::string getAppUserDir();
}
#endif // PLATFORM_H

@ -54,6 +54,8 @@ public:
inline T top() const { return y1; }
inline T right() const { return x2; }
inline T bottom() const { return y2; }
inline T horizontalCenter() const { return x1 + (x2 - x1)/2; }
inline T verticalCenter() const { return y1 + (y2 - y1)/2; }
inline T x() const { return x1; }
inline T y() const { return y1; }
inline TPoint<T> topLeft() const { return TPoint<T>(x1, y1); }
@ -108,6 +110,16 @@ public:
x2 = x1 + w;
y2 = y1 + h;
}
inline void moveHorizontalCenter(T x) {
T w = x2 - x1;
x1 = x - w/2;
x2 = x1 + w;
}
inline void moveVerticalCenter(T y) {
T h = y2 - y1;
y1 = y - h/2;
y2 = y1 + h;
}
inline bool contains(const TPoint<T> &p, bool insideOnly = false) const {
T l, r;

@ -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(); }
void setId(const std::string& id) { m_id = id; }
const std::string& getId() const { return m_id; }
virtual void setName(const std::string& name) { m_name = name; }
const std::string& getName() const { return m_name; }
void setSize(const Size& size);
Size getSize() { return m_rect.size(); }
virtual void setRect(const Rect& rect) { m_rect = rect; }
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);

@ -351,13 +351,13 @@ bool Platform::isWindowMaximized()
return win32.maximized;
}
const char *Platform::getAppUserDir()
std::string Platform::getAppUserDir()
{
std::stringstream sdir;
sdir << PHYSFS_getUserDir() << "/." << win32.appName << "/";
if((mkdir(sdir.str().c_str()) != 0) && (errno != EEXIST))
logError("Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str());
return sdir.str().c_str();
return sdir.str();
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

@ -826,11 +826,11 @@ bool Platform::isWindowMaximized()
return ret;
}
const char *Platform::getAppUserDir()
std::string Platform::getAppUserDir()
{
std::stringstream sdir;
sdir << PHYSFS_getUserDir() << "/." << x11.appName << "/";
if((mkdir(sdir.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST))
logError("Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str());
return sdir.str().c_str();
return sdir.str();
}

@ -62,7 +62,7 @@ void MenuState::onInputEvent(InputEvent* event)
void MenuState::onResize(const Size& size)
{
recalculateMenuPanelPosition();
}
void MenuState::render()
@ -80,55 +80,52 @@ void MenuState::render()
g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background.get(), texCoords);
}
void MenuState::update(int ticks, int elapsedTicks)
{
}
void MenuState::createMainMenu()
{
UIButtonPtr button;
int y = 16;
int y = 0;
m_menuPanel = UIPanelPtr(new UIPanel);
m_menuPanel->setSkin("roundedGridPanel");
recalculateMenuPanelPosition();
m_menuPanel->anchorLeft(g_ui->left());
m_menuPanel->anchorBottom(g_ui->bottom());
m_menuPanel->setSize(Size(118, 172));
m_menuPanel->setMargin(0, 60, 70, 0);
button = UIButtonPtr(new UIButton("Enter Game"));
button->setRect(Rect(16, y, 86, 20));
button->anchorLeft(m_menuPanel->left());
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 16);
m_menuPanel->addChild(button);
y += 30;
button = UIButtonPtr(new UIButton("Access Account"));
button->setRect(Rect(16, y, 86, 20));
button->anchorLeft(m_menuPanel->left());
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
m_menuPanel->addChild(button);
y += 30;
button = UIButtonPtr(new UIButton("Options"));
button->setRect(Rect(16, y, 86, 20));
button->anchorLeft(m_menuPanel->left());
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
m_menuPanel->addChild(button);
y += 30;
button = UIButtonPtr(new UIButton("Info"));
button->setRect(Rect(16, y, 86, 20));
button->anchorLeft(m_menuPanel->left());
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
m_menuPanel->addChild(button);
y += 30;
button = UIButtonPtr(new UIButton("Exit Game"));
button->setRect(Rect(16, y, 86, 20));
button->anchorLeft(m_menuPanel->left());
button->anchorTop(m_menuPanel->top());
button->anchorHorizontalCenter(m_menuPanel->horizontalCenter());
button->setMargin(y += 30);
m_menuPanel->addChild(button);
y += 30;
g_ui->addChild(m_menuPanel);
}
void MenuState::recalculateMenuPanelPosition()
{
if(m_menuPanel) {
// calculate panel rect
Size panelSize = Size(117, 171);
Rect panelRect = Rect(0, 0, panelSize);
panelRect.moveBottomLeft(Point(60, g_graphics.getScreenSize().height() - 70));
m_menuPanel->setRect(panelRect);
}
}

@ -44,11 +44,9 @@ public:
void onResize(const Size& size);
void render();
void update(int ticks, int elapsedTicks);
private:
void createMainMenu();
void recalculateMenuPanelPosition();
UIPanelPtr m_menuPanel;
TexturePtr m_background;

@ -57,9 +57,3 @@ void TestState::render()
{
}
void TestState::update(int ticks, int elapsedTicks)
{
}

@ -40,7 +40,6 @@ public:
void onResize(const Size& size);
void render();
void update(int ticks, int elapsedTicks);
};
#endif // TESTSTATE_H

Loading…
Cancel
Save