Files
panopainter/engine/layout.h

205 lines
6.4 KiB
C++

#pragma once
namespace att
{
enum class kAttribute : uint8_t {
Width, MinWidth, MaxWidth,
Height, MinHeight, MaxHeight,
Divisions, InnerRadius, OuterRadius,
Grow, Shrink, FlexDir, FlexWrap,
Padding, Margin,
Color
};
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 typemap
{
const char* name;
kAttribute value;
};
static constexpr typemap map[] =
{
{ "width", kAttribute::Width },
{ "min-width", kAttribute::MinWidth },
{ "max-width", kAttribute::MaxWidth },
{ "height", kAttribute::Height },
{ "min-height", kAttribute::MinHeight },
{ "max-height", kAttribute::MaxHeight },
{ "divisions", kAttribute::Divisions },
{ "inner-radius", kAttribute::InnerRadius },
{ "outer-radius", kAttribute::OuterRadius },
{ "grow", kAttribute::Grow },
{ "shrink", kAttribute::Shrink },
{ "dir", kAttribute::FlexDir },
{ "wrap", kAttribute::FlexWrap },
{ "pad", kAttribute::Padding },
{ "margin", kAttribute::Margin },
{ "color", kAttribute::Color },
};
static constexpr int map_size = sizeof(map) / sizeof(typemap) - 1;
constexpr bool same(const char* a, const char* b)
{
return (*a && *b) ? (*a == *b && same(a + 1, b + 1)) : !(*a || *b);
}
constexpr const kAttribute value(char const *name, int i = 0)
{
return ((i >= map_size) || same(map[i].name, name)) ?
map[i].value : value(name, i + 1);
}
constexpr const char* string(const kAttribute value, int i = 0)
{
return (map[i].value == value) ? map[i].name : string(value, i + 1);
}
//constexpr const char* string(kAttribute a) { return names[(int)a]; }
// template<kAttribute T, typename V>
// constexpr const char* string(const Attribute<T, V> a) { return names[(int)a.id]; }
#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 Node
{
const Node* parent{ nullptr };
YGNodeRef y_node{ nullptr };
struct stat m_file_info { 0 };
std::string m_path;
public:
std::vector<Node> children;
glm::vec4 color;
glm::vec2 m_pos;
glm::vec2 m_size;
glm::vec4 m_clip;
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
Node&& operator=(Node&& o) { return std::forward<Node>(o); }
Node(Node&& o)
{
children = std::move(o.children);
for (auto& c : children)
c.parent = this;
parent = o.parent;
y_node = o.y_node;
m_pos = o.m_pos;
m_size = o.m_size;
m_clip = o.m_clip;
color = o.color;
m_file_info = o.m_file_info;
o.y_node = nullptr;
o.parent = nullptr;
}
Node() { y_node = YGNodeNew(); }
~Node()
{
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(glm::vec2 origin);
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();
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->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;
}
};