diff --git a/src/framework/engine.cpp b/src/framework/engine.cpp index 87ac4cbb..0e82e9ed 100644 --- a/src/framework/engine.cpp +++ b/src/framework/engine.cpp @@ -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); diff --git a/src/framework/engine.h b/src/framework/engine.h index 7f2063dd..29025430 100644 --- a/src/framework/engine.h +++ b/src/framework/engine.h @@ -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; diff --git a/src/framework/gamestate.h b/src/framework/gamestate.h index ba0ff028..2b007688 100644 --- a/src/framework/gamestate.h +++ b/src/framework/gamestate.h @@ -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 diff --git a/src/framework/platform.h b/src/framework/platform.h index 2e2f1d5e..fb61d8af 100644 --- a/src/framework/platform.h +++ b/src/framework/platform.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 diff --git a/src/framework/rect.h b/src/framework/rect.h index 90857df0..44c12018 100644 --- a/src/framework/rect.h +++ b/src/framework/rect.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 topLeft() const { return TPoint(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 &p, bool insideOnly = false) const { T l, r; diff --git a/src/framework/ui/uicontainer.cpp b/src/framework/ui/uicontainer.cpp index 34de5c7e..51e085a2 100644 --- a/src/framework/ui/uicontainer.cpp +++ b/src/framework/ui/uicontainer.cpp @@ -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; diff --git a/src/framework/ui/uicontainer.h b/src/framework/ui/uicontainer.h index 5629a51d..59af838c 100644 --- a/src/framework/ui/uicontainer.h +++ b/src/framework/ui/uicontainer.h @@ -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; } diff --git a/src/framework/ui/uielement.cpp b/src/framework/ui/uielement.cpp index 24ff0cdb..59aa1e2a 100644 --- a/src/framework/ui/uielement.cpp +++ b/src/framework/ui/uielement.cpp @@ -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(); + } +} diff --git a/src/framework/ui/uielement.h b/src/framework/ui/uielement.h index 37997c3b..6578c84b 100644 --- a/src/framework/ui/uielement.h +++ b/src/framework/ui/uielement.h @@ -29,13 +29,45 @@ #include "../input.h" #include "../rect.h" #include "uiconstants.h" -#include "uielementskin.h" + +class UIElementSkin; class UIContainer; typedef std::shared_ptr UIContainerPtr; +typedef std::weak_ptr UIContainerWeakPtr; class UIElement; typedef std::shared_ptr UIElementPtr; +typedef std::weak_ptr 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 { @@ -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 m_anchoredElements; }; #endif // UIELEMENT_H diff --git a/src/framework/ui/uiskins.cpp b/src/framework/ui/uiskins.cpp index b58d39d5..cf9c7e6a 100644 --- a/src/framework/ui/uiskins.cpp +++ b/src/framework/ui/uiskins.cpp @@ -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); diff --git a/src/framework/ui/uiskins.h b/src/framework/ui/uiskins.h index 6260c6b9..3d41740c 100644 --- a/src/framework/ui/uiskins.h +++ b/src/framework/ui/uiskins.h @@ -35,6 +35,7 @@ class UISkins { public: UISkins() { } + ~UISkins(); bool load(const std::string& file); diff --git a/src/framework/win32platform.cpp b/src/framework/win32platform.cpp index 3606ddcb..a799983c 100644 --- a/src/framework/win32platform.cpp +++ b/src/framework/win32platform.cpp @@ -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) diff --git a/src/framework/x11platform.cpp b/src/framework/x11platform.cpp index 6887249f..ba08f708 100644 --- a/src/framework/x11platform.cpp +++ b/src/framework/x11platform.cpp @@ -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(); } diff --git a/src/menustate.cpp b/src/menustate.cpp index c88eac3f..d239523d 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -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); - } -} \ No newline at end of file diff --git a/src/menustate.h b/src/menustate.h index 74b1ddec..4791b8b3 100644 --- a/src/menustate.h +++ b/src/menustate.h @@ -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; diff --git a/src/teststate.cpp b/src/teststate.cpp index bb8555b2..59d333f8 100644 --- a/src/teststate.cpp +++ b/src/teststate.cpp @@ -57,9 +57,3 @@ void TestState::render() { } - -void TestState::update(int ticks, int elapsedTicks) -{ - -} - diff --git a/src/teststate.h b/src/teststate.h index 7bab44c0..4b33de8c 100644 --- a/src/teststate.h +++ b/src/teststate.h @@ -40,7 +40,6 @@ public: void onResize(const Size& size); void render(); - void update(int ticks, int elapsedTicks); }; #endif // TESTSTATE_H