From a5cd0bed740d603e3a24128fd5c2984a4fd96bf1 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 9 Apr 2011 14:18:50 -0300 Subject: [PATCH 1/6] ui anchoring --- src/framework/engine.cpp | 24 +------ src/framework/engine.h | 2 - src/framework/gamestate.h | 1 - src/framework/platform.h | 2 +- src/framework/rect.h | 12 ++++ src/framework/ui/uicontainer.cpp | 55 ++-------------- src/framework/ui/uicontainer.h | 14 ++-- src/framework/ui/uielement.cpp | 106 ++++++++++++++++++++++++++++++- src/framework/ui/uielement.h | 86 ++++++++++++++++++++++--- src/framework/ui/uiskins.cpp | 6 ++ src/framework/ui/uiskins.h | 1 + src/framework/win32platform.cpp | 4 +- src/framework/x11platform.cpp | 4 +- src/menustate.cpp | 55 ++++++++-------- src/menustate.h | 2 - src/teststate.cpp | 6 -- src/teststate.h | 1 - 17 files changed, 239 insertions(+), 142 deletions(-) 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 From 22c4b0976aef286016eca61bf424f0897edf0d5f Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 9 Apr 2011 16:07:35 -0300 Subject: [PATCH 2/6] refator some stuff, button implementation --- CMakeLists.txt | 2 + src/framework/engine.cpp | 2 +- src/framework/engine.h | 2 +- src/framework/gamestate.h | 3 +- src/framework/input.h | 2 + src/framework/ui/uibutton.cpp | 14 +++- src/framework/ui/uibutton.h | 3 + src/framework/ui/uiconstants.h | 2 +- src/framework/ui/uicontainer.cpp | 13 +++- src/framework/ui/uicontainer.h | 2 +- src/framework/ui/uielement.cpp | 110 ++--------------------------- src/framework/ui/uielement.h | 83 +++------------------- src/framework/ui/uielementskin.cpp | 34 +++++---- src/framework/ui/uielementskin.h | 10 ++- src/framework/ui/uiskins.cpp | 13 ++-- src/framework/x11platform.cpp | 8 +-- src/menustate.cpp | 6 +- src/menustate.h | 2 +- src/teststate.cpp | 2 +- src/teststate.h | 2 +- 20 files changed, 91 insertions(+), 224 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d016879..f95f5f23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,8 +73,10 @@ SET(SOURCES src/framework/util.cpp # ui + src/framework/ui/anchorlayout.cpp src/framework/ui/uielement.cpp src/framework/ui/uielementskin.cpp + src/framework/ui/uibuttonskin.cpp src/framework/ui/uicontainer.cpp src/framework/ui/uiskins.cpp src/framework/ui/uipanel.cpp diff --git a/src/framework/engine.cpp b/src/framework/engine.cpp index 0e82e9ed..c89229a1 100644 --- a/src/framework/engine.cpp +++ b/src/framework/engine.cpp @@ -140,7 +140,7 @@ void Engine::onResize(const Size& size) m_currentState->onResize(size); } -void Engine::onInputEvent(InputEvent *event) +void Engine::onInputEvent(const InputEvent& event) { // inputs goest to gui first if(!g_ui->onInputEvent(event)) { diff --git a/src/framework/engine.h b/src/framework/engine.h index 29025430..5a85634f 100644 --- a/src/framework/engine.h +++ b/src/framework/engine.h @@ -60,7 +60,7 @@ public: /// Fired by platform on window resize void onResize(const Size& size); /// Fired by platform on mouse/keyboard input - void onInputEvent(InputEvent *event); + void onInputEvent(const InputEvent& event); /// Enable FPS counter on screen void enableFpsCounter(bool enable = true) { m_calculateFps = enable; }; diff --git a/src/framework/gamestate.h b/src/framework/gamestate.h index 2b007688..37fdd939 100644 --- a/src/framework/gamestate.h +++ b/src/framework/gamestate.h @@ -25,6 +25,7 @@ #ifndef GAMESTATE_H #define GAMESTATE_H +#include "input.h" #include "size.h" struct InputEvent; @@ -39,7 +40,7 @@ public: virtual void onLeave() = 0; virtual void onClose() = 0; - virtual void onInputEvent(InputEvent *event) = 0; + virtual void onInputEvent(const InputEvent& event) = 0; virtual void onResize(const Size& size) = 0; virtual void render() = 0; diff --git a/src/framework/input.h b/src/framework/input.h index 0090852d..4f74b765 100644 --- a/src/framework/input.h +++ b/src/framework/input.h @@ -25,6 +25,8 @@ #ifndef INPUT_H #define INPUT_H +#include "prerequisites.h" + enum EKeyCode { KC_UNKNOWN = 0x00, KC_ESCAPE = 0x01, diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index b246ea28..bea92336 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -30,5 +30,17 @@ void UIButton::render() { UIElement::render(); - g_fonts.get("tibia-8px-antialised")->renderText(m_text, m_rect, ALIGN_CENTER); + g_fonts.get("tibia-8px-antialised")->renderText(m_text, getRect(), ALIGN_CENTER); +} + +bool UIButton::onInputEvent(const InputEvent& event) +{ + if(event.type == EV_MOUSE_LDOWN && + getRect().contains(Point(event.mouse.x, event.mouse.y))) { + m_state = UI::ButtonDown; + } else if(m_state == UI::ButtonDown && + event.type == EV_MOUSE_LUP) { + m_state = UI::ButtonUp; + } + return false; } diff --git a/src/framework/ui/uibutton.h b/src/framework/ui/uibutton.h index 61e27222..acff35a4 100644 --- a/src/framework/ui/uibutton.h +++ b/src/framework/ui/uibutton.h @@ -39,6 +39,9 @@ public: } virtual void render(); + bool onInputEvent(const InputEvent& event); + + UI::EButtonState getState() { return m_state; } private: std::string m_text; diff --git a/src/framework/ui/uiconstants.h b/src/framework/ui/uiconstants.h index 4239240f..16774979 100644 --- a/src/framework/ui/uiconstants.h +++ b/src/framework/ui/uiconstants.h @@ -53,7 +53,7 @@ namespace UI { enum EElementType { - Element, + Element = 0, Container, Panel, Window, diff --git a/src/framework/ui/uicontainer.cpp b/src/framework/ui/uicontainer.cpp index 51e085a2..19821415 100644 --- a/src/framework/ui/uicontainer.cpp +++ b/src/framework/ui/uicontainer.cpp @@ -57,13 +57,20 @@ void UIContainer::render() UIElement::render(); for(auto it = m_children.begin(); it != m_children.end(); ++it) { const UIElementPtr& child = (*it); - child->render(); + if(child->isVisible()) + child->render(); } } -bool UIContainer::onInputEvent(InputEvent* event) +bool UIContainer::onInputEvent(const InputEvent& event) { - return false; + bool ret = false; + for(auto it = m_children.begin(); it != m_children.end(); ++it) { + const UIElementPtr& child = (*it); + if(child->isEnabled() && child->isVisible()) + ret = child->onInputEvent(event) || ret; + } + return ret; } void UIContainer::setActiveElement(UIElementPtr activeElement) diff --git a/src/framework/ui/uicontainer.h b/src/framework/ui/uicontainer.h index 59af838c..0ef14f6f 100644 --- a/src/framework/ui/uicontainer.h +++ b/src/framework/ui/uicontainer.h @@ -41,7 +41,7 @@ public: UIElementPtr getChildById(const std::string& id) const; virtual void render(); - virtual bool onInputEvent(InputEvent *event); + virtual bool onInputEvent(const InputEvent& event); void setActiveElement(UIElementPtr activeElement); UIElementPtr getActiveElement() const { return m_activeElement; } diff --git a/src/framework/ui/uielement.cpp b/src/framework/ui/uielement.cpp index 59aa1e2a..afb01d57 100644 --- a/src/framework/ui/uielement.cpp +++ b/src/framework/ui/uielement.cpp @@ -26,40 +26,15 @@ #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) : + AnchorLayout(), m_type(type), - m_marginLeft(0), - m_marginRight(0), - m_marginTop(0), - m_marginBottom(0) + m_visible(true), + m_enabled(true) { // set default skin - setSkin(g_uiSkins.getElementSkin(type)); + if(type > UI::Container) + setSkin(g_uiSkins.getElementSkin(type)); } @@ -71,7 +46,7 @@ bool UIElement::setSkin(const std::string& skinName) void UIElement::setSkin(UIElementSkin* skin) { - if(skin && !m_rect.isValid()) { + if(skin && !getRect().isValid()) { setSize(skin->getDefaultSize()); } m_skin = skin; @@ -82,76 +57,3 @@ void UIElement::render() if(m_skin) 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 6578c84b..ae3c6014 100644 --- a/src/framework/ui/uielement.h +++ b/src/framework/ui/uielement.h @@ -29,6 +29,7 @@ #include "../input.h" #include "../rect.h" #include "uiconstants.h" +#include "anchorlayout.h" class UIElementSkin; @@ -40,43 +41,14 @@ 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 +class UIElement : public AnchorLayout { public: UIElement(UI::EElementType type = UI::Element); virtual ~UIElement() { } virtual void render(); - virtual bool onInputEvent(InputEvent *event) { return false; } + virtual bool onInputEvent(const InputEvent& event) { return false; } bool setSkin(const std::string& skinName); void setSkin(UIElementSkin *skin); @@ -88,62 +60,23 @@ public: void setId(const std::string& id) { m_id = id; } const std::string& getId() const { return m_id; } - void setSize(const Size& size); - Size getSize() { return m_rect.size(); } - - void setRect(const Rect& rect); - const Rect& getRect() const{ return m_rect; } - - void setActive(bool active) { m_active = active; } - bool isActive() const { return m_active; } + void setEnabled(bool enabled) { m_enabled = enabled; } + bool isEnabled() const { return m_enabled; } 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); + UIElementPtr asUIElement() { return std::static_pointer_cast(shared_from_this()); } +private: UI::EElementType m_type; UIContainerWeakPtr m_parent; UIElementSkin *m_skin; - Rect m_rect; 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; + bool m_enabled; }; #endif // UIELEMENT_H diff --git a/src/framework/ui/uielementskin.cpp b/src/framework/ui/uielementskin.cpp index 2698f0ef..f1f21024 100644 --- a/src/framework/ui/uielementskin.cpp +++ b/src/framework/ui/uielementskin.cpp @@ -30,17 +30,20 @@ void UIElementSkin::draw(UIElement *element) { - const ImagePtr& image = m_stateImages.front(); - if(image) { - image->draw(element->getRect()); - } + if(m_defaultImage) + m_defaultImage->draw(element->getRect()); } void UIElementSkin::load(const YAML::Node& node) { if(node.FindValue("default size")) node["default size"] >> m_defaultSize; + m_defaultImage = loadImage(node); +} +ImagePtr UIElementSkin::loadImage(const YAML::Node& node) +{ + ImagePtr image; if(node.FindValue("bordered image")) { const YAML::Node& child = node["bordered image"]; Rect left, right, top, bottom, topLeft, topRight, bottomLeft, bottomRight, center; @@ -63,16 +66,17 @@ void UIElementSkin::load(const YAML::Node& node) texture = g_uiSkins.getDefaultTexture(); } - ImagePtr image = ImagePtr(new BorderedImage(texture, - left, - right, - top, - bottom, - topLeft, - topRight, - bottomLeft, - bottomRight, - center)); - m_stateImages.push_back(image); + image = ImagePtr(new BorderedImage(texture, + left, + right, + top, + bottom, + topLeft, + topRight, + bottomLeft, + bottomRight, + center)); } + return image; } + diff --git a/src/framework/ui/uielementskin.h b/src/framework/ui/uielementskin.h index 3d456fc5..05b402e3 100644 --- a/src/framework/ui/uielementskin.h +++ b/src/framework/ui/uielementskin.h @@ -39,18 +39,22 @@ public: m_name(name), m_elementType(elementType) { } - void load(const YAML::Node& node); - void draw(UIElement *element); + virtual void load(const YAML::Node& node); + virtual void draw(UIElement *element); const std::string& getName() const { return m_name; } const Size& getDefaultSize() const { return m_defaultSize; } UI::EElementType getElementType() const { return m_elementType; } + ImagePtr getDefaultImage() const { return m_defaultImage; } + +protected: + ImagePtr loadImage(const YAML::Node& node); private: std::string m_name; UI::EElementType m_elementType; Size m_defaultSize; - std::vector m_stateImages; + ImagePtr m_defaultImage; }; #endif // UIELEMENTSKIN_H diff --git a/src/framework/ui/uiskins.cpp b/src/framework/ui/uiskins.cpp index cf9c7e6a..ac6bbfd0 100644 --- a/src/framework/ui/uiskins.cpp +++ b/src/framework/ui/uiskins.cpp @@ -26,6 +26,7 @@ #include "../resources.h" #include "../textures.h" #include "uielementskin.h" +#include "uibuttonskin.h" UISkins g_uiSkins; @@ -61,9 +62,9 @@ bool UISkins::load(const std::string& file) std::string name; it.first() >> name; - UIElementSkin *elementSkin = new UIElementSkin(name, UI::Button); - elementSkin->load(it.second()); - m_elementSkins.push_back(elementSkin); + UIButtonSkin *skin = new UIButtonSkin(name, UI::Button); + skin->load(it.second()); + m_elementSkins.push_back(skin); } } @@ -73,9 +74,9 @@ bool UISkins::load(const std::string& file) std::string name; it.first() >> name; - UIElementSkin *elementSkin = new UIElementSkin(name, UI::Panel); - elementSkin->load(it.second()); - m_elementSkins.push_back(elementSkin); + UIElementSkin *skin = new UIElementSkin(name, UI::Panel); + skin->load(it.second()); + m_elementSkins.push_back(skin); } } } catch (YAML::ParserException& e) { diff --git a/src/framework/x11platform.cpp b/src/framework/x11platform.cpp index ba08f708..a4021596 100644 --- a/src/framework/x11platform.cpp +++ b/src/framework/x11platform.cpp @@ -351,7 +351,7 @@ void Platform::poll() inputEvent.type = EV_TEXT_ENTER; inputEvent.key.keychar = buf[0]; inputEvent.key.keycode = KC_UNKNOWN; - g_engine.onInputEvent(&inputEvent); + g_engine.onInputEvent(inputEvent); } } @@ -364,7 +364,7 @@ void Platform::poll() inputEvent.key.keycode = x11.keyMap[keysym]; inputEvent.type = (event.type == KeyPress) ? EV_KEY_DOWN : EV_KEY_UP; inputEvent.key.keychar = (len > 0) ? buf[0] : 0; - g_engine.onInputEvent(&inputEvent); + g_engine.onInputEvent(inputEvent); } break; } @@ -387,14 +387,14 @@ void Platform::poll() inputEvent.type = EV_MOUSE_WHEEL_DOWN; break; } - g_engine.onInputEvent(&inputEvent); + g_engine.onInputEvent(inputEvent); break; case MotionNotify: inputEvent.type = EV_MOUSE_MOVE; inputEvent.mouse.x = event.xbutton.x; inputEvent.mouse.y = event.xbutton.y; - g_engine.onInputEvent(&inputEvent); + g_engine.onInputEvent(inputEvent); break; case MapNotify: diff --git a/src/menustate.cpp b/src/menustate.cpp index d239523d..c4cf3f74 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -55,7 +55,7 @@ void MenuState::onClose() g_engine.stop(); } -void MenuState::onInputEvent(InputEvent* event) +void MenuState::onInputEvent(const InputEvent& event) { } @@ -93,28 +93,24 @@ void MenuState::createMainMenu() m_menuPanel->setMargin(0, 60, 70, 0); button = UIButtonPtr(new UIButton("Enter Game")); - button->anchorLeft(m_menuPanel->left()); button->anchorTop(m_menuPanel->top()); button->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); button->setMargin(y += 16); m_menuPanel->addChild(button); button = UIButtonPtr(new UIButton("Access Account")); - button->anchorLeft(m_menuPanel->left()); button->anchorTop(m_menuPanel->top()); button->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); button->setMargin(y += 30); m_menuPanel->addChild(button); button = UIButtonPtr(new UIButton("Options")); - button->anchorLeft(m_menuPanel->left()); button->anchorTop(m_menuPanel->top()); button->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); button->setMargin(y += 30); m_menuPanel->addChild(button); button = UIButtonPtr(new UIButton("Info")); - button->anchorLeft(m_menuPanel->left()); button->anchorTop(m_menuPanel->top()); button->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); button->setMargin(y += 30); diff --git a/src/menustate.h b/src/menustate.h index 4791b8b3..686e8569 100644 --- a/src/menustate.h +++ b/src/menustate.h @@ -40,7 +40,7 @@ public: void onLeave(); void onClose(); - void onInputEvent(InputEvent *event); + void onInputEvent(const InputEvent& event); void onResize(const Size& size); void render(); diff --git a/src/teststate.cpp b/src/teststate.cpp index 59d333f8..7cc25f29 100644 --- a/src/teststate.cpp +++ b/src/teststate.cpp @@ -43,7 +43,7 @@ void TestState::onClose() g_engine.stop(); } -void TestState::onInputEvent(InputEvent* event) +void TestState::onInputEvent(const InputEvent& event) { } diff --git a/src/teststate.h b/src/teststate.h index 4b33de8c..aba4aab9 100644 --- a/src/teststate.h +++ b/src/teststate.h @@ -36,7 +36,7 @@ public: void onLeave(); void onClose(); - void onInputEvent(InputEvent *event); + void onInputEvent(const InputEvent& event); void onResize(const Size& size); void render(); From a9a110f44b0a1d10f208e02da99cc4294c7e8ecf Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 9 Apr 2011 16:08:43 -0300 Subject: [PATCH 3/6] missing files --- src/framework/ui/anchorlayout.cpp | 123 ++++++++++++++++++++++++++++++ src/framework/ui/anchorlayout.h | 116 ++++++++++++++++++++++++++++ src/framework/ui/uibuttonskin.cpp | 51 +++++++++++++ src/framework/ui/uibuttonskin.h | 45 +++++++++++ 4 files changed, 335 insertions(+) create mode 100644 src/framework/ui/anchorlayout.cpp create mode 100644 src/framework/ui/anchorlayout.h create mode 100644 src/framework/ui/uibuttonskin.cpp create mode 100644 src/framework/ui/uibuttonskin.h diff --git a/src/framework/ui/anchorlayout.cpp b/src/framework/ui/anchorlayout.cpp new file mode 100644 index 00000000..78739e64 --- /dev/null +++ b/src/framework/ui/anchorlayout.cpp @@ -0,0 +1,123 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "anchorlayout.h" + +int AnchorLine::getPos() const +{ + AnchorLayoutPtr 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; +} + +void AnchorLayout::setSize(const Size& size) +{ + m_rect.setSize(size); + recalculateAnchors(); +} + +void AnchorLayout::setRect(const Rect& rect) +{ + m_rect = rect; + recalculateAnchors(); +} + +void AnchorLayout::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(asAnchorLayout()); + recalculateAnchors(); +} + +void AnchorLayout::addAnchoredElement(AnchorLayoutPtr 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 AnchorLayout::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) { + AnchorLayoutPtr element = (*it).lock(); + if(element) + element->recalculateAnchors(); + } +} diff --git a/src/framework/ui/anchorlayout.h b/src/framework/ui/anchorlayout.h new file mode 100644 index 00000000..96c944d6 --- /dev/null +++ b/src/framework/ui/anchorlayout.h @@ -0,0 +1,116 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef ANCHORLAYOUT_H +#define ANCHORLAYOUT_H + +#include "../prerequisites.h" +#include "../rect.h" +#include "uiconstants.h" + +enum EAnchorType { + ANCHOR_LEFT = 0, + ANCHOR_RIGHT, + ANCHOR_TOP, + ANCHOR_BOTTOM, + ANCHOR_HORIZONTAL_CENTER, + ANCHOR_VERTICAL_CENTER, + ANCHOR_NONE +}; + +class AnchorLayout; +typedef std::shared_ptr AnchorLayoutPtr; +typedef std::weak_ptr AnchorLayoutWeakPtr; + +class AnchorLine +{ +public: + AnchorLine() : m_anchorType(ANCHOR_NONE) { } + AnchorLine(const AnchorLine& other) : + m_relativeElement(other.m_relativeElement), m_anchorType(other.m_anchorType) { } + AnchorLine(AnchorLayoutPtr 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; } + AnchorLayoutPtr getRelativeElement() const { return m_relativeElement.lock(); } + +private: + AnchorLayoutWeakPtr m_relativeElement; + EAnchorType m_anchorType; +}; + +class AnchorLayout : public std::enable_shared_from_this +{ +public: + AnchorLayout() : + m_marginLeft(0), + m_marginRight(0), + m_marginTop(0), + m_marginBottom(0) { } + virtual ~AnchorLayout() { } + + void setSize(const Size& size); + Size getSize() { return m_rect.size(); } + + void setRect(const Rect& rect); + const Rect& getRect() const{ return m_rect; } + + 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(asAnchorLayout(), ANCHOR_LEFT); } + AnchorLine right() { return AnchorLine(asAnchorLayout(), ANCHOR_RIGHT); } + AnchorLine top() { return AnchorLine(asAnchorLayout(), ANCHOR_TOP); } + AnchorLine bottom() { return AnchorLine(asAnchorLayout(), ANCHOR_BOTTOM); } + AnchorLine horizontalCenter() { return AnchorLine(asAnchorLayout(), ANCHOR_HORIZONTAL_CENTER); } + AnchorLine verticalCenter() { return AnchorLine(asAnchorLayout(), 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(); } + + AnchorLayoutPtr asAnchorLayout() { return shared_from_this(); } + +private: + void recalculateAnchors(); + void addAnchoredElement(AnchorLayoutPtr anchoredElement); + + AnchorLine m_anchors[6]; + + Rect m_rect; + int m_marginLeft; + int m_marginRight; + int m_marginTop; + int m_marginBottom; + std::list m_anchoredElements; +}; + +#endif // ANCHORLAYOUT_H diff --git a/src/framework/ui/uibuttonskin.cpp b/src/framework/ui/uibuttonskin.cpp new file mode 100644 index 00000000..8b3d8f88 --- /dev/null +++ b/src/framework/ui/uibuttonskin.cpp @@ -0,0 +1,51 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "uibuttonskin.h" +#include "uibutton.h" + +void UIButtonSkin::draw(UIElement *element) +{ + + UIButton *button = static_cast(element); + + if(button->getState() == UI::ButtonDown && m_buttonDownImage) { + m_buttonDownImage->draw(element->getRect()); + } else if(button->getState() == UI::ButtonMouseOver && m_buttonHoverImage) { + m_buttonHoverImage->draw(element->getRect()); + } else { + UIElementSkin::draw(element); + } +} + +void UIButtonSkin::load(const YAML::Node& node) +{ + UIElementSkin::load(node); + + if(node.FindValue("down state")) + m_buttonDownImage = loadImage(node["down state"]); + + if(node.FindValue("mouse over state")) + m_buttonHoverImage = loadImage(node["mouse over state"]); +} diff --git a/src/framework/ui/uibuttonskin.h b/src/framework/ui/uibuttonskin.h new file mode 100644 index 00000000..268348fa --- /dev/null +++ b/src/framework/ui/uibuttonskin.h @@ -0,0 +1,45 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef UIBUTTONSKIN_H +#define UIBUTTONSKIN_H + +#include "../prerequisites.h" +#include "uiconstants.h" +#include "uielementskin.h" + +class UIButtonSkin : public UIElementSkin +{ +public: + UIButtonSkin(const std::string& name, UI::EElementType elementType) :UIElementSkin(name, elementType) { } + + void load(const YAML::Node& node); + void draw(UIElement *element); + +private: + ImagePtr m_buttonDownImage; + ImagePtr m_buttonHoverImage; +}; + +#endif // UIBUTTONSKIN_H From f2bdc89d8dac1b25ebeb5561a9809c8b7b7740da Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 9 Apr 2011 19:55:58 -0300 Subject: [PATCH 4/6] window ui --- CMakeLists.txt | 2 + src/framework/borderedimage.cpp | 12 ++-- src/framework/font.cpp | 106 ++++++++++++++++++++--------- src/framework/font.h | 9 ++- src/framework/graphics.cpp | 15 ++++ src/framework/texture.cpp | 8 +++ src/framework/texture.h | 1 + src/framework/ui/ui.h | 2 +- src/framework/ui/uibutton.cpp | 2 +- src/framework/ui/uibuttonskin.cpp | 1 - src/framework/ui/uielementskin.cpp | 27 +++++--- src/framework/ui/uiskins.cpp | 13 ++++ src/framework/ui/uiwindow.cpp | 26 +++++++ src/framework/ui/uiwindow.h | 46 +++++++++++++ src/framework/ui/uiwindowskin.cpp | 60 ++++++++++++++++ src/framework/ui/uiwindowskin.h | 48 +++++++++++++ src/main.cpp | 6 +- src/menustate.cpp | 7 +- 18 files changed, 335 insertions(+), 56 deletions(-) create mode 100644 src/framework/ui/uiwindow.cpp create mode 100644 src/framework/ui/uiwindow.h create mode 100644 src/framework/ui/uiwindowskin.cpp create mode 100644 src/framework/ui/uiwindowskin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f95f5f23..0dde949b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,8 @@ SET(SOURCES src/framework/ui/uipanel.cpp src/framework/ui/uibutton.cpp src/framework/ui/uilabel.cpp + src/framework/ui/uiwindow.cpp + src/framework/ui/uiwindowskin.cpp # network src/framework/net/connection.cpp diff --git a/src/framework/borderedimage.cpp b/src/framework/borderedimage.cpp index c43b272e..8fcd2d0b 100644 --- a/src/framework/borderedimage.cpp +++ b/src/framework/borderedimage.cpp @@ -76,8 +76,8 @@ void BorderedImage::setTexCoords(const Rect& left, m_bottomRightCornerTexCoords = bottomRight; m_centerTexCoords = center; - m_cornersSize = Size(topLeft.width() + topRight.width(), - topLeft.height() + bottomLeft.height()); + m_cornersSize = Size(left.width() + right.width(), + top.height() + bottom.height()); } void BorderedImage::draw(const Rect& screenCoords) @@ -93,7 +93,8 @@ void BorderedImage::draw(const Rect& screenCoords) g_graphics._beginTextureRender(m_texture.get()); // first the center - rectCoords = Rect(screenCoords.topLeft() + m_topLeftCornerTexCoords.size().toPoint(), + rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width(), + screenCoords.top() + m_topBorderTexCoords.height(), centerSize); g_graphics._drawRepeatedTexturedRect(rectCoords, m_centerTexCoords, textureSize); @@ -124,7 +125,7 @@ void BorderedImage::draw(const Rect& screenCoords) g_graphics._drawRepeatedTexturedRect(rectCoords, m_leftBorderTexCoords, textureSize); // right - rectCoords = Rect(screenCoords.left() + m_topLeftCornerTexCoords.width() + centerSize.width(), + rectCoords = Rect(screenCoords.left() + m_leftBorderTexCoords.width() + centerSize.width(), screenCoords.top() + m_topRightCornerTexCoords.height(), m_rightBorderTexCoords.width(), centerSize.height()); @@ -132,7 +133,7 @@ void BorderedImage::draw(const Rect& screenCoords) // bottom left corner rectCoords = Rect(screenCoords.left(), - screenCoords.top() + m_topLeftCornerTexCoords.height() + centerSize.height(), + screenCoords.top() + m_topBorderTexCoords.height() + centerSize.height(), m_bottomLeftCornerTexCoords.size()); g_graphics._drawTexturedRect(rectCoords, m_bottomLeftCornerTexCoords, textureSize); @@ -149,5 +150,6 @@ void BorderedImage::draw(const Rect& screenCoords) m_bottomRightCornerTexCoords.size()); g_graphics._drawTexturedRect(rectCoords, m_bottomRightCornerTexCoords, textureSize); + //g_graphics._drawBoundingRect(screenCoords, Color(0xFF00FF00), 1); g_graphics._endTextureRender(); } diff --git a/src/framework/font.cpp b/src/framework/font.cpp index cf4add32..cfb46db3 100644 --- a/src/framework/font.cpp +++ b/src/framework/font.cpp @@ -28,12 +28,47 @@ #include "graphics.h" Font::Font() : - m_lineHeight(14), - m_cursorSize(14), - m_color(0xFFFFFFFF) + m_glyphHeight(10), + m_topMargin(0) { } +void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize) +{ + int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width(); + uchar *texturePixels = m_texture->getPixels(); + + // small AI to auto calculate pixels widths + for(int glyph = 32; glyph< 256; ++glyph) { + Rect glyphCoords(((glyph - 32) % numHorizontalGlyphs) * glyphSize.width(), + ((glyph - 32) / numHorizontalGlyphs) * glyphSize.height(), + glyphSize.width(), + m_glyphHeight); + int width = glyphSize.width(); + for(int x = glyphCoords.left() + 2; x <= glyphCoords.right(); ++x) { + bool allAlpha = true; + + // check if all vertical pixels are alpha + for(int y = glyphCoords.top(); y <= glyphCoords.bottom(); ++y) { + if(texturePixels[(y * m_texture->getSize().width() * 4) + (x*4) + 3] != 0) { + allAlpha = false; + break; + } + } + + // if all pixels were alpha we found the width + if(allAlpha) { + width = x - glyphCoords.left(); + break; + } + } + // store glyph size + m_glyphsSize[glyph].setWidth(width); + } + + delete[] texturePixels; +} + bool Font::load(const std::string& file) { std::string fileContents = g_resources.loadTextFile(file); @@ -45,10 +80,7 @@ bool Font::load(const std::string& file) std::istringstream fin(fileContents); std::string textureName; - int numHorizontalGlyphs; - int firstGlyph; Size glyphSize; - Size textureSize; try { YAML::Parser parser(fin); @@ -56,10 +88,9 @@ bool Font::load(const std::string& file) YAML::Node doc; parser.GetNextDocument(doc); - doc["line height"] >> m_lineHeight; - doc["cursor size"] >> m_cursorSize; - doc["color"] >> m_color; - doc["first glyph"] >> firstGlyph; + doc["glyph height"] >> m_glyphHeight; + doc["glyph spacing"] >> m_glyphSpacing; + doc["top margin"] >> m_topMargin; doc["image glyph size"] >> glyphSize; doc["image"] >> textureName; @@ -69,25 +100,33 @@ bool Font::load(const std::string& file) return false; } - textureSize = m_texture->getSize(); - numHorizontalGlyphs = textureSize.width() / glyphSize.width(); + // set glyphs height + for(int glyph = 32; glyph< 256; ++glyph) { + m_glyphsSize[glyph].setHeight(m_glyphHeight); + } - const YAML::Node& widthsNode = doc["glyph widths"]; - for(auto it = widthsNode.begin(); it != widthsNode.end(); ++it) { - int glyph, glyphWidth; - it.first() >> glyph; - it.second() >> glyphWidth; + calculateGlyphsWidthsAutomatically(glyphSize); - // calculate glyph texture coords - m_glyphsTextureCoords[glyph].setRect(((glyph - firstGlyph) % numHorizontalGlyphs) * glyphSize.width(), - ((glyph - firstGlyph) / numHorizontalGlyphs) * glyphSize.height(), - glyphWidth, - glyphSize.height()); + // read custom widths + if(doc.FindValue("glyph widths")) { + const YAML::Node& widthsNode = doc["glyph widths"]; + for(auto it = widthsNode.begin(); it != widthsNode.end(); ++it) { + int glyph, glyphWidth; + it.first() >> glyph; + it.second() >> glyphWidth; + m_glyphsSize[glyph].setWidth(glyphWidth); + } + } - // store glyph size - m_glyphsSize[glyph].setHeight(glyphSize.height()); - m_glyphsSize[glyph].setWidth(glyphWidth); + // calculate glyphs texture coords + int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width(); + for(int glyph = 32; glyph< 256; ++glyph) { + m_glyphsTextureCoords[glyph].setRect(((glyph - 32) % numHorizontalGlyphs) * glyphSize.width(), + ((glyph - 32) / numHorizontalGlyphs) * glyphSize.height(), + m_glyphsSize[glyph].width(), + m_glyphsSize[glyph].height()); } + } catch (YAML::ParserException& e) { logError("Malformed font file \"%s\"", file.c_str()); return false; @@ -107,6 +146,7 @@ void Font::renderText(const std::string& text, void Font::renderText(const std::string& text, const Rect& screenCoords, int align, + const Color& color, const Point& startInternalPos, bool debug) { @@ -115,7 +155,7 @@ void Font::renderText(const std::string& text, return; // begin texture rendering - g_graphics.setColor(m_color); + g_graphics.setColor(color); g_graphics._beginTextureRender(m_texture.get()); const Size& textureSize = m_texture->getSize(); @@ -189,6 +229,8 @@ void Font::renderText(const std::string& text, // render glyph g_graphics._drawTexturedRect(glyphScreenCoords, glyphTextureCoords, textureSize); + + //g_graphics._drawBoundingRect(glyphScreenCoords, Color(0xFF0000FF)); } // end texture redering @@ -196,7 +238,7 @@ void Font::renderText(const std::string& text, g_graphics.resetColor(); if(debug) - g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00), 1); + g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00)); } Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *textBoxSize) @@ -222,13 +264,13 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size * if(glyph == (uchar)'\n') { lineWidths[++lines] = 0; } else if(glyph >= 32) { - lineWidths[lines] += m_glyphsSize[glyph].width(); + lineWidths[lines] += m_glyphsSize[glyph].width() + m_glyphSpacing.width(); maxLineWidth = std::max(maxLineWidth, lineWidths[lines]); } } } - Point virtualPos; + Point virtualPos(0, m_topMargin); lines = 0; for(i = 0; i < numGlyphs; ++i) { glyph = (int)text[i]; @@ -239,7 +281,7 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size * // new line or first glyph if(glyph == (uchar)'\n' || i == 0) { if(glyph == (uchar)'\n') { - virtualPos.y += m_lineHeight; + virtualPos.y += m_glyphsSize[glyph].height() + m_glyphSpacing.height(); lines++; } @@ -255,13 +297,13 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size * // render only if the glyph is valid if(glyph >= 32 && glyph != (uchar)'\n') { - virtualPos.x += m_glyphsSize[glyph].width(); + virtualPos.x += m_glyphsSize[glyph].width() + m_glyphSpacing.width(); } } if(textBoxSize) { textBoxSize->setWidth(maxLineWidth); - textBoxSize->setHeight(virtualPos.y + m_lineHeight); + textBoxSize->setHeight(virtualPos.y + m_glyphHeight); } return (Point *)glyphsPositions; diff --git a/src/framework/font.h b/src/framework/font.h index 66cc0e00..12d71ee7 100644 --- a/src/framework/font.h +++ b/src/framework/font.h @@ -64,6 +64,7 @@ public: void renderText(const std::string& text, const Rect& screenCoords, int align = ALIGN_TOP_LEFT, + const Color& color = Color(0xFFFFFFFF), const Point& startInternalPos = Point(), bool debug = false); @@ -74,9 +75,11 @@ public: Size calculateTextRectSize(const std::string& text); private: - int m_lineHeight; - int m_cursorSize; - Color m_color; + void calculateGlyphsWidthsAutomatically(const Size& glyphSize); + + int m_glyphHeight; + int m_topMargin; + Size m_glyphSpacing; TexturePtr m_texture; Rect m_glyphsTextureCoords[256]; Size m_glyphsSize[256]; diff --git a/src/framework/graphics.cpp b/src/framework/graphics.cpp index 327eb00a..d44b1923 100644 --- a/src/framework/graphics.cpp +++ b/src/framework/graphics.cpp @@ -148,6 +148,9 @@ void Graphics::_endTextureRender() void Graphics::drawTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& textureCoords) { + if(screenCoords.size().isEmpty()) + return; + glBindTexture(GL_TEXTURE_2D, texture->getTextureId()); glBegin(GL_QUADS); _drawTexturedRect(screenCoords, textureCoords, texture->getSize()); @@ -156,6 +159,9 @@ void Graphics::drawTexturedRect(const Rect& screenCoords, const Texture *texture void Graphics::_drawTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize) { + if(screenCoords.size().isEmpty()) + return; + // rect correction for opengl int right = screenCoords.right() + 1; int bottom = screenCoords.bottom() + 1; @@ -182,6 +188,9 @@ void Graphics::_drawTexturedRect(const Rect& screenCoords, const Rect& textureCo void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const Texture* texture, const Rect& texCoords) { + if(screenCoords.size().isEmpty()) + return; + glBindTexture(GL_TEXTURE_2D, texture->getTextureId()); glBegin(GL_QUADS); _drawRepeatedTexturedRect(screenCoords, texCoords, texture->getSize()); @@ -190,6 +199,9 @@ void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const Texture* void Graphics::_drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize) { + if(screenCoords.size().isEmpty()) + return; + // render many repeated texture rects Rect virtualScreenCoords(0,0,screenCoords.size()); for(int y = 0; y <= virtualScreenCoords.height(); y += textureCoords.height()) { @@ -216,6 +228,9 @@ void Graphics::_drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& t void Graphics::drawColoredRect(const Rect& screenCoords, const Color& color) { + if(screenCoords.size().isEmpty()) + return; + glDisable(GL_TEXTURE_2D); setColor(color); diff --git a/src/framework/texture.cpp b/src/framework/texture.cpp index 3da954a3..ea0bf577 100644 --- a/src/framework/texture.cpp +++ b/src/framework/texture.cpp @@ -72,3 +72,11 @@ void Texture::enableBilinearFilter() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } + +uchar *Texture::getPixels() +{ + uchar *pixels = new uchar[m_size.area()*4]; + glBindTexture(GL_TEXTURE_2D, m_textureId); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + return pixels; +} diff --git a/src/framework/texture.h b/src/framework/texture.h index 495baedb..e80112af 100644 --- a/src/framework/texture.h +++ b/src/framework/texture.h @@ -42,6 +42,7 @@ public: const Size& getSize() const { return m_size; } uint getTextureId() const { return m_textureId; } + uchar *getPixels(); private: uint m_textureId; diff --git a/src/framework/ui/ui.h b/src/framework/ui/ui.h index 2dcb8528..e26fe19e 100644 --- a/src/framework/ui/ui.h +++ b/src/framework/ui/ui.h @@ -29,11 +29,11 @@ #include "uiconstants.h" #include "uielement.h" -#include "uielementskin.h" #include "uicontainer.h" #include "uipanel.h" #include "uibutton.h" #include "uilabel.h" #include "uiskins.h" +#include "uiwindow.h" #endif // UI_H diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index bea92336..decc5d2a 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -30,7 +30,7 @@ void UIButton::render() { UIElement::render(); - g_fonts.get("tibia-8px-antialised")->renderText(m_text, getRect(), ALIGN_CENTER); + g_fonts.get("tibia-8px-antialised")->renderText(m_text, getRect(), ALIGN_CENTER, Color(0xFFEEEEEE)); } bool UIButton::onInputEvent(const InputEvent& event) diff --git a/src/framework/ui/uibuttonskin.cpp b/src/framework/ui/uibuttonskin.cpp index 8b3d8f88..52d48df4 100644 --- a/src/framework/ui/uibuttonskin.cpp +++ b/src/framework/ui/uibuttonskin.cpp @@ -27,7 +27,6 @@ void UIButtonSkin::draw(UIElement *element) { - UIButton *button = static_cast(element); if(button->getState() == UI::ButtonDown && m_buttonDownImage) { diff --git a/src/framework/ui/uielementskin.cpp b/src/framework/ui/uielementskin.cpp index f1f21024..ee83b858 100644 --- a/src/framework/ui/uielementskin.cpp +++ b/src/framework/ui/uielementskin.cpp @@ -47,15 +47,24 @@ ImagePtr UIElementSkin::loadImage(const YAML::Node& node) if(node.FindValue("bordered image")) { const YAML::Node& child = node["bordered image"]; Rect left, right, top, bottom, topLeft, topRight, bottomLeft, bottomRight, center; - child["left border"] >> left; - child["right border"] >> right; - child["top border"] >> top; - child["bottom border"] >> bottom; - child["top left corner"] >> topLeft; - child["top right corner"] >> topRight; - child["bottom left corner"] >> bottomLeft; - child["bottom right corner"] >> bottomRight; - child["center"] >> center; + if(child.FindValue("left border")) + child["left border"] >> left; + if(child.FindValue("right border")) + child["right border"] >> right; + if(child.FindValue("top border")) + child["top border"] >> top; + if(child.FindValue("bottom border")) + child["bottom border"] >> bottom; + if(child.FindValue("top left corner")) + child["top left corner"] >> topLeft; + if(child.FindValue("top right corner")) + child["top right corner"] >> topRight; + if(child.FindValue("bottom left corner")) + child["bottom left corner"] >> bottomLeft; + if(child.FindValue("bottom right corner")) + child["bottom right corner"] >> bottomRight; + if(child.FindValue("center")) + child["center"] >> center; TexturePtr texture; if(child.FindValue("image")) { diff --git a/src/framework/ui/uiskins.cpp b/src/framework/ui/uiskins.cpp index ac6bbfd0..e6d45225 100644 --- a/src/framework/ui/uiskins.cpp +++ b/src/framework/ui/uiskins.cpp @@ -27,6 +27,7 @@ #include "../textures.h" #include "uielementskin.h" #include "uibuttonskin.h" +#include "uiwindowskin.h" UISkins g_uiSkins; @@ -79,6 +80,18 @@ bool UISkins::load(const std::string& file) m_elementSkins.push_back(skin); } } + + { + const YAML::Node& node = doc["windows"]; + for(auto it = node.begin(); it != node.end(); ++it) { + std::string name; + it.first() >> name; + + UIWindowSkin *skin = new UIWindowSkin(name, UI::Window); + skin->load(it.second()); + m_elementSkins.push_back(skin); + } + } } catch (YAML::ParserException& e) { logError("Malformed font file \"%s\"", file.c_str()); return false; diff --git a/src/framework/ui/uiwindow.cpp b/src/framework/ui/uiwindow.cpp new file mode 100644 index 00000000..9648e165 --- /dev/null +++ b/src/framework/ui/uiwindow.cpp @@ -0,0 +1,26 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "uiwindow.h" + diff --git a/src/framework/ui/uiwindow.h b/src/framework/ui/uiwindow.h new file mode 100644 index 00000000..72ac014a --- /dev/null +++ b/src/framework/ui/uiwindow.h @@ -0,0 +1,46 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef UIWINDOW_H +#define UIWINDOW_H + +#include "../prerequisites.h" +#include "uicontainer.h" + +class UIWindow : public UIContainer +{ +public: + UIWindow(const std::string& title) : + UIContainer(UI::Window), + m_title(title) { } + + const std::string& getTitle() const { return m_title; } + +private: + std::string m_title; +}; + +typedef std::shared_ptr UIWindowPtr; + +#endif // UIWINDOW_H diff --git a/src/framework/ui/uiwindowskin.cpp b/src/framework/ui/uiwindowskin.cpp new file mode 100644 index 00000000..e2cfe348 --- /dev/null +++ b/src/framework/ui/uiwindowskin.cpp @@ -0,0 +1,60 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "uiwindowskin.h" +#include "uiwindow.h" +#include "../fonts.h" + +void UIWindowSkin::draw(UIElement* element) +{ + UIElementSkin::draw(element); + + UIWindow *window = static_cast(element); + + Rect headRect = window->getRect(); + Rect bodyRect = window->getRect(); + + headRect.setHeight(m_headHeight); + bodyRect.setTop(headRect.bottom() + 1); + + m_headImage->draw(headRect); + m_titleFont->renderText(window->getTitle(), + headRect, + ALIGN_CENTER, + Color(0xFF8F8F8F)); + + m_bodyImage->draw(bodyRect); +} + +void UIWindowSkin::load(const YAML::Node& node) +{ + UIElementSkin::load(node); + + node["head"]["height"] >> m_headHeight; + m_headImage = loadImage(node["head"]); + m_bodyImage = loadImage(node["body"]); + + std::string fontName; + node["head"]["font"] >> fontName; + m_titleFont = g_fonts.get(fontName); +} diff --git a/src/framework/ui/uiwindowskin.h b/src/framework/ui/uiwindowskin.h new file mode 100644 index 00000000..fc97e2b6 --- /dev/null +++ b/src/framework/ui/uiwindowskin.h @@ -0,0 +1,48 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef UIWINDOWSKIN_H +#define UIWINDOWSKIN_H + +#include "../prerequisites.h" +#include "uiconstants.h" +#include "uielementskin.h" +#include "../font.h" + +class UIWindowSkin : public UIElementSkin +{ +public: + UIWindowSkin(const std::string& name, UI::EElementType elementType) : + UIElementSkin(name, elementType) { } + + void load(const YAML::Node& node); + void draw(UIElement *element); + +private: + ImagePtr m_headImage; + ImagePtr m_bodyImage; + Font *m_titleFont; + int m_headHeight; +}; + +#endif // UIWINDOWSKIN_H diff --git a/src/main.cpp b/src/main.cpp index 1aae7c52..8a383f13 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,8 +52,8 @@ void signal_handler(int sig) void setDefaultConfigs() { // default size - int defWidth = 640; - int defHeight = 480; + int defWidth = 550; + int defHeight = 450; // init on screen center g_configs.setValue("window x", (Platform::getDisplayWidth() - defWidth)/2); @@ -101,7 +101,7 @@ int main(int argc, const char *argv[]) // create the window Platform::createWindow(g_configs.getInteger("window x"), g_configs.getInteger("window y"), g_configs.getInteger("window width"), g_configs.getInteger("window height"), - 640, 480, + 550, 450, g_configs.getBoolean("window maximized")); Platform::setWindowTitle("OTClient"); //Platform::setVsync(); diff --git a/src/menustate.cpp b/src/menustate.cpp index c4cf3f74..12e8105b 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -91,6 +91,7 @@ void MenuState::createMainMenu() m_menuPanel->anchorBottom(g_ui->bottom()); m_menuPanel->setSize(Size(118, 172)); m_menuPanel->setMargin(0, 60, 70, 0); + g_ui->addChild(m_menuPanel); button = UIButtonPtr(new UIButton("Enter Game")); button->anchorTop(m_menuPanel->top()); @@ -123,5 +124,9 @@ void MenuState::createMainMenu() button->setMargin(y += 30); m_menuPanel->addChild(button); - g_ui->addChild(m_menuPanel); + UIWindowPtr window(new UIWindow("Enter Game")); + window->setSize(Size(236, 178)); + window->anchorHorizontalCenter(g_ui->horizontalCenter()); + window->anchorVerticalCenter(g_ui->verticalCenter()); + g_ui->addChild(window); } From 9d1ddf34bfb78a803e44366cfe30d898bd563774 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 9 Apr 2011 21:51:35 -0300 Subject: [PATCH 5/6] basic menu functionallity --- CMakeLists.txt | 2 + src/framework/font.cpp | 11 ++--- src/framework/ui/ui.h | 1 + src/framework/ui/uibutton.cpp | 7 ++- src/framework/ui/uibutton.h | 5 ++ src/framework/ui/uibuttonskin.h | 3 +- src/framework/ui/uiconstants.h | 2 +- src/framework/ui/uilabel.cpp | 22 +++++++++ src/framework/ui/uilabel.h | 15 +++++- src/framework/ui/uiskins.cpp | 31 ++++++++++++- src/framework/ui/uitextedit.cpp | 45 ++++++++++++++++++ src/framework/ui/uitextedit.h | 50 ++++++++++++++++++++ src/framework/ui/uitexteditskin.cpp | 26 +++++++++++ src/framework/ui/uitexteditskin.h | 40 ++++++++++++++++ src/framework/ui/uiwindowskin.h | 4 +- src/menustate.cpp | 71 ++++++++++++++++++++++++++--- 16 files changed, 313 insertions(+), 22 deletions(-) create mode 100644 src/framework/ui/uitextedit.cpp create mode 100644 src/framework/ui/uitextedit.h create mode 100644 src/framework/ui/uitexteditskin.cpp create mode 100644 src/framework/ui/uitexteditskin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dde949b..fb91e8cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,8 @@ SET(SOURCES src/framework/ui/uilabel.cpp src/framework/ui/uiwindow.cpp src/framework/ui/uiwindowskin.cpp + src/framework/ui/uitextedit.cpp + src/framework/ui/uitexteditskin.cpp # network src/framework/net/connection.cpp diff --git a/src/framework/font.cpp b/src/framework/font.cpp index cfb46db3..4192fac6 100644 --- a/src/framework/font.cpp +++ b/src/framework/font.cpp @@ -63,7 +63,7 @@ void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize) } } // store glyph size - m_glyphsSize[glyph].setWidth(width); + m_glyphsSize[glyph].setSize(width, m_glyphHeight); } delete[] texturePixels; @@ -101,8 +101,7 @@ bool Font::load(const std::string& file) } // set glyphs height - for(int glyph = 32; glyph< 256; ++glyph) { - m_glyphsSize[glyph].setHeight(m_glyphHeight); + for(int glyph = 32; glyph < 256; ++glyph) { } calculateGlyphsWidthsAutomatically(glyphSize); @@ -124,7 +123,7 @@ bool Font::load(const std::string& file) m_glyphsTextureCoords[glyph].setRect(((glyph - 32) % numHorizontalGlyphs) * glyphSize.width(), ((glyph - 32) / numHorizontalGlyphs) * glyphSize.height(), m_glyphsSize[glyph].width(), - m_glyphsSize[glyph].height()); + m_glyphHeight); } } catch (YAML::ParserException& e) { @@ -253,7 +252,7 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size * // protect buffer overflow on glyphsPostions int numGlyphs = text.length(); if(numGlyphs > 8192) - logFatal("A text was too long to render!"); + logFatal("could not calculate glyphs positions, text length is > 8192!"); // calculate lines width if((align & ALIGN_RIGHT || align & ALIGN_HORIZONTAL_CENTER) || textBoxSize) { @@ -281,7 +280,7 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size * // new line or first glyph if(glyph == (uchar)'\n' || i == 0) { if(glyph == (uchar)'\n') { - virtualPos.y += m_glyphsSize[glyph].height() + m_glyphSpacing.height(); + virtualPos.y += m_glyphHeight + m_glyphSpacing.height(); lines++; } diff --git a/src/framework/ui/ui.h b/src/framework/ui/ui.h index e26fe19e..27d4d11c 100644 --- a/src/framework/ui/ui.h +++ b/src/framework/ui/ui.h @@ -35,5 +35,6 @@ #include "uilabel.h" #include "uiskins.h" #include "uiwindow.h" +#include "uitextedit.h" #endif // UI_H diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index decc5d2a..25c87a1e 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -38,9 +38,12 @@ bool UIButton::onInputEvent(const InputEvent& event) if(event.type == EV_MOUSE_LDOWN && getRect().contains(Point(event.mouse.x, event.mouse.y))) { m_state = UI::ButtonDown; - } else if(m_state == UI::ButtonDown && - event.type == EV_MOUSE_LUP) { + } else if(m_state == UI::ButtonDown && event.type == EV_MOUSE_LUP) { m_state = UI::ButtonUp; + if(getRect().contains(Point(event.mouse.x, event.mouse.y))) { + if(m_buttonClickCallback) + m_buttonClickCallback(); + } } return false; } diff --git a/src/framework/ui/uibutton.h b/src/framework/ui/uibutton.h index acff35a4..6fc91a4a 100644 --- a/src/framework/ui/uibutton.h +++ b/src/framework/ui/uibutton.h @@ -29,6 +29,8 @@ #include "uielement.h" #include "../borderedimage.h" +typedef std::function Callback; + class UIButton : public UIElement { public: @@ -43,9 +45,12 @@ public: UI::EButtonState getState() { return m_state; } + void onClick(const Callback& callback) { m_buttonClickCallback = callback; } + private: std::string m_text; UI::EButtonState m_state; + Callback m_buttonClickCallback; }; typedef std::shared_ptr UIButtonPtr; diff --git a/src/framework/ui/uibuttonskin.h b/src/framework/ui/uibuttonskin.h index 268348fa..8caaa0d3 100644 --- a/src/framework/ui/uibuttonskin.h +++ b/src/framework/ui/uibuttonskin.h @@ -32,7 +32,8 @@ class UIButtonSkin : public UIElementSkin { public: - UIButtonSkin(const std::string& name, UI::EElementType elementType) :UIElementSkin(name, elementType) { } + UIButtonSkin(const std::string& name) : + UIElementSkin(name, UI::Button) { } void load(const YAML::Node& node); void draw(UIElement *element); diff --git a/src/framework/ui/uiconstants.h b/src/framework/ui/uiconstants.h index 16774979..66d34923 100644 --- a/src/framework/ui/uiconstants.h +++ b/src/framework/ui/uiconstants.h @@ -58,7 +58,7 @@ namespace UI { Panel, Window, Label, - TextBox, + TextEdit, Button, CheckBox }; diff --git a/src/framework/ui/uilabel.cpp b/src/framework/ui/uilabel.cpp index e1cc5048..af7d6dc7 100644 --- a/src/framework/ui/uilabel.cpp +++ b/src/framework/ui/uilabel.cpp @@ -23,4 +23,26 @@ #include "uilabel.h" +#include "../fonts.h" + +UILabel::UILabel(const std::string& text, Font* font) : + UIElement(UI::Label), + m_text(text), + m_font(font) +{ + if(!font) + m_font = g_fonts.get("tibia-10px-antialised"); + setSize(m_font->calculateTextRectSize(text)); +} + +void UILabel::render() +{ + m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF)); +} + +void UILabel::setText(const std::string& text) +{ + setSize(m_font->calculateTextRectSize(text)); + m_text = text; +} diff --git a/src/framework/ui/uilabel.h b/src/framework/ui/uilabel.h index d0deb919..4b2ab7f9 100644 --- a/src/framework/ui/uilabel.h +++ b/src/framework/ui/uilabel.h @@ -28,10 +28,23 @@ #include "../prerequisites.h" #include "uielement.h" +class Font; + class UILabel : public UIElement { public: - UILabel() : UIElement(UI::Label) { } + UILabel(const std::string& text, Font *font = NULL); + + void render(); + + void setText(const std::string& text); + const std::string& getText() const { return m_text; } + +private: + std::string m_text; + Font *m_font; }; +typedef std::shared_ptr UILabelPtr; + #endif // UILABEL_H diff --git a/src/framework/ui/uiskins.cpp b/src/framework/ui/uiskins.cpp index e6d45225..62b72b4b 100644 --- a/src/framework/ui/uiskins.cpp +++ b/src/framework/ui/uiskins.cpp @@ -28,6 +28,7 @@ #include "uielementskin.h" #include "uibuttonskin.h" #include "uiwindowskin.h" +#include "uitexteditskin.h" UISkins g_uiSkins; @@ -63,7 +64,7 @@ bool UISkins::load(const std::string& file) std::string name; it.first() >> name; - UIButtonSkin *skin = new UIButtonSkin(name, UI::Button); + UIElementSkin *skin = new UIButtonSkin(name); skin->load(it.second()); m_elementSkins.push_back(skin); } @@ -87,11 +88,37 @@ bool UISkins::load(const std::string& file) std::string name; it.first() >> name; - UIWindowSkin *skin = new UIWindowSkin(name, UI::Window); + UIElementSkin *skin = new UIWindowSkin(name); skin->load(it.second()); m_elementSkins.push_back(skin); } } + + { + const YAML::Node& node = doc["labels"]; + for(auto it = node.begin(); it != node.end(); ++it) { + std::string name; + it.first() >> name; + + UIElementSkin *skin = new UIElementSkin(name, UI::Label); + skin->load(it.second()); + m_elementSkins.push_back(skin); + } + } + + { + const YAML::Node& node = doc["text edits"]; + for(auto it = node.begin(); it != node.end(); ++it) { + std::string name; + it.first() >> name; + + UIElementSkin *skin = new UITextEditSkin(name); + skin->load(it.second()); + m_elementSkins.push_back(skin); + } + } + + } catch (YAML::ParserException& e) { logError("Malformed font file \"%s\"", file.c_str()); return false; diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp new file mode 100644 index 00000000..9da68902 --- /dev/null +++ b/src/framework/ui/uitextedit.cpp @@ -0,0 +1,45 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "uitextedit.h" +#include "../fonts.h" + +UITextEdit::UITextEdit(Font* font) : + UIElement(UI::TextEdit), + m_font(font) +{ + if(!font) + m_font = g_fonts.get("tibia-10px-antialised"); +} + +void UITextEdit::render() +{ + UIElement::render(); + m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF)); +} + +void UITextEdit::setText(const std::string& text) +{ + m_text = text; +} diff --git a/src/framework/ui/uitextedit.h b/src/framework/ui/uitextedit.h new file mode 100644 index 00000000..7ada3721 --- /dev/null +++ b/src/framework/ui/uitextedit.h @@ -0,0 +1,50 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef UITEXTEDIT_H +#define UITEXTEDIT_H + +#include "../prerequisites.h" +#include "uielement.h" + +class Font; + +class UITextEdit : public UIElement +{ +public: + UITextEdit(Font *font = NULL); + + void render(); + + void setText(const std::string& text); + const std::string& getText() const { return m_text; } + +private: + std::string m_text; + Font *m_font; +}; + +typedef std::shared_ptr UITextEditPtr; + +#endif // UITEXTEDIT_H diff --git a/src/framework/ui/uitexteditskin.cpp b/src/framework/ui/uitexteditskin.cpp new file mode 100644 index 00000000..33d422db --- /dev/null +++ b/src/framework/ui/uitexteditskin.cpp @@ -0,0 +1,26 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "uitexteditskin.h" + diff --git a/src/framework/ui/uitexteditskin.h b/src/framework/ui/uitexteditskin.h new file mode 100644 index 00000000..7e79e2cf --- /dev/null +++ b/src/framework/ui/uitexteditskin.h @@ -0,0 +1,40 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef UITEXTEDITSKIN_H +#define UITEXTEDITSKIN_H + +#include "../prerequisites.h" +#include "uiconstants.h" +#include "uielementskin.h" + +class UITextEditSkin : public UIElementSkin +{ +public: + UITextEditSkin(const std::string& name) : + UIElementSkin(name, UI::TextEdit) { } + +}; + +#endif // UITEXTEDITSKIN_H diff --git a/src/framework/ui/uiwindowskin.h b/src/framework/ui/uiwindowskin.h index fc97e2b6..09f917db 100644 --- a/src/framework/ui/uiwindowskin.h +++ b/src/framework/ui/uiwindowskin.h @@ -32,8 +32,8 @@ class UIWindowSkin : public UIElementSkin { public: - UIWindowSkin(const std::string& name, UI::EElementType elementType) : - UIElementSkin(name, elementType) { } + UIWindowSkin(const std::string& name) : + UIElementSkin(name, UI::Window) { } void load(const YAML::Node& node); void draw(UIElement *element); diff --git a/src/menustate.cpp b/src/menustate.cpp index 12e8105b..15f87328 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -82,7 +82,6 @@ void MenuState::render() void MenuState::createMainMenu() { - UIButtonPtr button; int y = 0; m_menuPanel = UIPanelPtr(new UIPanel); @@ -93,13 +92,14 @@ void MenuState::createMainMenu() m_menuPanel->setMargin(0, 60, 70, 0); g_ui->addChild(m_menuPanel); - button = UIButtonPtr(new UIButton("Enter Game")); - button->anchorTop(m_menuPanel->top()); - button->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); - button->setMargin(y += 16); - m_menuPanel->addChild(button); + // main menu + UIButtonPtr enterGameButton = UIButtonPtr(new UIButton("Enter Game")); + enterGameButton->anchorTop(m_menuPanel->top()); + enterGameButton->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); + enterGameButton->setMargin(y += 16); + m_menuPanel->addChild(enterGameButton); - button = UIButtonPtr(new UIButton("Access Account")); + UIButtonPtr button = UIButtonPtr(new UIButton("Access Account")); button->anchorTop(m_menuPanel->top()); button->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); button->setMargin(y += 30); @@ -122,11 +122,68 @@ void MenuState::createMainMenu() button->anchorTop(m_menuPanel->top()); button->anchorHorizontalCenter(m_menuPanel->horizontalCenter()); button->setMargin(y += 30); + button->onClick([]{ g_engine.stop(); }); m_menuPanel->addChild(button); + // login window UIWindowPtr window(new UIWindow("Enter Game")); window->setSize(Size(236, 178)); window->anchorHorizontalCenter(g_ui->horizontalCenter()); window->anchorVerticalCenter(g_ui->verticalCenter()); + window->setVisible(false); g_ui->addChild(window); + + UILabelPtr label(new UILabel("Account name:")); + label->anchorLeft(window->left()); + label->anchorTop(window->top()); + label->setMargin(18, 33); + window->addChild(label); + + label = UILabelPtr(new UILabel("Password:")); + label->anchorLeft(window->left()); + label->anchorTop(window->top()); + label->setMargin(18, 62); + window->addChild(label); + + label = UILabelPtr(new UILabel("If you don't have\nan account yet:")); + label->anchorLeft(window->left()); + label->anchorTop(window->top()); + label->setMargin(18, 87); + window->addChild(label); + + button = UIButtonPtr(new UIButton("Create Account")); + button->anchorLeft(window->left()); + button->anchorTop(window->top()); + button->setMargin(132, 94); + window->addChild(button); + + button = UIButtonPtr(new UIButton("Ok")); + button->setSize(Size(43, 20)); + button->anchorRight(window->right()); + button->anchorBottom(window->bottom()); + button->setMargin(0, 0, 10, 66); + button->onClick([window]{ window->setVisible(false); }); + window->addChild(button); + + button = UIButtonPtr(new UIButton("Cancel")); + button->setSize(Size(43, 20)); + button->anchorRight(window->right()); + button->anchorBottom(window->bottom()); + button->setMargin(0, 0, 10, 13); + button->onClick([window]{ window->setVisible(false); }); + window->addChild(button); + + UITextEditPtr textEdit(new UITextEdit); + textEdit->anchorRight(window->right()); + textEdit->anchorTop(window->top()); + textEdit->setMargin(32, 0, 0, 18); + window->addChild(textEdit); + + textEdit = UITextEditPtr(new UITextEdit); + textEdit->anchorRight(window->right()); + textEdit->anchorTop(window->top()); + textEdit->setMargin(61, 0, 0, 18); + window->addChild(textEdit); + + enterGameButton->onClick([window] { window->setVisible(true); }); } From 5de660a20ed638e10b91bc40d3299dc189a75b5a Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 9 Apr 2011 22:13:12 -0300 Subject: [PATCH 6/6] fix leaks --- src/framework/ui/uielement.cpp | 1 + src/framework/ui/uielementskin.cpp | 18 +++++++++--------- src/framework/ui/uielementskin.h | 1 + src/framework/ui/uiskins.cpp | 10 +++++++++- src/framework/ui/uiskins.h | 4 +++- src/main.cpp | 5 +++-- src/menustate.cpp | 19 ++++++++++++++++--- 7 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/framework/ui/uielement.cpp b/src/framework/ui/uielement.cpp index afb01d57..052ee849 100644 --- a/src/framework/ui/uielement.cpp +++ b/src/framework/ui/uielement.cpp @@ -29,6 +29,7 @@ UIElement::UIElement(UI::EElementType type) : AnchorLayout(), m_type(type), + m_skin(NULL), m_visible(true), m_enabled(true) { diff --git a/src/framework/ui/uielementskin.cpp b/src/framework/ui/uielementskin.cpp index ee83b858..f5b5928b 100644 --- a/src/framework/ui/uielementskin.cpp +++ b/src/framework/ui/uielementskin.cpp @@ -76,15 +76,15 @@ ImagePtr UIElementSkin::loadImage(const YAML::Node& node) } image = ImagePtr(new BorderedImage(texture, - left, - right, - top, - bottom, - topLeft, - topRight, - bottomLeft, - bottomRight, - center)); + left, + right, + top, + bottom, + topLeft, + topRight, + bottomLeft, + bottomRight, + center)); } return image; } diff --git a/src/framework/ui/uielementskin.h b/src/framework/ui/uielementskin.h index 05b402e3..cd24f39a 100644 --- a/src/framework/ui/uielementskin.h +++ b/src/framework/ui/uielementskin.h @@ -38,6 +38,7 @@ public: UIElementSkin(const std::string& name, UI::EElementType elementType) : m_name(name), m_elementType(elementType) { } + virtual ~UIElementSkin() { } virtual void load(const YAML::Node& node); virtual void draw(UIElement *element); diff --git a/src/framework/ui/uiskins.cpp b/src/framework/ui/uiskins.cpp index 62b72b4b..ee296b0d 100644 --- a/src/framework/ui/uiskins.cpp +++ b/src/framework/ui/uiskins.cpp @@ -32,10 +32,18 @@ UISkins g_uiSkins; -UISkins::~UISkins() +void UISkins::init() +{ + // load default skin + g_uiSkins.load("skins/tibiaskin.yml"); + +} + +void UISkins::terminate() { for(auto it = m_elementSkins.begin(); it != m_elementSkins.end(); ++it) delete (*it); + m_elementSkins.clear(); } bool UISkins::load(const std::string& file) diff --git a/src/framework/ui/uiskins.h b/src/framework/ui/uiskins.h index 3d41740c..d240e133 100644 --- a/src/framework/ui/uiskins.h +++ b/src/framework/ui/uiskins.h @@ -35,7 +35,9 @@ class UISkins { public: UISkins() { } - ~UISkins(); + + void init(); + void terminate(); bool load(const std::string& file); diff --git a/src/main.cpp b/src/main.cpp index 8a383f13..0badcbe1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -109,8 +109,7 @@ int main(int argc, const char *argv[]) // init engine g_engine.init(); - // load UI skin - g_uiSkins.load("skins/tibiaskin.yml"); + g_uiSkins.init(); // state scope { @@ -129,6 +128,8 @@ int main(int argc, const char *argv[]) // terminate stuff g_engine.terminate(); + + g_uiSkins.terminate(); } // save configurations before exiting diff --git a/src/menustate.cpp b/src/menustate.cpp index 15f87328..a89373d0 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -127,6 +127,7 @@ void MenuState::createMainMenu() // login window UIWindowPtr window(new UIWindow("Enter Game")); + UIElementWeakPtr weakWindow(window); window->setSize(Size(236, 178)); window->anchorHorizontalCenter(g_ui->horizontalCenter()); window->anchorVerticalCenter(g_ui->verticalCenter()); @@ -162,7 +163,11 @@ void MenuState::createMainMenu() button->anchorRight(window->right()); button->anchorBottom(window->bottom()); button->setMargin(0, 0, 10, 66); - button->onClick([window]{ window->setVisible(false); }); + button->onClick([weakWindow]{ + UIElementPtr window = weakWindow.lock(); + if(window) + window->setVisible(false); + }); window->addChild(button); button = UIButtonPtr(new UIButton("Cancel")); @@ -170,7 +175,11 @@ void MenuState::createMainMenu() button->anchorRight(window->right()); button->anchorBottom(window->bottom()); button->setMargin(0, 0, 10, 13); - button->onClick([window]{ window->setVisible(false); }); + button->onClick([weakWindow]{ + UIElementPtr window = weakWindow.lock(); + if(window) + window->setVisible(false); + }); window->addChild(button); UITextEditPtr textEdit(new UITextEdit); @@ -185,5 +194,9 @@ void MenuState::createMainMenu() textEdit->setMargin(61, 0, 0, 18); window->addChild(textEdit); - enterGameButton->onClick([window] { window->setVisible(true); }); + enterGameButton->onClick([weakWindow]{ + UIElementPtr window = weakWindow.lock(); + if(window) + window->setVisible(true); + }); }