💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

506 lines
11 KiB

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef UI_HPP
#define UI_HPP
#include "../input.hpp"
#include "../materials.hpp"
#include <vector>
#include <functional>
#include <emergent/emergent.hpp>
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<void()> callback);
void setMouseOutCallback(std::function<void()> callback);
void setMouseMovedCallback(std::function<void()> callback);
void setMousePressedCallback(std::function<void(int)> callback);
void setMouseReleasedCallback(std::function<void(int)> 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<UIElement*> 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<void()> mouseOverCallback;
std::function<void()> mouseOutCallback;
std::function<void()> mouseMovedCallback;
std::function<void(int)> mousePressedCallback;
std::function<void(int)> 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<const UIElement*>* 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<void()> callback);
void setDeselectedCallback(std::function<void()> callback);
void setActivatedCallback(std::function<void()> 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<void()> selectedCallback;
std::function<void()> deselectedCallback;
std::function<void()> 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<void()> callback);
void setExitedCallback(std::function<void()> callback);
std::size_t getItemCount();
const MenuItem* getItem(std::size_t index) const;
MenuItem* getItem(std::size_t index);
private:
std::vector<MenuItem*> items;
std::function<void()> enteredCallback;
std::function<void()> 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