/* * Copyright (C) 2017 Christopher J. Howard * * This file is part of Antkeeper Source Code. * * Antkeeper Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper Source Code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper Source Code. If not, see . */ #ifndef UI_HPP #define UI_HPP #include "../input.hpp" #include "../materials.hpp" #include #include #include using namespace Emergent; namespace Anchor { static const Vector2& TOP_LEFT = Vector2(0.0f, 0.0f); static const Vector2& TOP_RIGHT = Vector2(1.0f, 0.0f); static const Vector2& BOTTOM_LEFT = Vector2(0.0f, 1.0f); static const Vector2& BOTTOM_RIGHT = Vector2(1.0f, 1.0f); static const Vector2& CENTER = Vector2(0.5f, 0.5f); } class UIElement: public MouseMotionObserver, public MouseButtonObserver { public: enum class Type { CONTAINER, LABEL, IMAGE }; UIElement(); virtual ~UIElement(); /// Sets the anchor vector. Possible values are 0, 0.5, and 1, corresponding to the left, center, and right, respectively, and the top, center, and bottom. void setAnchor(const Vector2& anchor); /// Sets the layer offset, relative to its parent layer + 1 void setLayerOffset(int offset); /// Sets the local origin of the element void setOrigin(const Vector2& origin); /// Sets the translation of the element, relative to its position in its parent element void setTranslation(const Vector2& translation); /// Sets the dimensions of the element void setDimensions(const Vector2& dimensions); /// Sets the tint color of the element void setTintColor(const Vector4& color); /// Sets the visibility of the element void setVisible(bool visible); /// Enables or disables callbacks void setActive(bool active); /// Returns the type of this element virtual UIElement::Type getElementType() const = 0; /// Returns the material of this element const UIMaterial* getMaterial() const; /// @copydoc UIElement::getMaterial() const UIMaterial* getMaterial(); /// Returns the parent of this element const UIElement* getParent() const; /// @copydoc UIElement::getParent() const UIElement* getParent(); /// Returns the number of child elements std::size_t getChildCount() const; /// Returns the child element at the specified index const UIElement* getChild(std::size_t index) const; /// @copydoc UIElement::getChild() const UIElement* getChild(std::size_t index); /// Returns the anchor vector const Vector2& getAnchor() const; /// Returns the layer offset int getLayerOffset() const; /// Returns the layer of this element int getLayer() const; /// Returns the origin of this element const Vector2& getOrigin() const; /// Returns the translation of this element, relative to its parent const Vector2& getTranslation() const; /// Returns the dimensions of this element const Vector2& getDimensions() const; /// Returns the world-space position of this element. Only accurate after update() is called const Vector2& getPosition() const; /// Returns the world-space bounds of this element. const Rect& getBounds() const; /// Returns the tint color of this element const Vector4& getTintColor() const; /// Returns the final color of this element, relative to its ancestor's tint colors const Vector4& getColor() const; /// Returns the visibility of this element bool isVisible() const; /// Returns `true` if the element is active (callbacks enabled) bool isActive() const; /// Calculates the world-space position and bounds of this element and its children virtual void update(); /// Adds a child to this element void addChild(UIElement* element); /// Removes a child from this element void removeChild(UIElement* element); void setMouseOverCallback(std::function callback); void setMouseOutCallback(std::function callback); void setMouseMovedCallback(std::function callback); void setMousePressedCallback(std::function callback); void setMouseReleasedCallback(std::function callback); void mouseMoved(int x, int y); void mouseButtonPressed(int button, int x, int y); void mouseButtonReleased(int button, int x, int y); protected: UIMaterial material; private: UIElement* parent; std::vector children; Vector2 anchor; int layerOffset; int layer; Vector2 origin; Vector2 translation; Vector2 dimensions; Vector2 position; Rect bounds; Vector4 tintColor; Vector4 color; bool visible; bool active; bool mouseOver; std::function mouseOverCallback; std::function mouseOutCallback; std::function mouseMovedCallback; std::function mousePressedCallback; std::function mouseReleasedCallback; }; inline void UIElement::setAnchor(const Vector2& anchor) { this->anchor = anchor; } inline void UIElement::setLayerOffset(int offset) { this->layerOffset = offset; } inline void UIElement::setOrigin(const Vector2& origin) { this->origin = origin; } inline void UIElement::setTranslation(const Vector2& translation) { this->translation = translation; } inline void UIElement::setDimensions(const Vector2& dimensions) { this->dimensions = dimensions; } inline void UIElement::setTintColor(const Vector4& color) { this->tintColor = color; } inline void UIElement::setVisible(bool visible) { this->visible = visible; } inline void UIElement::setActive(bool active) { this->active = active; } inline const UIElement* UIElement::getParent() const { return parent; } inline const UIMaterial* UIElement::getMaterial() const { return &material; } inline UIMaterial* UIElement::getMaterial() { return &material; } inline UIElement* UIElement::getParent() { return parent; } inline std::size_t UIElement::getChildCount() const { return children.size(); } inline const UIElement* UIElement::getChild(std::size_t index) const { return children[index]; } inline UIElement* UIElement::getChild(std::size_t index) { return children[index]; } inline const Vector2& UIElement::getAnchor() const { return anchor; } inline int UIElement::getLayerOffset() const { return layerOffset; } inline int UIElement::getLayer() const { return layer; } inline const Vector2& UIElement::getOrigin() const { return origin; } inline const Vector2& UIElement::getTranslation() const { return translation; } inline const Vector2& UIElement::getDimensions() const { return dimensions; } inline const Vector2& UIElement::getPosition() const { return position; } inline const Rect& UIElement::getBounds() const { return bounds; } inline const Vector4& UIElement::getTintColor() const { return tintColor; } inline const Vector4& UIElement::getColor() const { return color; } inline bool UIElement::isVisible() const { return visible; } inline bool UIElement::isActive() const { return active; } class UIContainer: public UIElement { public: virtual UIElement::Type getElementType() const; }; inline UIElement::Type UIContainer::getElementType() const { return UIElement::Type::CONTAINER; } class UILabel: public UIElement { public: UILabel(); virtual ~UILabel(); virtual UIElement::Type getElementType() const; void setFont(Font* font); void setText(const std::string& text); const Font* getFont() const; Font* getFont(); const std::string& getText() const; private: void calculateDimensions(); Font* font; std::string text; }; inline UIElement::Type UILabel::getElementType() const { return UIElement::Type::LABEL; } inline const Font* UILabel::getFont() const { return font; } inline Font* UILabel::getFont() { return font; } inline const std::string& UILabel::getText() const { return text; } class UIImage: public UIElement { public: UIImage(); virtual ~UIImage(); virtual UIElement::Type getElementType() const; virtual const Texture* getTexture() const; void setTexture(Texture* texture); void setTextureBounds(const Rect& bounds); const Rect& getTextureBounds() const; private: Rect textureBounds; }; inline UIElement::Type UIImage::getElementType() const { return UIElement::Type::IMAGE; } inline const Texture* UIImage::getTexture() const { return material.texture; } inline void UIImage::setTexture(Texture* texture) { material.texture = texture; } inline void UIImage::setTextureBounds(const Rect& bounds) { this->textureBounds = bounds; } inline const Rect& UIImage::getTextureBounds() const { return textureBounds; } // Creates a scene from a root UI element (follows visitor pattern?) class UIBatcher { public: void batch(BillboardBatch* result, const UIElement* ui); private: void queueElements(std::list* elements, const UIElement* element) const; BillboardBatch::Range* getRange(BillboardBatch* result, const UIElement* element) const; void batchElement(BillboardBatch* result, const UIElement* element); void batchLabel(BillboardBatch* result, const UILabel* label); void batchImage(BillboardBatch* result, const UIImage* image); }; class Menu; class MenuItem { public: void select(); void deselect(); void activate(); void setSelectedCallback(std::function callback); void setDeselectedCallback(std::function callback); void setActivatedCallback(std::function callback); std::size_t getIndex() const; bool isSelected() const; private: friend class Menu; MenuItem(Menu* parent, std::size_t index); Menu* parent; std::size_t index; bool selected; std::function selectedCallback; std::function deselectedCallback; std::function activatedCallback; }; inline std::size_t MenuItem::getIndex() const { return index; } inline bool MenuItem::isSelected() const { return selected; } class Menu { public: Menu(); ~Menu(); void enter(); void exit(); MenuItem* addItem(); void removeItems(); void setEnteredCallback(std::function callback); void setExitedCallback(std::function callback); std::size_t getItemCount(); const MenuItem* getItem(std::size_t index) const; MenuItem* getItem(std::size_t index); private: std::vector items; std::function enteredCallback; std::function exitedCallback; }; inline std::size_t Menu::getItemCount() { return items.size(); } inline const MenuItem* Menu::getItem(std::size_t index) const { return items[index]; } inline MenuItem* Menu::getItem(std::size_t index) { return items[index]; } #endif // UI_HPP