diff --git a/CMakeLists.txt b/CMakeLists.txt index 7eb1d45b..8d016879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,9 @@ SET(SOURCES # ui src/framework/ui/uielement.cpp + src/framework/ui/uielementskin.cpp src/framework/ui/uicontainer.cpp + src/framework/ui/uiskins.cpp src/framework/ui/uipanel.cpp src/framework/ui/uibutton.cpp src/framework/ui/uilabel.cpp diff --git a/src/framework/engine.cpp b/src/framework/engine.cpp index 4b54b9df..87ac4cbb 100644 --- a/src/framework/engine.cpp +++ b/src/framework/engine.cpp @@ -136,7 +136,7 @@ void Engine::render() g_graphics.beginRender(); if(m_currentState) m_currentState->render(); - g_gui->render(); + g_ui->render(); g_graphics.endRender(); } @@ -144,7 +144,7 @@ void Engine::update(int ticks, int elapsedTicks) { if(m_currentState) m_currentState->update(ticks, elapsedTicks); - g_gui->update(ticks, elapsedTicks); + g_ui->update(ticks, elapsedTicks); } void Engine::onClose() @@ -156,7 +156,7 @@ void Engine::onClose() void Engine::onResize(const Size& size) { g_graphics.resize(size); - g_gui->resize(size); + g_ui->resize(size); if(m_currentState) m_currentState->onResize(size); @@ -165,7 +165,7 @@ void Engine::onResize(const Size& size) void Engine::onInputEvent(InputEvent *event) { // inputs goest to gui first - if(!g_gui->onInputEvent(event)) { + if(!g_ui->onInputEvent(event)) { // if gui didnt capture the input then goes to the state if(m_currentState) m_currentState->onInputEvent(event); diff --git a/src/framework/font.cpp b/src/framework/font.cpp index fc5149b3..cf4add32 100644 --- a/src/framework/font.cpp +++ b/src/framework/font.cpp @@ -36,11 +36,6 @@ Font::Font() : bool Font::load(const std::string& file) { - if(!g_resources.fileExists(file)) { - logError("Font file %s does not exists", file.c_str()); - return false; - } - std::string fileContents = g_resources.loadTextFile(file); if(!fileContents.size()) { logError("Empty font file \"%s", file.c_str()); diff --git a/src/framework/ui/ui.h b/src/framework/ui/ui.h index f2f05011..2dcb8528 100644 --- a/src/framework/ui/ui.h +++ b/src/framework/ui/ui.h @@ -29,9 +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" #endif // UI_H diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index 032ef315..b246ea28 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -26,25 +26,9 @@ #include "../fonts.h" #include "../font.h" -UIButton::UIButton(const std::string& text) : - m_text(text), - m_state(UI::ButtonUp) -{ - m_imageButtonUp = ImagePtr(new BorderedImage("ui.png", - Rect(45,139,1,18), - Rect(130,139,1,18), - Rect(46,138,84,1), - Rect(46,157,84,1), - Rect(45,138,1,1), - Rect(130,138,1,1), - Rect(45,157,1,1), - Rect(130,157,1,1), - Rect(46,139,84,18))); -} - void UIButton::render() { - m_imageButtonUp->draw(m_rect); + UIElement::render(); g_fonts.get("tibia-8px-antialised")->renderText(m_text, m_rect, ALIGN_CENTER); } diff --git a/src/framework/ui/uibutton.h b/src/framework/ui/uibutton.h index 6b3a4750..61e27222 100644 --- a/src/framework/ui/uibutton.h +++ b/src/framework/ui/uibutton.h @@ -32,19 +32,17 @@ class UIButton : public UIElement { public: - UIButton(const std::string& text); + UIButton(const std::string& text) : UIElement(UI::Button), + m_text(text), + m_state(UI::ButtonUp) { + UIElement(); + } - void render(); - - virtual UI::EControlType getControlType() const { return UI::Button; } + virtual void render(); private: std::string m_text; UI::EButtonState m_state; - - ImagePtr m_imageButtonUp; - ImagePtr m_imageButtonDown; - ImagePtr m_imageButtonOver; }; typedef std::shared_ptr UIButtonPtr; diff --git a/src/framework/ui/uiconstants.h b/src/framework/ui/uiconstants.h index b5bf2fd2..4239240f 100644 --- a/src/framework/ui/uiconstants.h +++ b/src/framework/ui/uiconstants.h @@ -51,7 +51,7 @@ namespace UI { MessageBoxYesNo = MessageBoxYes | MessageBoxNo }; - enum EControlType + enum EElementType { Element, Container, diff --git a/src/framework/ui/uicontainer.cpp b/src/framework/ui/uicontainer.cpp index 92fba7c6..34de5c7e 100644 --- a/src/framework/ui/uicontainer.cpp +++ b/src/framework/ui/uicontainer.cpp @@ -24,7 +24,7 @@ #include "uicontainer.h" -UIContainerPtr g_gui(new UIContainer); +UIContainerPtr g_ui(new UIContainer); void UIContainer::addChild(UIElementPtr child) { @@ -96,6 +96,7 @@ void UIContainer::moveTo(const Point& pos) void UIContainer::render() { + UIElement::render(); for(auto it = m_children.begin(); it != m_children.end(); ++it) { const UIElementPtr& child = (*it); child->render(); diff --git a/src/framework/ui/uicontainer.h b/src/framework/ui/uicontainer.h index 5c7c3d60..5629a51d 100644 --- a/src/framework/ui/uicontainer.h +++ b/src/framework/ui/uicontainer.h @@ -33,7 +33,7 @@ class UIContainer : public UIElement { public: - UIContainer() : UIElement() { } + UIContainer(UI::EElementType type = UI::Container) : UIElement(type) { } virtual ~UIContainer() { } virtual void addChild(UIElementPtr child); @@ -52,7 +52,7 @@ public: virtual void setActiveElement(UIElementPtr activeElement); UIElementPtr getActiveElement() const { return m_activeElement; } - virtual UI::EControlType getControlType() const { return UI::Container; } + virtual UI::EElementType getElementType() const { return UI::Container; } UIContainerPtr asUIContainer() { return std::static_pointer_cast(shared_from_this()); } @@ -64,6 +64,6 @@ private: void onMove(const Point& pos); }; -extern UIContainerPtr g_gui; +extern UIContainerPtr g_ui; #endif // UICONTAINER_H diff --git a/src/framework/ui/uielement.cpp b/src/framework/ui/uielement.cpp index 506c860d..24ff0cdb 100644 --- a/src/framework/ui/uielement.cpp +++ b/src/framework/ui/uielement.cpp @@ -23,3 +23,33 @@ #include "uielement.h" +#include "uiskins.h" + +UIElement::UIElement(UI::EElementType type) : + m_type(type) +{ + // set default skin + setSkin(g_uiSkins.getElementSkin(type)); +} + + +bool UIElement::setSkin(const std::string& skinName) +{ + setSkin(g_uiSkins.getElementSkin(m_type, skinName)); + return m_skin != NULL; +} + +void UIElement::setSkin(UIElementSkin* skin) +{ + if(skin && !m_rect.isValid()) { + m_rect.setSize(skin->getDefaultSize()); + } + m_skin = skin; +} + +void UIElement::render() +{ + if(m_skin) + m_skin->draw(this); +} + diff --git a/src/framework/ui/uielement.h b/src/framework/ui/uielement.h index 7b9b1ed0..37997c3b 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 "uielementskin.h" class UIContainer; typedef std::shared_ptr UIContainerPtr; @@ -39,13 +40,17 @@ typedef std::shared_ptr UIElementPtr; class UIElement : public std::enable_shared_from_this { public: - UIElement() { } + UIElement(UI::EElementType type = UI::Element); virtual ~UIElement() { } - virtual void render() { } + virtual void render(); virtual void update(int ticks, int elapsedTicks) { } virtual bool onInputEvent(InputEvent *event) { return false; } + bool setSkin(const std::string& skinName); + void setSkin(UIElementSkin *skin); + UIElementSkin *getSkin() { return m_skin; } + virtual void setParent(UIContainerPtr parent) { m_parent = parent; } UIContainerPtr getParent() const { return m_parent; } @@ -61,13 +66,14 @@ public: virtual void setVisible(bool visible) { m_visible = visible; } bool isVisible() const { return m_visible; } - virtual UI::EControlType getControlType() const { return UI::Element; } + UI::EElementType getElementType() const { return m_type; } UIElementPtr asUIElement() { return shared_from_this(); } protected: - UI::EControlType m_type; + UI::EElementType m_type; UIContainerPtr m_parent; + UIElementSkin *m_skin; Rect m_rect; std::string m_name; bool m_visible; diff --git a/src/framework/ui/uielementskin.cpp b/src/framework/ui/uielementskin.cpp new file mode 100644 index 00000000..2698f0ef --- /dev/null +++ b/src/framework/ui/uielementskin.cpp @@ -0,0 +1,78 @@ +/* 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 "uielementskin.h" +#include "uielement.h" +#include "../borderedimage.h" +#include "../textures.h" +#include "uiskins.h" + +void UIElementSkin::draw(UIElement *element) +{ + const ImagePtr& image = m_stateImages.front(); + if(image) { + image->draw(element->getRect()); + } +} + +void UIElementSkin::load(const YAML::Node& node) +{ + if(node.FindValue("default size")) + node["default size"] >> m_defaultSize; + + 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; + + TexturePtr texture; + if(child.FindValue("image")) { + std::string textureName; + child["image"] >> textureName; + texture = g_textures.get(textureName); + } else { + texture = g_uiSkins.getDefaultTexture(); + } + + ImagePtr image = ImagePtr(new BorderedImage(texture, + left, + right, + top, + bottom, + topLeft, + topRight, + bottomLeft, + bottomRight, + center)); + m_stateImages.push_back(image); + } +} diff --git a/src/framework/ui/uielementskin.h b/src/framework/ui/uielementskin.h new file mode 100644 index 00000000..3d456fc5 --- /dev/null +++ b/src/framework/ui/uielementskin.h @@ -0,0 +1,56 @@ +/* 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 UIELEMENTSKIN_H +#define UIELEMENTSKIN_H + +#include "../prerequisites.h" +#include "uiconstants.h" +#include "../image.h" +#include "../rect.h" + +class UIElement; + +class UIElementSkin +{ +public: + UIElementSkin(const std::string& name, UI::EElementType elementType) : + m_name(name), + m_elementType(elementType) { } + + void load(const YAML::Node& node); + 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; } + +private: + std::string m_name; + UI::EElementType m_elementType; + Size m_defaultSize; + std::vector m_stateImages; +}; + +#endif // UIELEMENTSKIN_H diff --git a/src/framework/ui/uilabel.h b/src/framework/ui/uilabel.h index 24856adc..d0deb919 100644 --- a/src/framework/ui/uilabel.h +++ b/src/framework/ui/uilabel.h @@ -31,9 +31,7 @@ class UILabel : public UIElement { public: - UILabel() { } - - virtual UI::EControlType getControlType() const { return UI::Label; } + UILabel() : UIElement(UI::Label) { } }; #endif // UILABEL_H diff --git a/src/framework/ui/uipanel.cpp b/src/framework/ui/uipanel.cpp index ab6d24d6..7aa465de 100644 --- a/src/framework/ui/uipanel.cpp +++ b/src/framework/ui/uipanel.cpp @@ -23,24 +23,3 @@ #include "uipanel.h" - - -UIPanel::UIPanel() -{ - m_boderedImage = BorderedImagePtr(new BorderedImage("ui.png", - Rect(0,214,5,32), - Rect(6,214,5,32), - Rect(43,214,32,5), - Rect(43,220,32,5), - Rect(43,225,5,5), - Rect(49,225,5,5), - Rect(43,230,5,5), - Rect(48,231,5,5), - Rect(11,214,32,32))); -} - -void UIPanel::render() -{ - m_boderedImage->draw(m_rect); - UIContainer::render(); -} diff --git a/src/framework/ui/uipanel.h b/src/framework/ui/uipanel.h index 3297be47..d4f6126d 100644 --- a/src/framework/ui/uipanel.h +++ b/src/framework/ui/uipanel.h @@ -32,14 +32,7 @@ class UIPanel : public UIContainer { public: - UIPanel(); - - void render(); - - virtual UI::EControlType getControlType() const { return UI::Panel; } - -private: - BorderedImagePtr m_boderedImage; + UIPanel() : UIContainer(UI::Panel) { } }; typedef std::shared_ptr UIPanelPtr; diff --git a/src/framework/ui/uiskins.cpp b/src/framework/ui/uiskins.cpp new file mode 100644 index 00000000..b58d39d5 --- /dev/null +++ b/src/framework/ui/uiskins.cpp @@ -0,0 +1,92 @@ +/* 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 "uiskins.h" +#include "../resources.h" +#include "../textures.h" +#include "uielementskin.h" + +UISkins g_uiSkins; + +bool UISkins::load(const std::string& file) +{ + std::string fileContents = g_resources.loadTextFile(file); + if(!fileContents.size()) { + logFatal("Could not load skin file \"%s", file.c_str()); + return false; + } + + std::istringstream fin(fileContents); + + try { + YAML::Parser parser(fin); + + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string defaultTexture; + doc["default skin image"] >> defaultTexture; + m_defaultTexture = g_textures.get("skins/" + defaultTexture); + + { + const YAML::Node& node = doc["buttons"]; + for(auto it = node.begin(); it != node.end(); ++it) { + std::string name; + it.first() >> name; + + UIElementSkin *elementSkin = new UIElementSkin(name, UI::Button); + elementSkin->load(it.second()); + m_elementSkins.push_back(elementSkin); + } + } + + { + const YAML::Node& node = doc["panels"]; + for(auto it = node.begin(); it != node.end(); ++it) { + std::string name; + it.first() >> name; + + UIElementSkin *elementSkin = new UIElementSkin(name, UI::Panel); + elementSkin->load(it.second()); + m_elementSkins.push_back(elementSkin); + } + } + } catch (YAML::ParserException& e) { + logError("Malformed font file \"%s\"", file.c_str()); + return false; + } + return true; +} + +UIElementSkin* UISkins::getElementSkin(UI::EElementType elementType, const std::string& name) +{ + for(auto it = m_elementSkins.begin(); it != m_elementSkins.end(); ++it) { + UIElementSkin *skin = (*it); + if(elementType == skin->getElementType() && name == skin->getName()) { + return skin; + } + } + logWarning("Element skin '%s' not found", name.c_str()); + return NULL; +} diff --git a/src/framework/ui/uiskins.h b/src/framework/ui/uiskins.h new file mode 100644 index 00000000..6260c6b9 --- /dev/null +++ b/src/framework/ui/uiskins.h @@ -0,0 +1,52 @@ +/* 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 UISKIN_H +#define UISKIN_H + +#include "../prerequisites.h" +#include "uicontainer.h" +#include "../texture.h" + +class UIElementSkin; + +class UISkins +{ +public: + UISkins() { } + + bool load(const std::string& file); + + UIElementSkin *getElementSkin(UI::EElementType elementType, const std::string& name = "default"); + TexturePtr getDefaultTexture() { return m_defaultTexture; } + +private: + TexturePtr m_defaultTexture; + + std::vector m_elementSkins; +}; + +extern UISkins g_uiSkins; + +#endif // UISKIN_H diff --git a/src/main.cpp b/src/main.cpp index 76106ff5..1aae7c52 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include "menustate.h" #include "teststate.h" #include "framework/dispatcher.h" +#include "framework/ui/uiskins.h" /// Catches signals so we can exit nicely void signal_handler(int sig) @@ -108,6 +109,9 @@ int main(int argc, const char *argv[]) // init engine g_engine.init(); + // load UI skin + g_uiSkins.load("skins/tibiaskin.yml"); + // state scope { std::shared_ptr initialState(new MenuState); diff --git a/src/menustate.cpp b/src/menustate.cpp index 0a10510e..c88eac3f 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -91,6 +91,7 @@ void MenuState::createMainMenu() int y = 16; m_menuPanel = UIPanelPtr(new UIPanel); + m_menuPanel->setSkin("roundedGridPanel"); recalculateMenuPanelPosition(); button = UIButtonPtr(new UIButton("Enter Game")); @@ -118,7 +119,7 @@ void MenuState::createMainMenu() m_menuPanel->addChild(button); y += 30; - g_gui->addChild(m_menuPanel); + g_ui->addChild(m_menuPanel); } void MenuState::recalculateMenuPanelPosition()