frontend/gui moved to graphics/ui

This commit is contained in:
MihailRis
2024-03-19 00:08:46 +03:00
parent b56408a202
commit 5393977e57
26 changed files with 139 additions and 140 deletions
+16 -16
View File
@@ -3,28 +3,28 @@
#include <iostream>
#include <glm/glm.hpp>
#include "BlocksPreview.h"
#include "LevelFrontend.h"
#include "../window/Events.h"
#include "../window/input.h"
#include "../assets/Assets.h"
#include "../graphics/core/Atlas.h"
#include "../graphics/core/Shader.h"
#include "../graphics/core/Batch2D.h"
#include "../graphics/core/GfxContext.h"
#include "../graphics/core/Font.h"
#include "../content/Content.h"
#include "../items/ItemDef.h"
#include "../items/Inventory.h"
#include "../graphics/core/Atlas.h"
#include "../graphics/core/Batch2D.h"
#include "../graphics/core/Font.h"
#include "../graphics/core/GfxContext.h"
#include "../graphics/core/Shader.h"
#include "../graphics/ui/elements/containers.h"
#include "../graphics/ui/elements/controls.h"
#include "../items/Inventories.h"
#include "../items/Inventory.h"
#include "../items/ItemDef.h"
#include "../logic/scripting/scripting.h"
#include "../maths/voxmaths.h"
#include "../objects/Player.h"
#include "../voxels/Block.h"
#include "../frontend/gui/containers.h"
#include "../frontend/gui/controls.h"
#include "../util/stringutil.h"
#include "../voxels/Block.h"
#include "../window/Events.h"
#include "../window/input.h"
#include "../world/Level.h"
#include "../logic/scripting/scripting.h"
#include "BlocksPreview.h"
#include "LevelFrontend.h"
SlotLayout::SlotLayout(
int index,
@@ -369,7 +369,7 @@ void InventoryView::setInventory(std::shared_ptr<Inventory> inventory) {
}
#include "../coders/xml.h"
#include "gui/gui_xml.h"
#include "../graphics/ui/gui_xml.h"
static slotcallback readSlotFunc(InventoryView* view, gui::UiXmlReader& reader, xml::xmlelement& element, const std::string& attr) {
auto consumer = scripting::create_int_array_consumer(
+3 -3
View File
@@ -5,9 +5,9 @@
#include <functional>
#include <glm/glm.hpp>
#include "../frontend/gui/UINode.h"
#include "../frontend/gui/containers.h"
#include "../frontend/gui/controls.h"
#include "../graphics/ui/elements/UINode.h"
#include "../graphics/ui/elements/containers.h"
#include "../graphics/ui/elements/controls.h"
#include "../items/ItemStack.h"
#include "../typedefs.h"
+5 -6
View File
@@ -1,12 +1,11 @@
#include "UiDocument.h"
#include <iostream>
#include "gui/UINode.h"
#include "gui/containers.h"
#include "InventoryView.h"
#include "../logic/scripting/scripting.h"
#include "../files/files.h"
#include "../frontend/gui/gui_xml.h"
#include "../graphics/ui/elements/containers.h"
#include "../graphics/ui/elements/UINode.h"
#include "../graphics/ui/gui_xml.h"
#include "../logic/scripting/scripting.h"
#include "InventoryView.h"
UiDocument::UiDocument(
std::string id,
+9 -9
View File
@@ -2,18 +2,18 @@
#include <memory>
#include <sstream>
#include "gui/controls.h"
#include "../audio/audio.h"
#include "../graphics/core/Mesh.h"
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "../world/Level.h"
#include "../world/World.h"
#include "../voxels/Chunks.h"
#include "../voxels/Block.h"
#include "../util/stringutil.h"
#include "../delegates.h"
#include "../engine.h"
#include "../graphics/core/Mesh.h"
#include "../graphics/ui/elements/controls.h"
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "../util/stringutil.h"
#include "../voxels/Block.h"
#include "../voxels/Chunks.h"
#include "../world/Level.h"
#include "../world/World.h"
#include "WorldRenderer.h"
-192
View File
@@ -1,192 +0,0 @@
#include "GUI.h"
#include "UINode.h"
#include "containers.h"
#include <iostream>
#include <algorithm>
#include "../../assets/Assets.h"
#include "../../graphics/core/Batch2D.h"
#include "../../graphics/core/Shader.h"
#include "../../graphics/core/GfxContext.h"
#include "../../window/Events.h"
#include "../../window/input.h"
#include "../../window/Camera.h"
using namespace gui;
GUI::GUI() {
container = std::make_shared<Container>(glm::vec2(1000));
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
uicamera->perspective = false;
uicamera->flipped = true;
menu = std::make_shared<PagesControl>();
container->add(menu);
container->setScrollable(false);
}
GUI::~GUI() {
}
std::shared_ptr<PagesControl> GUI::getMenu() {
return menu;
}
/** Mouse related input and logic handling
* @param delta delta time
*/
void GUI::actMouse(float delta) {
auto hover = container->getAt(Events::cursor, nullptr);
if (this->hover && this->hover != hover) {
this->hover->setHover(false);
}
if (hover) {
hover->setHover(true);
if (Events::scroll) {
hover->scrolled(Events::scroll);
}
}
this->hover = hover;
if (Events::jclicked(mousecode::BUTTON_1)) {
if (pressed == nullptr && this->hover) {
pressed = hover;
pressed->click(this, Events::cursor.x, Events::cursor.y);
if (focus && focus != pressed) {
focus->defocus();
}
if (focus != pressed) {
focus = pressed;
focus->onFocus(this);
return;
}
}
if (this->hover == nullptr && focus) {
focus->defocus();
focus = nullptr;
}
} else if (pressed) {
pressed->mouseRelease(this, Events::cursor.x, Events::cursor.y);
pressed = nullptr;
}
if (hover) {//WTF?! FIXME
for (int i = static_cast<int>(mousecode::BUTTON_1); i < static_cast<int>(mousecode::BUTTON_1)+12; i++) {
if (Events::jclicked(i)) {
hover->clicked(this, static_cast<mousecode>(i));
}
}
}
}
/** Processing user input and UI logic
* @param delta delta time
*/
void GUI::act(float delta) {
while (!postRunnables.empty()) {
runnable callback = postRunnables.back();
postRunnables.pop();
callback();
}
container->setSize(glm::vec2(Window::width, Window::height));
container->act(delta);
auto prevfocus = focus;
if (!Events::_cursor_locked) {
actMouse(delta);
}
if (focus) {
if (Events::jpressed(keycode::ESCAPE)) {
focus->defocus();
focus = nullptr;
} else {
for (auto codepoint : Events::codepoints) {
focus->typed(codepoint);
}
for (auto key : Events::pressedKeys) {
focus->keyPressed(key);
}
if (!Events::_cursor_locked) {
if (Events::clicked(mousecode::BUTTON_1)) {
if (Events::jclicked(mousecode::BUTTON_1) ||
Events::delta.x || Events::delta.y)
{
focus->mouseMove(this, Events::cursor.x, Events::cursor.y);
}
}
}
}
}
if (focus && !focus->isFocused()) {
focus = nullptr;
}
}
void GUI::draw(const GfxContext* pctx, Assets* assets) {
auto& viewport = pctx->getViewport();
glm::vec2 wsize = viewport.size();
menu->setPos((wsize - menu->getSize()) / 2.0f);
uicamera->setFov(wsize.y);
Shader* uishader = assets->getShader("ui");
uishader->use();
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
pctx->getBatch2D()->begin();
container->draw(pctx, assets);
}
std::shared_ptr<UINode> GUI::getFocused() const {
return focus;
}
bool GUI::isFocusCaught() const {
return focus && focus->isFocuskeeper();
}
void GUI::add(std::shared_ptr<UINode> node) {
container->add(node);
}
void GUI::remove(std::shared_ptr<UINode> node) noexcept {
container->remove(node);
}
void GUI::store(std::string name, std::shared_ptr<UINode> node) {
storage[name] = node;
}
std::shared_ptr<UINode> GUI::get(std::string name) noexcept {
auto found = storage.find(name);
if (found == storage.end()) {
return nullptr;
}
return found->second;
}
void GUI::remove(std::string name) noexcept {
storage.erase(name);
}
void GUI::setFocus(std::shared_ptr<UINode> node) {
if (focus) {
focus->defocus();
}
focus = node;
if (focus) {
focus->onFocus(this);
}
}
std::shared_ptr<Container> GUI::getContainer() const {
return container;
}
void GUI::postRunnable(runnable callback) {
postRunnables.push(callback);
}
-128
View File
@@ -1,128 +0,0 @@
#ifndef FRONTEND_GUI_GUI_H_
#define FRONTEND_GUI_GUI_H_
#include <queue>
#include <memory>
#include <vector>
#include <string>
#include <glm/glm.hpp>
#include <functional>
#include <unordered_map>
#include "../../delegates.h"
class GfxContext;
class Assets;
class Camera;
/*
Some info about padding and margin.
Padding is element inner space, margin is outer
glm::vec4 usage:
x - left
y - top
z - right
w - bottom
Outer element
+======================================================================+
| . . . . |
| .padding.y . . . |
| padding.x . . . . padding.z |
|- - - - - - + - - - - - + - - - - - - - - - -+- - - - - + - - - - - - |
| . . . . |
| . .margin.y . . |
| .margin.x . . margin.z. |
|- - - - - - + - - - - - +====================+- - - - - + - - - - - - |
| . | Inner element | . |
|- - - - - - + - - - - - +====================+- - - - - + - - - - - - |
| . . . . |
| . .margin.w . . |
| . . . . |
|- - - - - - + - - - - - + - - - - - - - - - -+- - - - - + - - - - - - |
| . . . . |
| .padding.w . . . |
| . . . . |
+======================================================================+
*/
namespace gui {
class UINode;
class Container;
class PagesControl;
/// @brief The main UI controller
class GUI {
std::shared_ptr<Container> container;
std::shared_ptr<UINode> hover = nullptr;
std::shared_ptr<UINode> pressed = nullptr;
std::shared_ptr<UINode> focus = nullptr;
std::unordered_map<std::string, std::shared_ptr<UINode>> storage;
std::unique_ptr<Camera> uicamera;
std::shared_ptr<PagesControl> menu;
std::queue<runnable> postRunnables;
void actMouse(float delta);
public:
GUI();
~GUI();
/// @brief Get the main menu (PagesControl) node
std::shared_ptr<PagesControl> getMenu();
/// @brief Get current focused node
/// @return focused node or nullptr
std::shared_ptr<UINode> getFocused() const;
/// @brief Check if all user input is caught by some element like TextBox
bool isFocusCaught() const;
/// @brief Main input handling and logic update method
/// @param delta delta time
void act(float delta);
/// @brief Draw all visible elements on main container
/// @param pctx parent graphics context
/// @param assets active assets storage
void draw(const GfxContext* pctx, Assets* assets);
/// @brief Add element to the main container
/// @param node UI element
void add(std::shared_ptr<UINode> node);
/// @brief Add element to the main container
/// @param node UI element
/// @param coord element position within the main container
void add(std::shared_ptr<UINode> node, glm::vec2 coord);
/// @brief Remove node from the main container
void remove(std::shared_ptr<UINode> node) noexcept;
/// @brief Store node in the GUI nodes dictionary
/// (does not add node to the main container)
/// @param name node key
/// @param node target node
void store(std::string name, std::shared_ptr<UINode> node);
/// @brief Get node from the GUI nodes dictionary
/// @param name node key
/// @return stored node or nullptr
std::shared_ptr<UINode> get(std::string name) noexcept;
/// @brief Remove node from the GUI nodes dictionary
/// @param name node key
void remove(std::string name) noexcept;
/// @brief Set node as focused
/// @param node new focused node or nullptr to remove focus
void setFocus(std::shared_ptr<UINode> node);
/// @brief Get the main container
/// @deprecated
std::shared_ptr<Container> getContainer() const;
void postRunnable(runnable callback);
};
}
#endif // FRONTEND_GUI_GUI_H_
-239
View File
@@ -1,239 +0,0 @@
#include "UINode.h"
#include "../../graphics/core/Batch2D.h"
using gui::UINode;
using gui::Align;
UINode::UINode(glm::vec2 size) : size(size) {
}
UINode::~UINode() {
}
bool UINode::isVisible() const {
return visible;
}
void UINode::setVisible(bool flag) {
visible = flag;
}
Align UINode::getAlign() const {
return align;
}
void UINode::setAlign(Align align) {
this->align = align;
}
void UINode::setHover(bool flag) {
hover = flag;
}
bool UINode::isHover() const {
return hover;
}
void UINode::setParent(UINode* node) {
parent = node;
}
UINode* UINode::getParent() const {
return parent;
}
void UINode::click(GUI*, int x, int y) {
pressed = true;
}
void UINode::mouseRelease(GUI*, int x, int y) {
pressed = false;
}
bool UINode::isPressed() const {
return pressed;
}
void UINode::defocus() {
focused = false;
}
bool UINode::isFocused() const {
return focused;
}
bool UINode::isInside(glm::vec2 point) {
glm::vec2 pos = calcPos();
glm::vec2 size = getSize();
return (point.x >= pos.x && point.y >= pos.y &&
point.x < pos.x + size.x && point.y < pos.y + size.y);
}
std::shared_ptr<UINode> UINode::getAt(glm::vec2 point, std::shared_ptr<UINode> self) {
if (!interactive) {
return nullptr;
}
return isInside(point) ? self : nullptr;
}
bool UINode::isInteractive() const {
return interactive && isVisible();
}
void UINode::setInteractive(bool flag) {
interactive = flag;
}
void UINode::setResizing(bool flag) {
resizing = flag;
}
bool UINode::isResizing() const {
return resizing;
}
glm::vec2 UINode::calcPos() const {
if (parent) {
return pos + parent->calcPos() + parent->contentOffset();
}
return pos;
}
void UINode::scrolled(int value) {
if (parent) {
parent->scrolled(value);
}
}
void UINode::setPos(glm::vec2 pos) {
this->pos = pos;
}
glm::vec2 UINode::getPos() const {
return pos;
}
glm::vec2 UINode::getSize() const {
return size;
}
void UINode::setSize(glm::vec2 size) {
this->size = glm::vec2(
glm::max(minSize.x, size.x), glm::max(minSize.y, size.y)
);
}
glm::vec2 UINode::getMinSize() const {
return minSize;
}
void UINode::setMinSize(glm::vec2 minSize) {
this->minSize = minSize;
setSize(getSize());
}
void UINode::setColor(glm::vec4 color) {
this->color = color;
this->hoverColor = color;
}
void UINode::setHoverColor(glm::vec4 newColor) {
this->hoverColor = newColor;
}
glm::vec4 UINode::getHoverColor() const {
return hoverColor;
}
glm::vec4 UINode::getColor() const {
return color;
}
void UINode::setMargin(glm::vec4 margin) {
this->margin = margin;
}
glm::vec4 UINode::getMargin() const {
return margin;
}
void UINode::setZIndex(int zindex) {
this->zindex = zindex;
}
int UINode::getZIndex() const {
return zindex;
}
void UINode::lock() {
}
vec2supplier UINode::getPositionFunc() const {
return positionfunc;
}
void UINode::setPositionFunc(vec2supplier func) {
positionfunc = func;
}
void UINode::setId(const std::string& id) {
this->id = id;
}
const std::string& UINode::getId() const {
return id;
}
void UINode::reposition() {
if (positionfunc) {
setPos(positionfunc());
}
}
void UINode::setGravity(Gravity gravity) {
if (gravity == Gravity::none) {
setPositionFunc(nullptr);
return;
}
setPositionFunc([this, gravity](){
auto parent = getParent();
if (parent == nullptr) {
return getPos();
}
glm::vec4 margin = getMargin();
glm::vec2 size = getSize();
glm::vec2 parentSize = parent->getSize();
float x = 0.0f, y = 0.0f;
switch (gravity) {
case Gravity::top_left:
case Gravity::center_left:
case Gravity::bottom_left: x = parentSize.x+margin.x; break;
case Gravity::top_center:
case Gravity::center_center:
case Gravity::bottom_center: x = (parentSize.x-size.x)/2.0f; break;
case Gravity::top_right:
case Gravity::center_right:
case Gravity::bottom_right: x = parentSize.x-size.x-margin.z; break;
default: break;
}
switch (gravity) {
case Gravity::top_left:
case Gravity::top_center:
case Gravity::top_right: y = parentSize.y+margin.y; break;
case Gravity::center_left:
case Gravity::center_center:
case Gravity::center_right: y = (parentSize.y-size.y)/2.0f; break;
case Gravity::bottom_left:
case Gravity::bottom_center:
case Gravity::bottom_right: y = parentSize.y-size.y-margin.w; break;
default: break;
}
return glm::vec2(x, y);
});
if (parent) {
reposition();
}
}
-185
View File
@@ -1,185 +0,0 @@
#ifndef FRONTEND_GUI_UINODE_H_
#define FRONTEND_GUI_UINODE_H_
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <string>
#include <functional>
#include "../../delegates.h"
#include "../../window/input.h"
class GfxContext;
class Assets;
namespace gui {
class UINode;
class GUI;
using onaction = std::function<void(GUI*)>;
using onnumberchange = std::function<void(GUI*, double)>;
enum class Align {
left, center, right,
top=left, bottom=right,
};
enum class Gravity {
none,
top_left,
top_center,
top_right,
center_left,
center_center,
center_right,
bottom_left,
bottom_center,
bottom_right
};
/// @brief Base abstract class for all UI elements
class UINode {
/// @brief element identifier used for direct access in UiDocument
std::string id = "";
protected:
/// @brief element position within the parent element
glm::vec2 pos {0.0f};
/// @brief element size (width, height)
glm::vec2 size;
/// @brief minimal element size
glm::vec2 minSize {1.0f};
/// @brief element primary color (background-color or text-color if label)
glm::vec4 color {1.0f};
/// @brief element color when mouse is over it
glm::vec4 hoverColor {1.0f};
/// @brief element margin (only supported for Panel sub-nodes)
glm::vec4 margin {1.0f};
/// @brief is element visible
bool visible = true;
/// @brief is mouse over the element
bool hover = false;
/// @brief is mouse has been pressed over the element and not released yet
bool pressed = false;
/// @brief is element focused
bool focused = false;
/// @brief is element opaque for cursor interaction
bool interactive = true;
/// @brief does the element support resizing by parent elements
bool resizing = true;
/// @brief z-index property specifies the stack order of an element
int zindex = 0;
/// @brief element content alignment (supported by Label only)
Align align = Align::left;
/// @brief parent element
UINode* parent = nullptr;
/// @brief position supplier for the element (called on parent element size update)
vec2supplier positionfunc = nullptr;
UINode(glm::vec2 size);
public:
virtual ~UINode();
/// @brief Called every frame for all visible elements
/// @param delta delta timУ
virtual void act(float delta) {};
virtual void draw(const GfxContext* pctx, Assets* assets) = 0;
virtual void setVisible(bool flag);
bool isVisible() const;
virtual void setAlign(Align align);
Align getAlign() const;
virtual void setHover(bool flag);
bool isHover() const;
virtual void setParent(UINode* node);
UINode* getParent() const;
/// @brief Set element color (doesn't affect inner elements).
/// Also replaces hover color to avoid adding extra properties
virtual void setColor(glm::vec4 newColor);
/// @brief Get element color
/// @return (float R,G,B,A in range [0.0, 1.0])
glm::vec4 getColor() const;
virtual void setHoverColor(glm::vec4 newColor);
glm::vec4 getHoverColor() const;
virtual void setMargin(glm::vec4 margin);
glm::vec4 getMargin() const;
/// @brief Specifies the stack order of an element
/// @attention Is not supported by Panel
virtual void setZIndex(int idx);
/// @brief Get element z-index
int getZIndex() const;
virtual void onFocus(GUI*) {focused = true;}
virtual void click(GUI*, int x, int y);
virtual void clicked(GUI*, mousecode button) {}
virtual void mouseMove(GUI*, int x, int y) {};
virtual void mouseRelease(GUI*, int x, int y);
virtual void scrolled(int value);
bool isPressed() const;
void defocus();
bool isFocused() const;
/** Check if element catches all user input when focused */
virtual bool isFocuskeeper() const {return false;}
virtual void typed(unsigned int codepoint) {};
virtual void keyPressed(keycode key) {};
/** Check if screen position is inside of the element
* @param pos screen position */
virtual bool isInside(glm::vec2 pos);
/** Get element under the cursor.
* @param pos cursor screen position
* @param self shared pointer to element
* @return self, sub-element or nullptr if element is not interractive */
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self);
/* Check if element is opaque for cursor */
virtual bool isInteractive() const;
/* Make the element opaque (true) or transparent (false) for cursor */
virtual void setInteractive(bool flag);
virtual void setResizing(bool flag);
virtual bool isResizing() const;
/* Get inner content offset. Used for scroll */
virtual glm::vec2 contentOffset() {return glm::vec2(0.0f);};
/* Calculate screen position of the element */
virtual glm::vec2 calcPos() const;
virtual void setPos(glm::vec2 pos);
virtual glm::vec2 getPos() const;
virtual glm::vec2 getSize() const;
virtual void setSize(glm::vec2 size);
virtual glm::vec2 getMinSize() const;
virtual void setMinSize(glm::vec2 size);
/* Called in containers when new element added */
virtual void refresh() {};
virtual void lock();
virtual vec2supplier getPositionFunc() const;
virtual void setPositionFunc(vec2supplier);
void setId(const std::string& id);
const std::string& getId() const;
/* Fetch pos from positionfunc if assigned */
void reposition();
virtual void setGravity(Gravity gravity);
};
}
#endif // FRONTEND_GUI_UINODE_H_
-300
View File
@@ -1,300 +0,0 @@
#include "containers.h"
#include <stdexcept>
#include <algorithm>
#include "../../window/Window.h"
#include "../../assets/Assets.h"
#include "../../graphics/core/Batch2D.h"
#include "../../graphics/core/GfxContext.h"
using namespace gui;
Container::Container(glm::vec2 size) : UINode(size) {
actualLength = size.y;
setColor(glm::vec4());
}
std::shared_ptr<UINode> Container::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
if (!interactive) {
return nullptr;
}
if (!isInside(pos)) return nullptr;
for (int i = nodes.size()-1; i >= 0; i--) {
auto& node = nodes[i];
if (!node->isVisible())
continue;
auto hover = node->getAt(pos, node);
if (hover != nullptr) {
return hover;
}
}
return UINode::getAt(pos, self);
}
void Container::act(float delta) {
for (auto node : nodes) {
if (node->isVisible()) {
node->act(delta);
}
}
for (IntervalEvent& event : intervalEvents) {
event.timer += delta;
if (event.timer > event.interval) {
event.callback();
event.timer = fmod(event.timer, event.interval);
if (event.repeat > 0) {
event.repeat--;
}
}
}
intervalEvents.erase(std::remove_if(
intervalEvents.begin(), intervalEvents.end(),
[](const IntervalEvent& event) {
return event.repeat == 0;
}
), intervalEvents.end());
}
void Container::scrolled(int value) {
int diff = (actualLength-getSize().y);
if (scroll < 0 && diff <= 0) {
scroll = 0;
}
if (diff > 0 && scrollable) {
scroll += value * scrollStep;
if (scroll > 0)
scroll = 0;
if (-scroll > diff) {
scroll = -diff;
}
} else if (parent) {
parent->scrolled(value);
}
}
void Container::setScrollable(bool flag) {
scrollable = flag;
}
void Container::draw(const GfxContext* pctx, Assets* assets) {
glm::vec2 pos = calcPos();
glm::vec2 size = getSize();
drawBackground(pctx, assets);
auto batch = pctx->getBatch2D();
batch->texture(nullptr);
batch->flush();
{
GfxContext ctx = pctx->sub();
ctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y));
for (auto node : nodes) {
if (node->isVisible())
node->draw(pctx, assets);
}
}
}
void Container::drawBackground(const GfxContext* pctx, Assets* assets) {
if (color.a <= 0.0f)
return;
glm::vec2 pos = calcPos();
auto batch = pctx->getBatch2D();
batch->texture(nullptr);
batch->setColor(color);
batch->rect(pos.x, pos.y, size.x, size.y);
}
void Container::add(std::shared_ptr<UINode> node) {
nodes.push_back(node);
node->setParent(this);
node->reposition();
refresh();
}
void Container::add(std::shared_ptr<UINode> node, glm::vec2 pos) {
node->setPos(pos);
add(node);
}
void Container::remove(std::shared_ptr<UINode> selected) {
selected->setParent(nullptr);
nodes.erase(std::remove_if(nodes.begin(), nodes.end(),
[selected](const std::shared_ptr<UINode> node) {
return node == selected;
}
), nodes.end());
refresh();
}
void Container::listenInterval(float interval, ontimeout callback, int repeat) {
intervalEvents.push_back({callback, interval, 0.0f, repeat});
}
void Container::setSize(glm::vec2 size) {
if (size == getSize()) {
refresh();
return;
}
UINode::setSize(size);
refresh();
for (auto& node : nodes) {
node->reposition();
}
}
void Container::refresh() {
std::stable_sort(nodes.begin(), nodes.end(), [](const auto& a, const auto& b) {
return a->getZIndex() < b->getZIndex();
});
}
const std::vector<std::shared_ptr<UINode>>& Container::getNodes() const {
return nodes;
}
Panel::Panel(glm::vec2 size, glm::vec4 padding, float interval)
: Container(size),
padding(padding),
interval(interval)
{
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
}
Panel::~Panel() {
}
void Panel::setMaxLength(int value) {
maxLength = value;
}
int Panel::getMaxLength() const {
return maxLength;
}
void Panel::setPadding(glm::vec4 padding) {
this->padding = padding;
refresh();
}
glm::vec4 Panel::getPadding() const {
return padding;
}
void Panel::cropToContent() {
if (maxLength > 0.0f) {
setSize(glm::vec2(getSize().x, glm::min(maxLength, actualLength)));
} else {
setSize(glm::vec2(getSize().x, actualLength));
}
}
void Panel::add(std::shared_ptr<UINode> node) {
Container::add(node);
refresh();
cropToContent();
}
void Panel::refresh() {
UINode::refresh();
float x = padding.x;
float y = padding.y;
glm::vec2 size = getSize();
if (orientation == Orientation::vertical) {
float maxw = size.x;
for (auto& node : nodes) {
glm::vec2 nodesize = node->getSize();
const glm::vec4 margin = node->getMargin();
y += margin.y;
float ex = x + margin.x;
node->setPos(glm::vec2(ex, y));
y += nodesize.y + margin.w + interval;
float width = size.x - padding.x - padding.z - margin.x - margin.z;
if (node->isResizing()) {
node->setSize(glm::vec2(width, nodesize.y));
}
node->refresh();
maxw = fmax(maxw, ex+node->getSize().x+margin.z+padding.z);
}
actualLength = y + padding.w;
} else {
float maxh = size.y;
for (auto& node : nodes) {
glm::vec2 nodesize = node->getSize();
const glm::vec4 margin = node->getMargin();
x += margin.x;
node->setPos(glm::vec2(x, y+margin.y));
x += nodesize.x + margin.z + interval;
node->refresh();
maxh = fmax(maxh, y+margin.y+node->getSize().y+margin.w+padding.w);
}
actualLength = size.y;
}
}
void Panel::setOrientation(Orientation orientation) {
this->orientation = orientation;
}
Orientation Panel::getOrientation() const {
return orientation;
}
PagesControl::PagesControl() : Container(glm::vec2(1)){
}
bool PagesControl::has(std::string name) {
return pages.find(name) != pages.end();
}
void PagesControl::addPage(std::string name, std::shared_ptr<UINode> panel) {
pages[name] = Page{panel};
}
void PagesControl::setPage(std::string name, bool history) {
auto found = pages.find(name);
if (found == pages.end()) {
throw std::runtime_error("no page found");
}
if (current.panel) {
Container::remove(current.panel);
}
if (history) {
pageStack.push(curname);
}
curname = name;
current = found->second;
Container::add(current.panel);
setSize(current.panel->getSize());
}
void PagesControl::back() {
if (pageStack.empty())
return;
std::string name = pageStack.top();
pageStack.pop();
setPage(name, false);
}
Page& PagesControl::getCurrent() {
return current;
}
void PagesControl::clearHistory() {
pageStack = std::stack<std::string>();
}
void PagesControl::reset() {
clearHistory();
if (current.panel) {
curname = "";
Container::remove(current.panel);
current = Page{nullptr};
}
}
-112
View File
@@ -1,112 +0,0 @@
#ifndef FRONTEND_GUI_CONTAINERS_H_
#define FRONTEND_GUI_CONTAINERS_H_
#include <glm/glm.hpp>
#include <vector>
#include <stack>
#include <string>
#include <memory>
#include "UINode.h"
class Batch2D;
class Assets;
namespace gui {
using ontimeout = std::function<void()>;
struct IntervalEvent {
ontimeout callback;
float interval;
float timer;
// -1 - infinity, 1 - one time event
int repeat;
};
enum class Orientation { vertical, horizontal };
class Container : public UINode {
protected:
std::vector<std::shared_ptr<UINode>> nodes;
std::vector<IntervalEvent> intervalEvents;
int scroll = 0;
int scrollStep = 40;
int actualLength = 0;
bool scrollable = true;
public:
Container(glm::vec2 size);
virtual void act(float delta) override;
virtual void drawBackground(const GfxContext* pctx, Assets* assets);
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
virtual void add(std::shared_ptr<UINode> node);
virtual void add(std::shared_ptr<UINode> node, glm::vec2 pos);
virtual void remove(std::shared_ptr<UINode> node);
virtual void scrolled(int value) override;
virtual void setScrollable(bool flag);
void listenInterval(float interval, ontimeout callback, int repeat=-1);
virtual glm::vec2 contentOffset() override {return glm::vec2(0.0f, scroll);};
virtual void setSize(glm::vec2 size) override;
virtual void refresh() override;
const std::vector<std::shared_ptr<UINode>>& getNodes() const;
};
class Panel : public Container {
protected:
Orientation orientation = Orientation::vertical;
glm::vec4 padding {2.0f};
float interval = 2.0f;
int maxLength = 0;
public:
Panel(
glm::vec2 size,
glm::vec4 padding=glm::vec4(2.0f),
float interval=2.0f
);
virtual ~Panel();
virtual void cropToContent();
virtual void setOrientation(Orientation orientation);
Orientation getOrientation() const;
virtual void add(std::shared_ptr<UINode> node) override;
virtual void refresh() override;
virtual void setMaxLength(int value);
int getMaxLength() const;
virtual void setPadding(glm::vec4 padding);
glm::vec4 getPadding() const;
};
struct Page {
std::shared_ptr<UINode> panel = nullptr;
~Page() {
panel = nullptr;
}
};
class PagesControl : public Container {
protected:
std::unordered_map<std::string, Page> pages;
std::stack<std::string> pageStack;
Page current;
std::string curname = "";
public:
PagesControl();
bool has(std::string name);
void setPage(std::string name, bool history=true);
void addPage(std::string name, std::shared_ptr<UINode> panel);
void back();
void clearHistory();
void reset();
Page& getCurrent();
};
}
#endif // FRONTEND_GUI_CONTAINERS_H_
File diff suppressed because it is too large Load Diff
-390
View File
@@ -1,390 +0,0 @@
#ifndef FRONTEND_GUI_CONTROLS_H_
#define FRONTEND_GUI_CONTROLS_H_
#include <string>
#include <memory>
#include <vector>
#include <functional>
#include <glm/glm.hpp>
#include "GUI.h"
#include "UINode.h"
#include "containers.h"
#include "../../window/input.h"
#include "../../delegates.h"
#include "../../typedefs.h"
class Batch2D;
class Assets;
class Font;
namespace gui {
class Label : public UINode {
protected:
std::wstring text;
std::string fontName;
wstringsupplier supplier = nullptr;
uint lines = 1;
float lineInterval = 1.5f;
Align valign = Align::center;
bool multiline = false;
// runtime values
/// @brief Text Y offset relative to label position
/// (last calculated alignment)
int textYOffset = 0;
/// @brief Text line height multiplied by line interval
int totalLineHeight = 1;
public:
Label(std::string text, std::string fontName="normal");
Label(std::wstring text, std::string fontName="normal");
virtual void setText(std::wstring text);
const std::wstring& getText() const;
virtual void setFontName(std::string name);
virtual const std::string& getFontName() const;
/// @brief Set text vertical alignment (default value: center)
/// @param align Align::top / Align::center / Align::bottom
virtual void setVerticalAlign(Align align);
virtual Align getVerticalAlign() const;
/// @brief Get line height multiplier used for multiline labels
/// (default value: 1.5)
virtual float getLineInterval() const;
/// @brief Set line height multiplier used for multiline labels
virtual void setLineInterval(float interval);
/// @brief Get Y position of the text relative to label position
/// @return Y offset
virtual int getTextYOffset() const;
/// @brief Get Y position of the line relative to label position
/// @param line target line index
/// @return Y offset
virtual int getLineYOffset(uint line) const;
/// @brief Get position of line start in the text
/// @param line target line index
/// @return position in the text [0..length]
virtual size_t getTextLineOffset(uint line) const;
/// @brief Get line index by its Y offset relative to label position
/// @param offset target Y offset
/// @return line index [0..+]
virtual uint getLineByYOffset(int offset) const;
virtual uint getLineByTextIndex(size_t index) const;
virtual uint getLinesNumber() const;
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual void textSupplier(wstringsupplier supplier);
virtual void setMultiline(bool multiline);
virtual bool isMultiline() const;
};
class Image : public UINode {
protected:
std::string texture;
bool autoresize = false;
public:
Image(std::string texture, glm::vec2 size=glm::vec2(32,32));
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual void setAutoResize(bool flag);
virtual bool isAutoResize() const;
};
class Button : public Panel {
protected:
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
std::vector<onaction> actions;
std::shared_ptr<Label> label = nullptr;
public:
Button(std::shared_ptr<UINode> content,
glm::vec4 padding=glm::vec4(2.0f));
Button(std::wstring text,
glm::vec4 padding,
onaction action,
glm::vec2 size=glm::vec2(-1));
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
virtual void mouseRelease(GUI*, int x, int y) override;
virtual Button* listenAction(onaction action);
virtual Align getTextAlign() const;
virtual void setTextAlign(Align align);
virtual void setText(std::wstring text);
virtual std::wstring getText() const;
virtual glm::vec4 getPressedColor() const;
virtual void setPressedColor(glm::vec4 color);
virtual Button* textSupplier(wstringsupplier supplier);
virtual void refresh() override;
};
class RichButton : public Container {
protected:
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
std::vector<onaction> actions;
public:
RichButton(glm::vec2 size);
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
virtual void mouseRelease(GUI*, int x, int y) override;
virtual RichButton* listenAction(onaction action);
};
class TextBox : public Panel {
protected:
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f};
std::shared_ptr<Label> label;
std::wstring input;
std::wstring placeholder;
wstringsupplier supplier = nullptr;
wstringconsumer consumer = nullptr;
wstringchecker validator = nullptr;
runnable onEditStart = nullptr;
bool valid = true;
/// @brief text input pointer, value may be greather than text length
uint caret = 0;
/// @brief actual local (line) position of the caret on vertical move
uint maxLocalCaret = 0;
uint textOffset = 0;
int textInitX;
/// @brief last time of the caret was moved (used for blink animation)
double caretLastMove = 0.0;
Font* font = nullptr;
size_t selectionStart = 0;
size_t selectionEnd = 0;
size_t selectionOrigin = 0;
bool multiline = false;
bool editable = true;
size_t normalizeIndex(int index);
int calcIndexAt(int x, int y) const;
void paste(const std::wstring& text);
void setTextOffset(uint x);
void erase(size_t start, size_t length);
bool eraseSelected();
void resetSelection();
void extendSelection(int index);
size_t getLineLength(uint line) const;
/// @brief Get total length of the selection
size_t getSelectionLength() const;
/// @brief Set maxLocalCaret to local (line) caret position
void resetMaxLocalCaret();
void performEditingKeyboardEvents(keycode key);
public:
TextBox(
std::wstring placeholder,
glm::vec4 padding=glm::vec4(4.0f)
);
virtual void setTextSupplier(wstringsupplier supplier);
/// @brief Consumer called on stop editing text (textbox defocus)
/// @param consumer std::wstring consumer function
virtual void setTextConsumer(wstringconsumer consumer);
/// @brief Text validator called while text editing and returns true if
/// text is valid
/// @param validator std::wstring consumer returning boolean
virtual void setTextValidator(wstringchecker validator);
virtual void setFocusedColor(glm::vec4 color);
virtual glm::vec4 getFocusedColor() const;
/// @brief Set color of textbox marked by validator as invalid
virtual void setErrorColor(glm::vec4 color);
/// @brief Get color of textbox marked by validator as invalid
virtual glm::vec4 getErrorColor() const;
/// @brief Get TextBox content text or placeholder if empty
virtual std::wstring getText() const;
/// @brief Set TextBox content text
virtual void setText(std::wstring value);
/// @brief Get text placeholder
virtual std::wstring getPlaceholder() const;
/// @brief Set text placeholder
/// @param text will be used instead of empty
virtual void setPlaceholder(const std::wstring& text);
/// @brief Get selected text
virtual std::wstring getSelection() const;
/// @brief Get current caret position in text
/// @return integer in range [0, text.length()]
virtual uint getCaret() const;
/// @brief Set caret position in the text
/// @param position integer in range [0, text.length()]
virtual void setCaret(uint position);
/// @brief Select part of the text
/// @param start index of the first selected character
/// @param end index of the last selected character + 1
virtual void select(int start, int end);
/// @brief Check text with validator set with setTextValidator
/// @return true if text is valid
virtual bool validate();
virtual void setValid(bool valid);
virtual bool isValid() const;
/// @brief Enable/disable multiline mode
virtual void setMultiline(bool multiline);
/// @brief Check if multiline mode is enabled
virtual bool isMultiline() const;
/// @brief Enable/disable text editing feature
virtual void setEditable(bool editable);
/// @brief Check if text editing feature is enabled
virtual bool isEditable() const;
/// @brief Set runnable called on textbox focus
virtual void setOnEditStart(runnable oneditstart);
virtual void onFocus(GUI*) override;
virtual void refresh() override;
virtual void click(GUI*, int, int) override;
virtual void mouseMove(GUI*, int x, int y) override;
virtual bool isFocuskeeper() const override {return true;}
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
virtual void typed(unsigned int codepoint) override;
virtual void keyPressed(keycode key) override;
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
};
class InputBindBox : public Panel {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
std::shared_ptr<Label> label;
Binding& binding;
public:
InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f));
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
virtual void clicked(GUI*, mousecode button) override;
virtual void keyPressed(keycode key) override;
virtual bool isFocuskeeper() const override {return true;}
};
class TrackBar : public UINode {
protected:
glm::vec4 trackColor {1.0f, 1.0f, 1.0f, 0.4f};
doublesupplier supplier = nullptr;
doubleconsumer consumer = nullptr;
double min;
double max;
double value;
double step;
int trackWidth;
public:
TrackBar(double min,
double max,
double value,
double step=1.0,
int trackWidth=1);
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual void setSupplier(doublesupplier supplier);
virtual void setConsumer(doubleconsumer consumer);
virtual void mouseMove(GUI*, int x, int y) override;
virtual double getValue() const;
virtual double getMin() const;
virtual double getMax() const;
virtual double getStep() const;
virtual int getTrackWidth() const;
virtual glm::vec4 getTrackColor() const;
virtual void setValue(double);
virtual void setMin(double);
virtual void setMax(double);
virtual void setStep(double);
virtual void setTrackWidth(int);
virtual void setTrackColor(glm::vec4);
};
class CheckBox : public UINode {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
glm::vec4 checkColor {1.0f, 1.0f, 1.0f, 0.4f};
boolsupplier supplier = nullptr;
boolconsumer consumer = nullptr;
bool checked = false;
public:
CheckBox(bool checked=false);
virtual void draw(const GfxContext* pctx, Assets* assets) override;
virtual void mouseRelease(GUI*, int x, int y) override;
virtual void setSupplier(boolsupplier supplier);
virtual void setConsumer(boolconsumer consumer);
virtual CheckBox* setChecked(bool flag);
virtual bool isChecked() const {
if (supplier)
return supplier();
return checked;
}
};
class FullCheckBox : public Panel {
protected:
std::shared_ptr<CheckBox> checkbox;
public:
FullCheckBox(std::wstring text, glm::vec2 size, bool checked=false);
virtual void setSupplier(boolsupplier supplier) {
checkbox->setSupplier(supplier);
}
virtual void setConsumer(boolconsumer consumer) {
checkbox->setConsumer(consumer);
}
virtual void setChecked(bool flag) {
checkbox->setChecked(flag);
}
virtual bool isChecked() const {
return checkbox->isChecked();
}
};
}
#endif // FRONTEND_GUI_CONTROLS_H_
-99
View File
@@ -1,99 +0,0 @@
#include "gui_util.h"
#include "controls.h"
#include "containers.h"
#include <glm/glm.hpp>
#include "../locale/langs.h"
#include "../../delegates.h"
using namespace gui;
std::shared_ptr<Button> guiutil::backButton(std::shared_ptr<PagesControl> menu) {
return std::make_shared<Button>(
langs::get(L"Back"), glm::vec4(10.f), [=](GUI*) {
menu->back();
}
);
}
std::shared_ptr<Button> guiutil::gotoButton(
std::wstring text,
const std::string& page,
std::shared_ptr<PagesControl> menu
) {
text = langs::get(text, L"menu");
return std::make_shared<Button>(text, glm::vec4(10.f), [=](GUI* gui) {
menu->setPage(page);
});
}
void guiutil::alert(GUI* gui, const std::wstring& text, runnable on_hidden) {
auto menu = gui->getMenu();
auto panel = std::make_shared<Panel>(glm::vec2(500, 200), glm::vec4(8.0f), 8.0f);
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
// TODO: implement built-in text wrapping
const int wrap_length = 60;
if (text.length() > wrap_length) {
size_t offset = 0;
int extra;
while ((extra = text.length() - offset) > 0) {
size_t endline = text.find(L'\n', offset);
if (endline != std::string::npos) {
extra = std::min(extra, int(endline-offset)+1);
}
extra = std::min(extra, wrap_length);
std::wstring part = text.substr(offset, extra);
panel->add(std::make_shared<Label>(part));
offset += extra;
}
} else {
panel->add(std::make_shared<Label>(text));
}
panel->add(std::make_shared<Button>(
langs::get(L"Ok"), glm::vec4(10.f),
[=](GUI* gui) {
if (on_hidden) {
on_hidden();
}
menu->back();
}
));
panel->refresh();
menu->addPage("<alert>", panel);
menu->setPage("<alert>");
}
void guiutil::confirm(
GUI* gui,
const std::wstring& text,
runnable on_confirm,
std::wstring yestext,
std::wstring notext) {
if (yestext.empty()) yestext = langs::get(L"Yes");
if (notext.empty()) notext = langs::get(L"No");
auto menu = gui->getMenu();
auto panel = std::make_shared<Panel>(glm::vec2(600, 200), glm::vec4(8.0f), 8.0f);
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
panel->add(std::make_shared<Label>(text));
auto subpanel = std::make_shared<Panel>(glm::vec2(600, 53));
subpanel->setColor(glm::vec4(0));
subpanel->add(std::make_shared<Button>(yestext, glm::vec4(8.f), [=](GUI*){
if (on_confirm)
on_confirm();
menu->back();
}));
subpanel->add(std::make_shared<Button>(notext, glm::vec4(8.f), [=](GUI*){
menu->back();
}));
panel->add(subpanel);
panel->refresh();
menu->addPage("<confirm>", panel);
menu->setPage("<confirm>");
}
-38
View File
@@ -1,38 +0,0 @@
#ifndef FRONTEND_GUI_GUI_UTIL_H_
#define FRONTEND_GUI_GUI_UTIL_H_
#include <memory>
#include <string>
#include "GUI.h"
#include "../../delegates.h"
namespace gui {
class Button;
}
namespace guiutil {
std::shared_ptr<gui::Button> backButton(
std::shared_ptr<gui::PagesControl> menu
);
std::shared_ptr<gui::Button> gotoButton(
std::wstring text,
const std::string& page,
std::shared_ptr<gui::PagesControl> menu
);
void alert(
gui::GUI* gui,
const std::wstring& text,
runnable on_hidden=nullptr
);
void confirm(
gui::GUI* gui,
const std::wstring& text,
runnable on_confirm=nullptr,
std::wstring yestext=L"",
std::wstring notext=L"");
}
#endif // FRONTEND_GUI_GUI_UTIL_H_
-384
View File
@@ -1,384 +0,0 @@
#include "gui_xml.h"
#include <charconv>
#include <stdexcept>
#include "containers.h"
#include "controls.h"
#include "../locale/langs.h"
#include "../../logic/scripting/scripting.h"
#include "../../util/stringutil.h"
using namespace gui;
static Align align_from_string(const std::string& str, Align def) {
if (str == "left") return Align::left;
if (str == "center") return Align::center;
if (str == "right") return Align::right;
if (str == "top") return Align::top;
if (str == "bottom") return Align::bottom;
return def;
}
static Gravity gravity_from_string(const std::string& str) {
static const std::unordered_map<std::string, Gravity> gravity_names {
{"top-left", Gravity::top_left},
{"top-center", Gravity::top_center},
{"top-right", Gravity::top_right},
{"center-left", Gravity::center_left},
{"center-center", Gravity::center_center},
{"center-right", Gravity::center_right},
{"bottom-left", Gravity::bottom_left},
{"bottom-center", Gravity::bottom_center},
{"bottom-right", Gravity::bottom_right},
};
auto found = gravity_names.find(str);
if (found == gravity_names.end()) {
return found->second;
}
return Gravity::none;
}
/* Read basic UINode properties */
static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) {
if (element->has("id")) {
node.setId(element->attr("id").getText());
}
if (element->has("pos")) {
node.setPos(element->attr("pos").asVec2());
}
if (element->has("size")) {
node.setSize(element->attr("size").asVec2());
}
if (element->has("color")) {
glm::vec4 color = element->attr("color").asColor();
glm::vec4 hoverColor = color;
if (element->has("hover-color")) {
hoverColor = node.getHoverColor();
}
node.setColor(color);
node.setHoverColor(hoverColor);
}
if (element->has("margin")) {
node.setMargin(element->attr("margin").asVec4());
}
if (element->has("z-index")) {
node.setZIndex(element->attr("z-index").asInt());
}
if (element->has("interactive")) {
node.setInteractive(element->attr("interactive").asBool());
}
if (element->has("visible")) {
node.setVisible(element->attr("visible").asBool());
}
if (element->has("position-func")) {
auto supplier = scripting::create_vec2_supplier(
reader.getEnvironment().getId(),
element->attr("position-func").getText(),
reader.getFilename()+".lua"
);
node.setPositionFunc(supplier);
}
if (element->has("hover-color")) {
node.setHoverColor(element->attr("hover-color").asColor());
}
std::string alignName = element->attr("align", "").getText();
node.setAlign(align_from_string(alignName, node.getAlign()));
if (element->has("gravity")) {
node.setGravity(gravity_from_string(
element->attr("gravity").getText()
));
}
}
static void _readContainer(UiXmlReader& reader, xml::xmlelement element, Container& container) {
_readUINode(reader, element, container);
if (element->has("scrollable")) {
container.setScrollable(element->attr("scrollable").asBool());
}
for (auto& sub : element->getElements()) {
if (sub->isText())
continue;
auto subnode = reader.readUINode(sub);
if (subnode) {
container.add(subnode);
}
}
}
void UiXmlReader::readUINode(UiXmlReader& reader, xml::xmlelement element, Container& container) {
_readContainer(reader, element, container);
}
void UiXmlReader::readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) {
_readUINode(reader, element, node);
}
static void _readPanel(UiXmlReader& reader, xml::xmlelement element, Panel& panel) {
_readUINode(reader, element, panel);
if (element->has("padding")) {
glm::vec4 padding = element->attr("padding").asVec4();
panel.setPadding(padding);
glm::vec2 size = panel.getSize();
panel.setSize(glm::vec2(
size.x + padding.x + padding.z,
size.y + padding.y + padding.w
));
}
if (element->has("size")) {
panel.setResizing(false);
}
if (element->has("max-length")) {
panel.setMaxLength(element->attr("max-length").asInt());
}
for (auto& sub : element->getElements()) {
if (sub->isText())
continue;
auto subnode = reader.readUINode(sub);
if (subnode) {
panel.add(subnode);
}
}
}
static std::wstring readAndProcessInnerText(xml::xmlelement element) {
std::wstring text = L"";
if (element->size() == 1) {
std::string source = element->sub(0)->attr("#").getText();
util::trim(source);
text = util::str2wstr_utf8(source);
if (text[0] == '@') {
text = langs::get(text.substr(1));
}
}
return text;
}
static std::shared_ptr<UINode> readLabel(UiXmlReader& reader, xml::xmlelement element) {
std::wstring text = readAndProcessInnerText(element);
auto label = std::make_shared<Label>(text);
_readUINode(reader, element, *label);
if (element->has("valign")) {
label->setVerticalAlign(
align_from_string(element->attr("valign").getText(), label->getVerticalAlign())
);
}
return label;
}
static std::shared_ptr<UINode> readContainer(UiXmlReader& reader, xml::xmlelement element) {
auto container = std::make_shared<Container>(glm::vec2());
_readContainer(reader, element, *container);
return container;
}
static std::shared_ptr<UINode> readPanel(UiXmlReader& reader, xml::xmlelement element) {
float interval = element->attr("interval", "2").asFloat();
auto panel = std::make_shared<Panel>(glm::vec2(), glm::vec4(), interval);
_readPanel(reader, element, *panel);
return panel;
}
static std::shared_ptr<UINode> readButton(UiXmlReader& reader, xml::xmlelement element) {
std::wstring text = readAndProcessInnerText(element);
auto button = std::make_shared<Button>(text, glm::vec4(0.0f), nullptr);
_readPanel(reader, element, *button);
if (element->has("onclick")) {
auto callback = scripting::create_runnable(
reader.getEnvironment().getId(),
element->attr("onclick").getText(),
reader.getFilename()
);
button->listenAction([callback](GUI*) {
callback();
});
}
if (element->has("text-align")) {
button->setTextAlign(align_from_string(element->attr("text-align").getText(), button->getTextAlign()));
}
if (element->has("pressed-color")) {
button->setPressedColor(element->attr("pressed-color").asColor());
}
return button;
}
static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, xml::xmlelement element) {
auto text = readAndProcessInnerText(element);
bool checked = element->attr("checked", "false").asBool();
auto checkbox = std::make_shared<FullCheckBox>(text, glm::vec2(), checked);
_readPanel(reader, element, *checkbox);
if (element->has("consumer")) {
auto consumer = scripting::create_bool_consumer(
reader.getEnvironment().getId(),
element->attr("consumer").getText(),
reader.getFilename()
);
checkbox->setConsumer(consumer);
}
if (element->has("supplier")) {
auto supplier = scripting::create_bool_supplier(
reader.getEnvironment().getId(),
element->attr("supplier").getText(),
reader.getFilename()
);
checkbox->setSupplier(supplier);
}
return checkbox;
}
static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement element) {
auto placeholder = util::str2wstr_utf8(element->attr("placeholder", "").getText());
auto text = readAndProcessInnerText(element);
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
_readPanel(reader, element, *textbox);
textbox->setText(text);
if (element->has("multiline")) {
textbox->setMultiline(element->attr("multiline").asBool());
}
if (element->has("editable")) {
textbox->setEditable(element->attr("editable").asBool());
}
if (element->has("consumer")) {
auto consumer = scripting::create_wstring_consumer(
reader.getEnvironment().getId(),
element->attr("consumer").getText(),
reader.getFilename()
);
textbox->setTextConsumer(consumer);
}
if (element->has("supplier")) {
auto supplier = scripting::create_wstring_supplier(
reader.getEnvironment().getId(),
element->attr("consumer").getText(),
reader.getFilename()
);
textbox->setTextSupplier(supplier);
}
if (element->has("focused-color")) {
textbox->setFocusedColor(element->attr("focused-color").asColor());
}
if (element->has("error-color")) {
textbox->setErrorColor(element->attr("error-color").asColor());
}
if (element->has("validator")) {
auto validator = scripting::create_wstring_validator(
reader.getEnvironment().getId(),
element->attr("validator").getText(),
reader.getFilename()
);
textbox->setTextValidator(validator);
}
return textbox;
}
static std::shared_ptr<UINode> readImage(UiXmlReader& reader, xml::xmlelement element) {
std::string src = element->attr("src", "").getText();
auto image = std::make_shared<Image>(src);
_readUINode(reader, element, *image);
return image;
}
static std::shared_ptr<UINode> readTrackBar(UiXmlReader& reader, xml::xmlelement element) {
float min = element->attr("min", "0.0").asFloat();
float max = element->attr("max", "1.0").asFloat();
float def = element->attr("value", "0.0").asFloat();
float step = element->attr("step", "1.0").asFloat();
int trackWidth = element->attr("track-width", "1.0").asInt();
auto bar = std::make_shared<TrackBar>(min, max, def, step, trackWidth);
_readUINode(reader, element, *bar);
if (element->has("consumer")) {
auto consumer = scripting::create_number_consumer(
reader.getEnvironment().getId(),
element->attr("consumer").getText(),
reader.getFilename()
);
bar->setConsumer(consumer);
}
if (element->has("supplier")) {
auto supplier = scripting::create_number_supplier(
reader.getEnvironment().getId(),
element->attr("supplier").getText(),
reader.getFilename()
);
bar->setSupplier(supplier);
}
if (element->has("track-color")) {
bar->setTrackColor(element->attr("track-color").asColor());
}
return bar;
}
UiXmlReader::UiXmlReader(const scripting::Environment& env) : env(env) {
add("image", readImage);
add("label", readLabel);
add("panel", readPanel);
add("button", readButton);
add("textbox", readTextBox);
add("chackbox", readCheckBox);
add("trackbar", readTrackBar);
add("container", readContainer);
}
void UiXmlReader::add(const std::string& tag, uinode_reader reader) {
readers[tag] = reader;
}
bool UiXmlReader::hasReader(const std::string& tag) const {
return readers.find(tag) != readers.end();
}
void UiXmlReader::addIgnore(const std::string& tag) {
ignored.insert(tag);
}
std::shared_ptr<UINode> UiXmlReader::readUINode(xml::xmlelement element) {
const std::string& tag = element->getTag();
auto found = readers.find(tag);
if (found == readers.end()) {
if (ignored.find(tag) != ignored.end()) {
return nullptr;
}
throw std::runtime_error("unsupported element '"+tag+"'");
}
return found->second(*this, element);
}
std::shared_ptr<UINode> UiXmlReader::readXML(
const std::string& filename,
const std::string& source
) {
this->filename = filename;
auto document = xml::parse(filename, source);
auto root = document->getRoot();
return readUINode(root);
}
std::shared_ptr<UINode> UiXmlReader::readXML(
const std::string& filename,
xml::xmlelement root
) {
this->filename = filename;
return readUINode(root);
}
const std::string& UiXmlReader::getFilename() const {
return filename;
}
const scripting::Environment& UiXmlReader::getEnvironment() const {
return env;
}
-61
View File
@@ -1,61 +0,0 @@
#ifndef FRONTEND_GUI_GUI_XML_H_
#define FRONTEND_GUI_GUI_XML_H_
#include <memory>
#include <unordered_set>
#include <unordered_map>
#include "GUI.h"
#include "../../coders/xml.h"
namespace scripting {
class Environment;
}
namespace gui {
class UiXmlReader;
using uinode_reader = std::function<std::shared_ptr<UINode>(UiXmlReader&, xml::xmlelement)>;
class UiXmlReader {
std::unordered_map<std::string, uinode_reader> readers;
std::unordered_set<std::string> ignored;
std::string filename;
const scripting::Environment& env;
public:
UiXmlReader(const scripting::Environment& env);
void add(const std::string& tag, uinode_reader reader);
bool hasReader(const std::string& tag) const;
void addIgnore(const std::string& tag);
std::shared_ptr<UINode> readUINode(xml::xmlelement element);
void readUINode(
UiXmlReader& reader,
xml::xmlelement element,
UINode& node
);
void readUINode(
UiXmlReader& reader,
xml::xmlelement element,
Container& container
);
std::shared_ptr<UINode> readXML(
const std::string& filename,
const std::string& source
);
std::shared_ptr<UINode> readXML(
const std::string& filename,
xml::xmlelement root
);
const scripting::Environment& getEnvironment() const;
const std::string& getFilename() const;
};
}
#endif // FRONTEND_GUI_GUI_XML_H_
+4 -4
View File
@@ -32,10 +32,10 @@
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "../maths/voxmaths.h"
#include "gui/controls.h"
#include "gui/containers.h"
#include "gui/UINode.h"
#include "gui/GUI.h"
#include "../graphics/ui/elements/controls.h"
#include "../graphics/ui/elements/containers.h"
#include "../graphics/ui/elements/UINode.h"
#include "../graphics/ui/GUI.h"
#include "ContentGfxCache.h"
#include "menu/menu.h"
#include "screens.h"
+4 -5
View File
@@ -8,9 +8,10 @@
#include <filesystem>
#include <glm/glm.hpp>
#include "../gui/GUI.h"
#include "../gui/containers.h"
#include "../gui/controls.h"
#include "../../graphics/ui/GUI.h"
#include "../../graphics/ui/gui_util.h"
#include "../../graphics/ui/elements/containers.h"
#include "../../graphics/ui/elements/controls.h"
#include "../screens.h"
#include "../../coders/png.h"
@@ -29,8 +30,6 @@
#include "../../content/Content.h"
#include "../../content/ContentLUT.h"
#include "../../content/ContentPack.h"
#include "../gui/gui_util.h"
#include "../locale/langs.h"
#include "menu_commons.h"
+1 -1
View File
@@ -1,7 +1,7 @@
#include "menu_commons.h"
#include "../../engine.h"
#include "../gui/containers.h"
#include "../../graphics/ui/elements/containers.h"
#include "../locale/langs.h"
using namespace gui;
+1 -1
View File
@@ -5,7 +5,7 @@
#include <memory>
#include <glm/glm.hpp>
#include "../gui/controls.h"
#include "../../graphics/ui/elements/controls.h"
class Engine;
+11 -11
View File
@@ -1,19 +1,19 @@
#ifndef FRONTEND_MENU_MENU_CREATE_WORLD_H_
#define FRONTEND_MENU_MENU_CREATE_WORLD_H_
#include "menu.h"
#include "menu_commons.h"
#include "../gui/controls.h"
#include "../gui/containers.h"
#include "../gui/gui_util.h"
#include "../../engine.h"
#include "../../files/WorldFiles.h"
#include "../../graphics/ui/elements/containers.h"
#include "../../graphics/ui/elements/controls.h"
#include "../../graphics/ui/gui_util.h"
#include "../../util/stringutil.h"
#include "../../world/Level.h"
#include "../../world/World.h"
#include "../../world/WorldGenerators.h"
#include "../locale/langs.h"
#include "../screens.h"
#include "../../world/WorldGenerators.h"
#include "../../files/WorldFiles.h"
#include "../../world/World.h"
#include "../../world/Level.h"
#include "../../util/stringutil.h"
#include "../../engine.h"
#include "menu_commons.h"
#include "menu.h"
#include <iostream>
+9 -8
View File
@@ -1,16 +1,17 @@
#include "menu.h"
#include "menu_commons.h"
#include "../locale/langs.h"
#include "../gui/gui_util.h"
#include "../screens.h"
#include "../../coders/png.h"
#include "../../content/ContentLUT.h"
#include "../../engine.h"
#include "../../files/WorldFiles.h"
#include "../../graphics/ui/gui_util.h"
#include "../../logic/LevelController.h"
#include "../../util/stringutil.h"
#include "../../world/Level.h"
#include "../../world/World.h"
#include "../../coders/png.h"
#include "../../util/stringutil.h"
#include "../../files/WorldFiles.h"
#include "../../content/ContentLUT.h"
#include "../../logic/LevelController.h"
#include "../locale/langs.h"
#include "../screens.h"
#include <glm/glm.hpp>
+2 -2
View File
@@ -2,8 +2,8 @@
#include "menu_commons.h"
#include "../locale/langs.h"
#include "../gui/GUI.h"
#include "../gui/gui_util.h"
#include "../../graphics/ui/GUI.h"
#include "../../graphics/ui/gui_util.h"
#include "../../engine.h"
#include "../../util/stringutil.h"
#include "../../window/Events.h"
+35 -35
View File
@@ -1,46 +1,46 @@
#include "screens.h"
#include "../assets/Assets.h"
#include "../audio/audio.h"
#include "../content/Content.h"
#include "../core_defs.h"
#include "../engine.h"
#include "../graphics/core/Batch2D.h"
#include "../graphics/core/GfxContext.h"
#include "../graphics/core/Shader.h"
#include "../graphics/core/TextureAnimation.h"
#include "../graphics/ui/elements/containers.h"
#include "../graphics/ui/GUI.h"
#include "../logic/ChunksController.h"
#include "../logic/LevelController.h"
#include "../logic/scripting/scripting_frontend.h"
#include "../logic/scripting/scripting.h"
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "../util/stringutil.h"
#include "../voxels/Block.h"
#include "../voxels/Chunk.h"
#include "../voxels/Chunks.h"
#include "../window/Camera.h"
#include "../window/Events.h"
#include "../window/input.h"
#include "../world/Level.h"
#include "../world/World.h"
#include "ContentGfxCache.h"
#include "hud.h"
#include "LevelFrontend.h"
#include "menu/menu.h"
#include "WorldRenderer.h"
#include <filesystem>
#include <glm/glm.hpp>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <glm/glm.hpp>
#include <filesystem>
#include <stdexcept>
#include "../audio/audio.h"
#include "../window/Camera.h"
#include "../window/Events.h"
#include "../window/input.h"
#include "../graphics/core/Shader.h"
#include "../graphics/core/Batch2D.h"
#include "../graphics/core/GfxContext.h"
#include "../graphics/core/TextureAnimation.h"
#include "../assets/Assets.h"
#include "../world/Level.h"
#include "../world/World.h"
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "../logic/ChunksController.h"
#include "../logic/LevelController.h"
#include "../logic/scripting/scripting.h"
#include "../logic/scripting/scripting_frontend.h"
#include "../voxels/Chunks.h"
#include "../voxels/Chunk.h"
#include "../engine.h"
#include "../util/stringutil.h"
#include "../core_defs.h"
#include "WorldRenderer.h"
#include "hud.h"
#include "ContentGfxCache.h"
#include "LevelFrontend.h"
#include "gui/GUI.h"
#include "gui/containers.h"
#include "menu/menu.h"
#include "../content/Content.h"
#include "../voxels/Block.h"
Screen::Screen(Engine* engine) : engine(engine), batch(new Batch2D(1024)) {
}