From 792d661dad641d26a1662ef38d3ab4e88d2cd4a5 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sun, 10 Apr 2011 04:34:52 -0300 Subject: [PATCH] loading ui from files --- CMakeLists.txt | 1 + src/framework/borderedimage.cpp | 2 - src/framework/ui/anchorlayout.cpp | 1 + src/framework/ui/anchorlayout.h | 5 ++ src/framework/ui/uibutton.cpp | 6 ++ src/framework/ui/uibutton.h | 4 +- src/framework/ui/uicontainer.cpp | 117 +++++++++++++++++++++++++++++- src/framework/ui/uicontainer.h | 14 +++- src/framework/ui/uielement.cpp | 100 +++++++++++++++++++++++++ src/framework/ui/uielement.h | 4 + src/framework/ui/uilabel.cpp | 9 +++ src/framework/ui/uilabel.h | 4 +- src/framework/ui/uiwindow.cpp | 5 ++ src/framework/ui/uiwindow.h | 4 +- src/menustate.cpp | 12 ++- 15 files changed, 276 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4eea742e..278ae162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ SET(SOURCES # game sources src/main.cpp src/menustate.cpp + src/mainmenu.cpp src/teststate.cpp # game net diff --git a/src/framework/borderedimage.cpp b/src/framework/borderedimage.cpp index 8fcd2d0b..73fe7334 100644 --- a/src/framework/borderedimage.cpp +++ b/src/framework/borderedimage.cpp @@ -26,8 +26,6 @@ #include "graphics.h" #include "textures.h" -#include - BorderedImage::BorderedImage(TexturePtr texture, const Rect& left, const Rect& right, diff --git a/src/framework/ui/anchorlayout.cpp b/src/framework/ui/anchorlayout.cpp index 78739e64..f9d7ae7f 100644 --- a/src/framework/ui/anchorlayout.cpp +++ b/src/framework/ui/anchorlayout.cpp @@ -23,6 +23,7 @@ #include "anchorlayout.h" +#include "uielement.h" int AnchorLine::getPos() const { diff --git a/src/framework/ui/anchorlayout.h b/src/framework/ui/anchorlayout.h index 96c944d6..ec3594a7 100644 --- a/src/framework/ui/anchorlayout.h +++ b/src/framework/ui/anchorlayout.h @@ -97,6 +97,11 @@ public: 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(); } + void setMarginLeft(int margin) { m_marginLeft = margin; recalculateAnchors(); } + void setMarginRight(int margin) { m_marginRight = margin; recalculateAnchors(); } + void setMarginTop(int margin) { m_marginTop = margin; recalculateAnchors(); } + void setMarginBottom(int margin) { m_marginBottom = margin; recalculateAnchors(); } + AnchorLayoutPtr asAnchorLayout() { return shared_from_this(); } private: diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index 25c87a1e..3e0a4960 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -26,6 +26,12 @@ #include "../fonts.h" #include "../font.h" +void UIButton::load(const YAML::Node& node) +{ + UIElement::load(node); + node["text"] >> m_text; +} + void UIButton::render() { UIElement::render(); diff --git a/src/framework/ui/uibutton.h b/src/framework/ui/uibutton.h index 6fc91a4a..59ff7f65 100644 --- a/src/framework/ui/uibutton.h +++ b/src/framework/ui/uibutton.h @@ -34,12 +34,14 @@ typedef std::function Callback; class UIButton : public UIElement { public: - UIButton(const std::string& text) : UIElement(UI::Button), + UIButton(const std::string& text = std::string()) : UIElement(UI::Button), m_text(text), m_state(UI::ButtonUp) { UIElement(); } + void load(const YAML::Node& node); + virtual void render(); bool onInputEvent(const InputEvent& event); diff --git a/src/framework/ui/uicontainer.cpp b/src/framework/ui/uicontainer.cpp index 19821415..880b7f7f 100644 --- a/src/framework/ui/uicontainer.cpp +++ b/src/framework/ui/uicontainer.cpp @@ -23,9 +23,99 @@ #include "uicontainer.h" +#include "../resources.h" +#include "uibutton.h" +#include "uipanel.h" +#include "uilabel.h" +#include "uitextedit.h" +#include "uiwindow.h" UIContainerPtr g_ui(new UIContainer); +UIElementPtr createElementFromDescription(std::string elementId) +{ + UIElementPtr element; + + std::vector split; + boost::split(split, elementId, boost::is_any_of("-")); + if(split.size() != 2) { + logError("incorrect element id format: %s", elementId.c_str()); + return element; + } + + std::string elementType = split[1]; + if(elementType == "panel") { + element = UIElementPtr(new UIPanel); + } else if(elementType == "button") { + element = UIElementPtr(new UIButton); + } else if(elementType == "label") { + element = UIElementPtr(new UILabel); + } else if(elementType == "window") { + element = UIElementPtr(new UIWindow); + } else if(elementType == "textEdit") { + element = UIElementPtr(new UITextEdit); + } + + if(element) + element->setId(elementId); + + return element; +} + +void UIContainer::load(const YAML::Node& node) +{ + UIElement::load(node); + + for(auto it = node.begin(); it != node.end(); ++it) { + std::string elementDesc; + it.first() >> elementDesc; + + if(elementDesc.find("-") != std::string::npos) { + UIElementPtr element = createElementFromDescription(elementDesc); + if(element) { + addChild(element); + element->load(it.second()); + } + } + } +} + +UIContainerPtr UIContainer::load(const std::string& file) +{ + //TODO: handle errors + //TODO: display errors in which file and line + UIContainerPtr container; + + std::string fileContents = g_resources.loadTextFile(file); + if(!fileContents.size()) { + logFatal("could not load ui file \"%s", file.c_str()); + return UIContainerPtr(); + } + + std::istringstream fin(fileContents); + + try { + YAML::Parser parser(fin); + + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string elementDesc; + doc.begin().first() >> elementDesc; + UIElementPtr element = createElementFromDescription(elementDesc); + if(element) { + g_ui->addChild(element); + element->load(doc.begin().second()); + return element->asUIContainer(); + } + } catch (YAML::ParserException& e) { + logError("Malformed ui file \"%s\": %s", file.c_str(), e.what()); + return UIContainerPtr(); + } + + return container; +} + void UIContainer::addChild(UIElementPtr child) { m_children.push_back(child); @@ -41,12 +131,35 @@ void UIContainer::removeChild(UIElementPtr child) child->setParent(UIContainerPtr()); } -UIElementPtr UIContainer::getChildById(const std::string& id) const +UIElementPtr UIContainer::getChildById(const std::string& id) { + if(getId() == id) + return asUIElement(); for(auto it = m_children.begin(); it != m_children.end(); ++it) { if((*it)->getId() == id) { return (*it); - break; + } + } + return UIElementPtr(); +} + +UIElementPtr UIContainer::recursiveGetChildById(const std::string& id) +{ + if(getId() == id) + return asUIElement(); + + UIElementPtr element; + for(auto it = m_children.begin(); it != m_children.end(); ++it) { + element = (*it); + if(element->getId() == id) { + return element; + } else { + UIContainerPtr container = element->asUIContainer(); + if(container) { + element = container->recursiveGetChildById(id); + if(element) + return element; + } } } return UIElementPtr(); diff --git a/src/framework/ui/uicontainer.h b/src/framework/ui/uicontainer.h index 0ef14f6f..c2efd7a9 100644 --- a/src/framework/ui/uicontainer.h +++ b/src/framework/ui/uicontainer.h @@ -25,6 +25,7 @@ #ifndef UICONTAINER_H #define UICONTAINER_H +//TODO: make includes paths, so this will be cleaner #include "../prerequisites.h" #include "uielement.h" #include "../point.h" @@ -36,9 +37,17 @@ public: UIContainer(UI::EElementType type = UI::Container) : UIElement(type) { } virtual ~UIContainer() { } + virtual void load(const YAML::Node& node); + + //TODO: move this shit + static UIContainerPtr load(const std::string& file); + void addChild(UIElementPtr child); void removeChild(UIElementPtr child); - UIElementPtr getChildById(const std::string& id) const; + UIElementPtr getChildById(const std::string& id); + + //TODO: make this backwards + UIElementPtr recursiveGetChildById(const std::string& id); virtual void render(); virtual bool onInputEvent(const InputEvent& event); @@ -53,9 +62,6 @@ public: protected: std::list m_children; UIElementPtr m_activeElement; - -private: - void onMove(const Point& pos); }; extern UIContainerPtr g_ui; diff --git a/src/framework/ui/uielement.cpp b/src/framework/ui/uielement.cpp index 052ee849..909231c6 100644 --- a/src/framework/ui/uielement.cpp +++ b/src/framework/ui/uielement.cpp @@ -38,6 +38,106 @@ UIElement::UIElement(UI::EElementType type) : setSkin(g_uiSkins.getElementSkin(type)); } +void UIElement::load(const YAML::Node& node) +{ + if(node.FindValue("skin")) + setSkin(g_uiSkins.getElementSkin(m_type, node["skin"])); + + if(node.FindValue("size")) { + Size size; + node["size"] >> size; + setSize(size); + } + + int margin; + if(node.FindValue("margin.left")) { + node["margin.left"] >> margin; + setMarginLeft(margin); + } + + if(node.FindValue("margin.right")) { + node["margin.right"] >> margin; + setMarginRight(margin); + } + + if(node.FindValue("margin.top")) { + node["margin.top"] >> margin; + setMarginTop(margin); + } + + if(node.FindValue("margin.bottom")) { + node["margin.bottom"] >> margin; + setMarginBottom(margin); + } + + if(node.FindValue("anchors.left")) + loadAnchor(ANCHOR_LEFT, node["anchors.left"]); + + if(node.FindValue("anchors.right")) + loadAnchor(ANCHOR_RIGHT, node["anchors.right"]); + + if(node.FindValue("anchors.top")) + loadAnchor(ANCHOR_TOP, node["anchors.top"]); + + if(node.FindValue("anchors.bottom")) + loadAnchor(ANCHOR_BOTTOM, node["anchors.bottom"]); + + if(node.FindValue("anchors.horizontalCenter")) + loadAnchor(ANCHOR_HORIZONTAL_CENTER, node["anchors.horizontalCenter"]); + + if(node.FindValue("anchors.verticalCenter")) + loadAnchor(ANCHOR_VERTICAL_CENTER, node["anchors.verticalCenter"]); +} + +void UIElement::loadAnchor(EAnchorType type, const YAML::Node& node) +{ + std::string anchorDescription; + node >> anchorDescription; + + std::vector split; + boost::split(split, anchorDescription, boost::is_any_of(".")); + if(split.size() != 2) { + logError("wrong anchors description: %s", anchorDescription.c_str()); + return; + } + + std::string relativeElementId = split[0]; + std::string relativeAnchorTypeId = split[1]; + EAnchorType relativeAnchorType; + + if(relativeAnchorTypeId == "left") + relativeAnchorType = ANCHOR_LEFT; + else if(relativeAnchorTypeId == "right") + relativeAnchorType = ANCHOR_RIGHT; + else if(relativeAnchorTypeId == "top") + relativeAnchorType = ANCHOR_TOP; + else if(relativeAnchorTypeId == "bottom") + relativeAnchorType = ANCHOR_BOTTOM; + else if(relativeAnchorTypeId == "horizontalCenter") + relativeAnchorType = ANCHOR_HORIZONTAL_CENTER; + else if(relativeAnchorTypeId == "verticalCenter") + relativeAnchorType = ANCHOR_VERTICAL_CENTER; + else { + logError("wrong anchors description: %s", anchorDescription.c_str()); + return; + } + + AnchorLayoutPtr relativeElement; + if(relativeElementId == "parent" && getParent()) { + relativeElement = getParent()->asAnchorLayout(); + } else { + UIElementPtr element = g_ui->recursiveGetChildById(relativeElementId); + if(element) + relativeElement = element->asAnchorLayout(); + } + + if(relativeElement) { + addAnchor(type, AnchorLine(relativeElement, relativeAnchorType)); + } else { + logError("anchoring has failed: %s", anchorDescription.c_str()); + return; + } +} bool UIElement::setSkin(const std::string& skinName) { diff --git a/src/framework/ui/uielement.h b/src/framework/ui/uielement.h index ae3c6014..29b139c1 100644 --- a/src/framework/ui/uielement.h +++ b/src/framework/ui/uielement.h @@ -50,6 +50,9 @@ public: virtual void render(); virtual bool onInputEvent(const InputEvent& event) { return false; } + virtual void load(const YAML::Node& node); + void loadAnchor(EAnchorType type, const YAML::Node& node); + bool setSkin(const std::string& skinName); void setSkin(UIElementSkin *skin); UIElementSkin *getSkin() { return m_skin; } @@ -69,6 +72,7 @@ public: UI::EElementType getElementType() const { return m_type; } UIElementPtr asUIElement() { return std::static_pointer_cast(shared_from_this()); } + virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); } private: UI::EElementType m_type; diff --git a/src/framework/ui/uilabel.cpp b/src/framework/ui/uilabel.cpp index af7d6dc7..15283864 100644 --- a/src/framework/ui/uilabel.cpp +++ b/src/framework/ui/uilabel.cpp @@ -35,6 +35,15 @@ UILabel::UILabel(const std::string& text, Font* font) : setSize(m_font->calculateTextRectSize(text)); } +void UILabel::load(const YAML::Node& node) +{ + UIElement::load(node); + + std::string text; + node["text"] >> text; + setText(text); +} + void UILabel::render() { m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF)); diff --git a/src/framework/ui/uilabel.h b/src/framework/ui/uilabel.h index 4b2ab7f9..2aab2e3b 100644 --- a/src/framework/ui/uilabel.h +++ b/src/framework/ui/uilabel.h @@ -33,7 +33,9 @@ class Font; class UILabel : public UIElement { public: - UILabel(const std::string& text, Font *font = NULL); + UILabel(const std::string& text = std::string(), Font *font = NULL); + + void load(const YAML::Node& node); void render(); diff --git a/src/framework/ui/uiwindow.cpp b/src/framework/ui/uiwindow.cpp index 9648e165..049233e6 100644 --- a/src/framework/ui/uiwindow.cpp +++ b/src/framework/ui/uiwindow.cpp @@ -24,3 +24,8 @@ #include "uiwindow.h" +void UIWindow::load(const YAML::Node& node) +{ + UIContainer::load(node); + node["title"] >> m_title; +} diff --git a/src/framework/ui/uiwindow.h b/src/framework/ui/uiwindow.h index 72ac014a..bdd3953a 100644 --- a/src/framework/ui/uiwindow.h +++ b/src/framework/ui/uiwindow.h @@ -31,10 +31,12 @@ class UIWindow : public UIContainer { public: - UIWindow(const std::string& title) : + UIWindow(const std::string& title = std::string()) : UIContainer(UI::Window), m_title(title) { } + void load(const YAML::Node& node); + const std::string& getTitle() const { return m_title; } private: diff --git a/src/menustate.cpp b/src/menustate.cpp index a89373d0..0b2d9af0 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -42,7 +42,15 @@ void MenuState::onEnter() m_background = g_textures.get("background.png"); m_background->enableBilinearFilter(); - createMainMenu(); + UIContainerPtr mainMenuPanel = UIContainer::load("ui/mainMenu-panel.yml"); + + UIButtonPtr button = std::static_pointer_cast(mainMenuPanel->getChildById("exitGame-button")); + button->onClick([]{ g_engine.stop(); }); + + button = std::static_pointer_cast(mainMenuPanel->getChildById("enterGame-button")); + button->onClick([]{ + UIContainer::load("ui/enterGame-window.yml"); + }); } void MenuState::onLeave() @@ -82,6 +90,7 @@ void MenuState::render() void MenuState::createMainMenu() { +/* int y = 0; m_menuPanel = UIPanelPtr(new UIPanel); @@ -199,4 +208,5 @@ void MenuState::createMainMenu() if(window) window->setVisible(true); }); + */ }