guixmlparser.h File Reference

Go to the documentation of this file. Source: include/ffw/gui/guixmlparser.h

/* This file is part of FineFramework project */
#ifndef FFW_GUI_XML_PARSER
#define FFW_GUI_XML_PARSER

#include <string>
#include <exception>
#include <unordered_map>
#include "./config.h"
#include "guistyle.h"
#include "guiwidget.h"

#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace tinyxml2 {
    class XMLElement;
}
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

namespace ffw {
    class GuiLayout;
    class GuiWidget;
    class GuiWindow;
    class GuiImage;

    class GuiXmlException: public std::runtime_error {
    public:
        GuiXmlException(const std::string& msg):std::runtime_error(msg) {
            
        }
    };

    class GuiXmlNotFound : public GuiXmlException {
    public:
        GuiXmlNotFound(const std::string& msg) :GuiXmlException(msg) {

        }
    };

    class FFW_API GuiXmlParser {
    public:
        class Token {
        public:
            Token() = default;
            virtual ~Token() = default;

            virtual bool hasAttribute(const char* key) const = 0;
            virtual std::string getAttributeString(const char* key) const = 0;
            virtual int getAttributeInt(const char* key) const = 0;
            virtual float getAttributeFloat(const char* key) const = 0;
            virtual std::string getContent() const = 0;

            GuiUnits getAttributeUnits(const char* key) const;
            float getAttributePixels(const char* key) const;
            GuiUnits2D getAttributeUnits2D(const char* keyW, const char* keyH) const;
            GuiStyle::Attribute<GuiUnits> getAttributeUnitsAttribute(const char* key) const;
            GuiAlign getAttributeAlign(const char* key) const;
            GuiOrientation getAttributeOrientation(const char* key) const;
            bool getAttributeBool(const char* key) const;
        };

        class Registry {
        public:
            Registry() = default;
            virtual ~Registry() = default;

            virtual const GuiImage* getImage(const std::string& key) const {
                auto it = images.find(key);
                if (it == images.end()) throw GuiXmlNotFound("image id: \"" + key + "\" not found");
                return it->second;
            }
            virtual const GuiFont* getFont(const std::string& key) const {
                auto it = fonts.find(key);
                if (it == fonts.end()) throw GuiXmlNotFound("font id: \"" + key + "\" not found");
                return it->second;
            }
            void addImage(const std::string& key, const GuiImage* image) {
                images.insert(std::make_pair(key, image));
            }
            void addFont(const std::string& key, const GuiFont* font) {
                fonts.insert(std::make_pair(key, font));
            }
        private:
            std::unordered_map<std::string, const GuiImage*> images;
            std::unordered_map<std::string, const GuiFont*> fonts;
        };

        class XmlToken; // Public Token

        class Visitor {
        public:
            Visitor(const std::string& key):key(key) {
                
            }
            virtual ~Visitor() = default;

            virtual void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const;
            virtual GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const = 0;

            inline const std::string& getKey() const {
                return key;
            }
        private:
            std::string key;
        };

        class VisitorGuiWidget: public Visitor {
        public:
            VisitorGuiWidget(const std::string& key):Visitor(key) {
            }
            virtual ~VisitorGuiWidget() = default;

            void defaults(const Token& token, GuiWidget* instance, const Registry* registry, bool padding = true, bool margin = true) const;
        };

        class VisitorGuiButton : public VisitorGuiWidget {
        public:
            VisitorGuiButton():VisitorGuiWidget("button") {
            }
            virtual ~VisitorGuiButton() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiButtonToggle : public VisitorGuiWidget {
        public:
            VisitorGuiButtonToggle() :VisitorGuiWidget("button-toggle") {
            }
            virtual ~VisitorGuiButtonToggle() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiButtonPrimary : public VisitorGuiWidget {
        public:
            VisitorGuiButtonPrimary() :VisitorGuiWidget("button-primary") {
            }
            virtual ~VisitorGuiButtonPrimary() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiBox : public VisitorGuiWidget {
        public:
            VisitorGuiBox():VisitorGuiWidget("box") {
            }
            virtual ~VisitorGuiBox() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiLayout : public VisitorGuiWidget {
        public:
            VisitorGuiLayout() :VisitorGuiWidget("layout") {
            }
            virtual ~VisitorGuiLayout() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiVerticalLayout : public VisitorGuiWidget {
        public:
            VisitorGuiVerticalLayout() :VisitorGuiWidget("vertial-layout") {
            }
            virtual ~VisitorGuiVerticalLayout() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiHorizontalLayout : public VisitorGuiWidget {
        public:
            VisitorGuiHorizontalLayout() :VisitorGuiWidget("horizontal-layout") {
            }
            virtual ~VisitorGuiHorizontalLayout() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiScrollableLayout : public VisitorGuiWidget {
        public:
            VisitorGuiScrollableLayout() :VisitorGuiWidget("scrollable-layout") {
            }
            virtual ~VisitorGuiScrollableLayout() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiLabel : public VisitorGuiWidget {
        public:
            VisitorGuiLabel() :VisitorGuiWidget("label") {
            }
            virtual ~VisitorGuiLabel() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiRadio: public VisitorGuiWidget {
        public:
            VisitorGuiRadio() :VisitorGuiWidget("radio") {
            }
            virtual ~VisitorGuiRadio() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiCheckbox : public VisitorGuiWidget {
        public:
            VisitorGuiCheckbox() :VisitorGuiWidget("checkbox") {
            }
            virtual ~VisitorGuiCheckbox() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiSlider : public VisitorGuiWidget {
        public:
            VisitorGuiSlider() :VisitorGuiWidget("slider") {
            }
            virtual ~VisitorGuiSlider() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiScrollBar : public VisitorGuiWidget {
        public:
            VisitorGuiScrollBar() :VisitorGuiWidget("scrollbar") {
            }
            virtual ~VisitorGuiScrollBar() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiImageViewer : public VisitorGuiWidget {
        public:
            VisitorGuiImageViewer() :VisitorGuiWidget("image-viewer") {
            }
            virtual ~VisitorGuiImageViewer() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiTextInput : public VisitorGuiWidget {
        public:
            VisitorGuiTextInput() :VisitorGuiWidget("text-input") {
            }
            virtual ~VisitorGuiTextInput() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiScrollableTextInput : public VisitorGuiWidget {
        public:
            VisitorGuiScrollableTextInput() :VisitorGuiWidget("text-area") {
            }
            virtual ~VisitorGuiScrollableTextInput() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiWindow : public Visitor {
        public:
            VisitorGuiWindow() :Visitor("window") {
            }
            virtual ~VisitorGuiWindow() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiList : public VisitorGuiWidget {
        public:
            VisitorGuiList() :VisitorGuiWidget("list") {
            }
            virtual ~VisitorGuiList() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiListItem : public VisitorGuiWidget {
        public:
            VisitorGuiListItem() :VisitorGuiWidget("list-item") {
            }
            virtual ~VisitorGuiListItem() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiSwitch : public VisitorGuiWidget {
        public:
            VisitorGuiSwitch() :VisitorGuiWidget("switch") {
            }
            virtual ~VisitorGuiSwitch() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiProgressBar : public VisitorGuiWidget {
        public:
            VisitorGuiProgressBar() :VisitorGuiWidget("progress-bar") {
            }
            virtual ~VisitorGuiProgressBar() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiProgressCircle : public VisitorGuiWidget {
        public:
            VisitorGuiProgressCircle() :VisitorGuiWidget("progress-circle") {
            }
            virtual ~VisitorGuiProgressCircle() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiTabs : public VisitorGuiWidget {
        public:
            VisitorGuiTabs() :VisitorGuiWidget("tabs") {
            }
            virtual ~VisitorGuiTabs() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiTabLayout : public VisitorGuiWidget {
        public:
            VisitorGuiTabLayout() :VisitorGuiWidget("tab-layout") {
            }
            virtual ~VisitorGuiTabLayout() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiText : public VisitorGuiWidget {
        public:
            VisitorGuiText() :VisitorGuiWidget("text") {
            }
            virtual ~VisitorGuiText() = default;

            void addWidget(GuiWidget* acceptor, GuiWindow* window, GuiWidget* child) const override;
            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        class VisitorGuiTextPara : public VisitorGuiWidget {
        public:
            VisitorGuiTextPara() :VisitorGuiWidget("para") {
            }
            virtual ~VisitorGuiTextPara() = default;

            GuiWidget* accept(GuiWidget* acceptor, GuiWindow* window, const Token& token, const Registry* registry) const override;
        };

        GuiXmlParser(GuiWindow& window, const Registry& registry);
        virtual ~GuiXmlParser() = default;
        void parse(const std::string& str) {
            parse(str.c_str(), str.size());
        }
        void parse(const char* src, size_t len);
        void addVisitor(const Visitor* visitor) {
            visitors.insert(std::make_pair(visitor->getKey(), visitor));
        }
    private:
        GuiWidget* recursive(tinyxml2::XMLElement* elem, GuiWidget* parent);
        const Visitor* getVisitor(const std::string& key);

        GuiWindow& window;
        const Registry& registry;
        std::unordered_map<std::string, const Visitor*> visitors;
    };
}

#endif