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();