231 lines
6.9 KiB
C++
231 lines
6.9 KiB
C++
#pragma once
|
|
#include "shape.hpp"
|
|
#include "util.hpp"
|
|
|
|
namespace att
|
|
{
|
|
enum class kAttribute : uint16_t
|
|
{
|
|
Width = const_hash("width"),
|
|
MinWidth = const_hash("max-width"),
|
|
MaxWidth = const_hash("min-width"),
|
|
Height = const_hash("height"),
|
|
MinHeight = const_hash("min-height"),
|
|
MaxHeight = const_hash("max-height"),
|
|
Divisions = const_hash("divisions"),
|
|
InnerRadius = const_hash("inner-radius"),
|
|
OuterRadius = const_hash("outer-radius"),
|
|
Grow = const_hash("grow"),
|
|
Shrink = const_hash("shrink"),
|
|
FlexDir = const_hash("dir"),
|
|
FlexWrap = const_hash("wrap"),
|
|
Padding = const_hash("pad"),
|
|
Margin = const_hash("margin"),
|
|
Color = const_hash("color"),
|
|
};
|
|
|
|
enum class kWidget : uint16_t
|
|
{
|
|
Border = const_hash("border"),
|
|
};
|
|
|
|
struct AttributeBase
|
|
{
|
|
kAttribute id;
|
|
};
|
|
|
|
typedef std::map<att::kAttribute, std::unique_ptr<att::AttributeBase>> AttrubutesMap;
|
|
|
|
template<kAttribute T, typename V>
|
|
struct Attribute : public AttributeBase
|
|
{
|
|
static const kAttribute static_id = T;
|
|
V value;
|
|
Attribute() : value{ 0 } { id = static_id; }
|
|
Attribute(V v) : value(v) { id = static_id; }
|
|
};
|
|
|
|
struct kAttributeMap
|
|
{
|
|
kAttribute value;
|
|
const char* name;
|
|
};
|
|
static constexpr kAttributeMap map[] =
|
|
{
|
|
{ kAttribute::Width, "width" },
|
|
{ kAttribute::MinWidth, "min-width" },
|
|
{ kAttribute::MaxWidth, "max-width" },
|
|
{ kAttribute::Height, "height" },
|
|
{ kAttribute::MinHeight, "min-height" },
|
|
{ kAttribute::MaxHeight, "max-height" },
|
|
{ kAttribute::Divisions, "divisions" },
|
|
{ kAttribute::InnerRadius, "inner-radius" },
|
|
{ kAttribute::OuterRadius, "outer-radius" },
|
|
{ kAttribute::Grow, "grow" },
|
|
{ kAttribute::Shrink, "shrink" },
|
|
{ kAttribute::FlexDir, "dir" },
|
|
{ kAttribute::FlexWrap, "wrap" },
|
|
{ kAttribute::Padding, "pad" },
|
|
{ kAttribute::Margin, "margin" },
|
|
{ kAttribute::Color, "color" },
|
|
};
|
|
|
|
constexpr const char* string(const kAttribute value, int i = 0)
|
|
{
|
|
// no check on size, value MUST be found
|
|
return (map[i].value == value) ? map[i].name : string(value, i + 1);
|
|
}
|
|
|
|
#define DECLARE_ATTRIBUTE(N,T) \
|
|
struct N : public Attribute<kAttribute::N,T> \
|
|
{ using Attribute<kAttribute::N,T>::Attribute; };
|
|
|
|
DECLARE_ATTRIBUTE(Width, float);
|
|
DECLARE_ATTRIBUTE(MinWidth, float);
|
|
DECLARE_ATTRIBUTE(MaxWidth, float);
|
|
DECLARE_ATTRIBUTE(Height, float);
|
|
DECLARE_ATTRIBUTE(MinHeight, float);
|
|
DECLARE_ATTRIBUTE(MaxHeight, float);
|
|
DECLARE_ATTRIBUTE(Divisions, int);
|
|
DECLARE_ATTRIBUTE(InnerRadius, float);
|
|
DECLARE_ATTRIBUTE(OuterRadius, float);
|
|
DECLARE_ATTRIBUTE(Grow, float);
|
|
DECLARE_ATTRIBUTE(Shrink, float);
|
|
DECLARE_ATTRIBUTE(FlexDir, int);
|
|
DECLARE_ATTRIBUTE(FlexWrap, int);
|
|
DECLARE_ATTRIBUTE(Padding, glm::vec4);
|
|
DECLARE_ATTRIBUTE(Margin, glm::vec4);
|
|
DECLARE_ATTRIBUTE(Color, glm::vec4);
|
|
|
|
#undef DECLARE_ATTRIBUTE
|
|
}
|
|
|
|
class Widget
|
|
{
|
|
public:
|
|
glm::mat4 mvp;
|
|
glm::vec4 clip;
|
|
virtual void draw() { };
|
|
};
|
|
|
|
class WidgetBorder : public Widget
|
|
{
|
|
public:
|
|
static Plane* m_plane;
|
|
virtual void draw() override
|
|
{
|
|
m_plane->draw_fill();
|
|
}
|
|
};
|
|
|
|
class Node
|
|
{
|
|
const Node* parent{ nullptr };
|
|
YGNodeRef y_node{ nullptr };
|
|
struct stat m_file_info { 0 };
|
|
std::string m_path;
|
|
|
|
public:
|
|
std::vector<Node> m_children;
|
|
std::unique_ptr<Widget> m_widget;
|
|
glm::vec2 m_pos;
|
|
glm::vec2 m_size;
|
|
glm::vec4 m_clip;
|
|
glm::vec4 color;
|
|
std::string m_name;
|
|
Node(const Node&) = delete;
|
|
Node& operator=(const Node&) = delete;
|
|
Node&& operator=(Node&& o) { return std::forward<Node>(o); }
|
|
Node(Node&& o)
|
|
{
|
|
m_children = std::move(o.m_children);
|
|
for (auto& c : m_children)
|
|
c.parent = this;
|
|
parent = o.parent;
|
|
y_node = o.y_node;
|
|
color = o.color;
|
|
m_pos = o.m_pos;
|
|
m_size = o.m_size;
|
|
m_clip = o.m_clip;
|
|
m_file_info = o.m_file_info;
|
|
o.y_node = nullptr;
|
|
o.parent = nullptr;
|
|
}
|
|
Node() { y_node = YGNodeNew(); }
|
|
~Node()
|
|
{
|
|
m_children.clear();
|
|
if (y_node)
|
|
YGNodeFree(y_node);
|
|
}
|
|
|
|
void SetWidth(float value) { YGNodeStyleSetWidth(y_node, value); }
|
|
void SetWidthP(float value) { YGNodeStyleSetWidthPercent(y_node, value); }
|
|
void SetHeight(float value) { YGNodeStyleSetHeight(y_node, value); }
|
|
void SetHeightP(float value) { YGNodeStyleSetHeightPercent(y_node, value); }
|
|
|
|
void SetPadding(float t, float r, float b, float l)
|
|
{
|
|
YGNodeStyleSetPadding(y_node, YGEdgeTop, t);
|
|
YGNodeStyleSetPadding(y_node, YGEdgeRight, r);
|
|
YGNodeStyleSetPadding(y_node, YGEdgeBottom, b);
|
|
YGNodeStyleSetPadding(y_node, YGEdgeLeft, l);
|
|
}
|
|
|
|
void SetFlexGrow(float value) { YGNodeStyleSetFlexGrow(y_node, value); }
|
|
void SetFlexShrink(float value) { YGNodeStyleSetFlexShrink(y_node, value); }
|
|
void SetFlexDir(YGFlexDirection value) { YGNodeStyleSetFlexDirection(y_node, value); }
|
|
void SetFlexWrap(YGWrap value) { YGNodeStyleSetFlexWrap(y_node, value); }
|
|
|
|
glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b)
|
|
{
|
|
// convert from [x,y,w,h] to [x1,y1,x2,y1]
|
|
a = glm::vec4(a.xy(), a.xy() + a.zw());
|
|
b = glm::vec4(b.xy(), b.xy() + b.zw());
|
|
auto o = glm::vec4(glm::max(a.xy(), b.xy()), glm::min(a.zw(), b.zw()));
|
|
o = glm::vec4(o.xy(), glm::max({ 0, 0 }, o.zw() - o.xy()));
|
|
return o;
|
|
}
|
|
|
|
void update(float width, float height);
|
|
void update_internal(const glm::vec2& origin, const glm::mat4& proj);
|
|
void parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* attr);
|
|
void load(const char* path);
|
|
void load_internal(const tinyxml2::XMLElement* x_node);
|
|
void reload();
|
|
void draw();
|
|
|
|
class iterator
|
|
{
|
|
std::stack<Node*> m_nodes;
|
|
Node* m_current;
|
|
public:
|
|
iterator(Node* root)
|
|
{
|
|
m_current = root;
|
|
if (root)
|
|
m_nodes.push(root);
|
|
}
|
|
iterator& operator++()
|
|
{
|
|
m_nodes.pop();
|
|
for (auto& c : m_current->m_children)
|
|
m_nodes.push(&c);
|
|
m_current = m_nodes.size() ? m_nodes.top() : nullptr;
|
|
return *this;
|
|
}
|
|
Node& operator*() { return *m_current; }
|
|
Node* operator->() { return m_current; }
|
|
bool operator==(const iterator& rhs) { return m_current == rhs.m_current; }
|
|
bool operator!=(const iterator& rhs) { return m_current != rhs.m_current; }
|
|
};
|
|
iterator begin()
|
|
{
|
|
return this;
|
|
}
|
|
iterator end()
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|