#include "pch.h" #include "layout.h" void Node::update(float width, float height) { YGNodeStyleSetWidth(y_node, width); YGNodeStyleSetHeight(y_node, height); YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR); update_internal({ 0, 0 }); } void Node::update_internal(glm::vec2 origin) { float x = YGNodeLayoutGetLeft(y_node); float y = YGNodeLayoutGetTop(y_node); float w = YGNodeLayoutGetWidth(y_node); float h = YGNodeLayoutGetHeight(y_node); m_pos = origin + glm::vec2(x, y); m_size = glm::vec2(w, h); if (!parent) m_clip = glm::vec4(m_pos, m_size); else m_clip = rect_intersection(glm::vec4(m_pos, m_size), parent->m_clip); for (auto& c : children) c.update_internal(m_pos); } void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* attr) { switch (ka) { case att::kAttribute::Width: if (strcmp(attr->Value(), "auto") == 0) { YGNodeStyleSetWidth(y_node, YGUndefined); YGNodeStyleSetWidthPercent(y_node, YGUndefined); } else { if (strchr(attr->Value(), '%')) YGNodeStyleSetWidthPercent(y_node, attr->FloatValue()); else YGNodeStyleSetWidth(y_node, attr->FloatValue()); } break; case att::kAttribute::MinWidth: if (strchr(attr->Value(), '%')) YGNodeStyleSetMinWidthPercent(y_node, attr->FloatValue()); else YGNodeStyleSetMinWidth(y_node, attr->FloatValue()); break; case att::kAttribute::MaxWidth: YGNodeStyleSetMaxWidth(y_node, attr->FloatValue()); break; case att::kAttribute::Height: if (strcmp(attr->Value(), "auto") == 0) { YGNodeStyleSetHeight(y_node, YGUndefined); YGNodeStyleSetHeightPercent(y_node, YGUndefined); } else { if (strchr(attr->Value(), '%')) YGNodeStyleSetHeightPercent(y_node, attr->FloatValue()); else YGNodeStyleSetHeight(y_node, attr->FloatValue()); } break; case att::kAttribute::MinHeight: YGNodeStyleSetMinHeight(y_node, attr->FloatValue()); break; case att::kAttribute::MaxHeight: YGNodeStyleSetMaxHeight(y_node, attr->FloatValue()); break; case att::kAttribute::Grow: YGNodeStyleSetFlexGrow(y_node, attr->FloatValue()); break; case att::kAttribute::Shrink: YGNodeStyleSetFlexShrink(y_node, attr->FloatValue()); break; case att::kAttribute::FlexDir: { YGFlexDirection dir = YGFlexDirectionRow; if (strcmp("col", attr->Value()) == 0) dir = YGFlexDirectionColumn; else if (strcmp("col-reverse", attr->Value()) == 0) dir = YGFlexDirectionColumnReverse; else if (strcmp("row", attr->Value()) == 0) dir = YGFlexDirectionRow; else if (strcmp("row-reverse", attr->Value()) == 0) dir = YGFlexDirectionRowReverse; YGNodeStyleSetFlexDirection(y_node, dir); break; } case att::kAttribute::FlexWrap: YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap); break; case att::kAttribute::Padding: { glm::vec4 pad; int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); if (n == 1) { YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.x); YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.x); YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.x); } else { YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.y); YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.z); YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.w); } break; } case att::kAttribute::Margin: { glm::vec4 pad; int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); if (n == 1) { YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.x); YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.x); YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.x); } else { YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.y); YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.z); YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.w); } break; } case att::kAttribute::Color: { glm::vec4 pad; int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); if (n == 1) { color = glm::vec4(pad.x); } else { color = pad; } break; } default: // other_attributes_handler() break; } } void Node::load(const char* path) { struct stat tmp_info; if (stat(path, &tmp_info) != 0) return; if (tmp_info.st_mtime <= m_file_info.st_mtime) return; m_file_info = tmp_info; m_path = path; children.clear(); YGNodeReset(y_node); tinyxml2::XMLDocument xml; auto ret = xml.LoadFile(path); if (ret != tinyxml2::XMLError::XML_SUCCESS) return; load_internal(xml.RootElement()); } void Node::load_internal(const tinyxml2::XMLElement* x_node) { auto attr = x_node->FirstAttribute(); while (attr) { parse_attributes(att::value(attr->Name()), attr); attr = attr->Next(); } auto x_child = x_node->FirstChildElement(); while (x_child) { //Node n; children.emplace_back(); auto& n = children.back(); n.parent = this; YGNodeInsertChild(y_node, n.y_node, YGNodeGetChildCount(y_node)); n.load_internal(x_child); x_child = x_child->NextSiblingElement(); } } void Node::reload() { float w = YGNodeLayoutGetWidth(y_node); float h = YGNodeLayoutGetHeight(y_node); // avoid conflict when assigning the same string from c_str std::string path_copy = m_path; load(path_copy.c_str()); update(w, h); }