#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> AttrubutesMap; template 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 // constexpr const char* string(const Attribute a) { return names[(int)a.id]; } #define DECLARE_ATTRIBUTE(N,T) \ struct N : public Attribute \ { using Attribute::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 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 Node(std::forward(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(); };