#pragma once #include #include #include #include namespace cigus { using json = nlohmann::json; template class Ref; template class OriginRef; template class MutRef; template class ConstRef; template class Ref { protected: T *ptr = nullptr; public: virtual ~Ref() {} Ref() = delete; Ref(const Ref &other) = delete; Ref(Ref &&other) = delete; Ref(const OriginRef& ptr) : ptr(ptr.ptr) { } Ref(T* ptr) : ptr(ptr) { } virtual bool operator!() const { return ptr == nullptr; } virtual void check() const { assert(ptr != nullptr || "Dereferencing null pointer"); } virtual const T &operator*() const { check(); return *ptr; } virtual const T *operator->() const { check(); return ptr; } static Ref Null() { return Ref(nullptr); } }; template class OriginRef final : public MutRef { public: friend class Ref; template OriginRef(Args... args) : Ref(new G(std::forward(args)...)) { } OriginRef(T* ptr) : MutRef(ptr) { } ~OriginRef() override { if (this->ptr != nullptr) { delete this->ptr; } } [[nodiscard]] MutRef mut() { return MutRef(this->ptr); } [[nodiscard]] ConstRef immute() const { return ConstRef(this->ptr); } }; template class MutRef : public Ref { protected: using Ref::ptr; public: friend class Ref; using Ref::check; using Ref::operator*; using Ref::operator->; MutRef(const OriginRef& other) : Ref(other.ptr) {} MutRef(T* ptr) : Ref(ptr) {} MutRef(const MutRef &other) : Ref(other.ptr) { } MutRef(MutRef &&other) noexcept : Ref(other.ptr) { } MutRef &operator=(MutRef &&other) noexcept { if (this->ptr != other.ptr) { ptr = other.ptr; } return *this; } T &operator*() { check(); return *ptr; } T *operator->() { check(); return ptr; } }; template class ConstRef : public Ref { protected: using Ref::ptr; using Ref::check; public: friend class Ref; ConstRef(const OriginRef other) : Ref(other.ptr) { } ConstRef(const MutRef other) : Ref(other.ptr) { } }; template class NullRef { public: friend class Ref; NullRef(const NullRef &other) = delete; NullRef(NullRef &&other) = delete; NullRef &operator=(NullRef &&other) = delete; NullRef() : Ref(nullptr) { } T *ptr = nullptr; bool operator!() const { return false; } }; } namespace cigus::UI { class RenderCall { OriginRef drawable; sf::RenderStates states; public: explicit RenderCall(const sf::RenderStates& states, sf::Drawable *ptr) : drawable(ptr), states(states) { drawable.check(); } void draw(sf::RenderTarget &target, const sf::RenderStates &states) const { target.draw(*drawable, states); } MutRef operator->() { drawable.check(); return drawable.mut(); } }; class View { std::vector m_RenderCalls; protected: void Rectangle(const float x, const float y, sf::Color color = sf::Color::White) { auto shape = new sf::RectangleShape(sf::Vector2f(x, y)); shape->setFillColor(color); m_RenderCalls.emplace_back(sf::RenderStates(), shape); } public: virtual ~View() = default; [[nodiscard]] const std::vector &renderCalls() const { return m_RenderCalls; } virtual bool update() { return false; } void draw() { if (!m_RenderCalls.empty()) { m_RenderCalls.clear(); } body(); } virtual void body() = 0; }; class Renderer { public: explicit Renderer(const MutRef &_view) : view(_view) { view->body(); } MutRef view; void update() { if (view->update()) view->draw(); } void render(sf::RenderTarget &target, const sf::RenderStates &states) const { for (const auto &renderCall: view->renderCalls()) { renderCall.draw(target, states); } } }; }