Skip to content

Commit

Permalink
Streamline style a bit (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
andreamancuso authored Aug 6, 2024
1 parent 5a6e989 commit ed7542b
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 134 deletions.
4 changes: 4 additions & 0 deletions packages/dear-imgui/cpp/include/element/element.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class Element {

void DrawBaseEffects() const;

void ResetStyle();

void SetStyle(const json& styleDef);

virtual void Patch(const json& elementPatchDef, ReactImgui* view);

virtual bool HasInternalOps();
Expand Down
6 changes: 4 additions & 2 deletions packages/dear-imgui/cpp/include/element/layout_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class LayoutNode {
return !parentNode || YGNodeStyleGetDisplay(parentNode) != YGDisplayNone;
}

void ResetStyle() const;

void SetDirection(const YGDirection direction) const {
YGNodeStyleSetDirection(m_node, direction);
}
Expand Down Expand Up @@ -206,7 +208,7 @@ class LayoutNode {

template <typename T, typename PropertyValueResolver>
void ApplyOptionalStyleProperty(const json& styleDef, const std::string& propertyKey, PropertyValueResolver resolver) const {
if (styleDef.contains(propertyKey) && styleDef[propertyKey].is_string()) {
if (styleDef.is_object() && styleDef.contains(propertyKey) && styleDef[propertyKey].is_string()) {
auto rawValue = styleDef[propertyKey].template get<std::string>();
std::optional<T> value = resolver(rawValue);
if (value.has_value()) {
Expand All @@ -217,7 +219,7 @@ class LayoutNode {

template <typename T1, typename T2, typename EdgeResolver>
void ApplyOptionalMultiEdgeStyleProperty(const json& styleDef, const std::string& propertyKey, EdgeResolver edgeResolver) const {
if (styleDef.contains(propertyKey) && styleDef[propertyKey].is_object()) {
if (styleDef.is_object() && styleDef.contains(propertyKey) && styleDef[propertyKey].is_object()) {
for (auto& [key, item] : styleDef[propertyKey].items()) {
if (item.is_number()) {
std::optional<T1> edge = edgeResolver(key);
Expand Down
44 changes: 26 additions & 18 deletions packages/dear-imgui/cpp/src/element/element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,41 @@ std::unique_ptr<Element> Element::makeElement(const json& nodeDef, ReactImgui* v
bool isRoot = (nodeDef.contains("root") && nodeDef["root"].is_boolean()) ? nodeDef["root"].template get<bool>() : false;
auto element = std::make_unique<Element>(view, id, isRoot);

if (nodeDef.is_object() && nodeDef.contains("style") && nodeDef["style"].is_object()) {
element->m_layoutNode->ApplyStyle(nodeDef["style"]);
return element;
};

void Element::ResetStyle() {
m_layoutNode->ResetStyle();
m_baseDrawStyle.reset();
};

if (nodeDef["style"].contains("backgroundColor") || nodeDef["style"].contains("borderColor")) {
void Element::SetStyle(const json& styleDef) {
if (styleDef.is_object()) {
m_layoutNode->ApplyStyle(styleDef);

if (styleDef.contains("backgroundColor") || styleDef.contains("borderColor")) {
BaseDrawStyle baseDrawStyle;

if (nodeDef["style"].contains("backgroundColor")) {
baseDrawStyle.backgroundColor = jsonHEXATupleToIV4(nodeDef["style"]["backgroundColor"]);
if (styleDef.contains("backgroundColor")) {
baseDrawStyle.backgroundColor = jsonHEXATupleToIV4(styleDef["backgroundColor"]);
}

if (nodeDef["style"].contains("borderColor")) {
baseDrawStyle.borderColor = jsonHEXATupleToIV4(nodeDef["style"]["borderColor"]);
if (styleDef.contains("borderColor")) {
baseDrawStyle.borderColor = jsonHEXATupleToIV4(styleDef["borderColor"]);
}

if (baseDrawStyle.backgroundColor.has_value() || baseDrawStyle.borderColor.has_value()) {

if (nodeDef["style"].contains("rounding")) {
baseDrawStyle.rounding = nodeDef["style"]["rounding"].template get<float>();
if (styleDef.contains("rounding")) {
baseDrawStyle.rounding = styleDef["rounding"].template get<float>();
}

if (nodeDef["style"].contains("borderThickness")) {
baseDrawStyle.borderThickness = nodeDef["style"]["borderThickness"].template get<float>();
if (styleDef.contains("borderThickness")) {
baseDrawStyle.borderThickness = styleDef["borderThickness"].template get<float>();
}

if (nodeDef["style"].contains("roundCorners") && nodeDef["style"]["roundCorners"].is_array()) {
const auto roundCorners = nodeDef["style"]["roundCorners"].template get<std::vector<std::string>>();
if (styleDef.contains("roundCorners") && styleDef["roundCorners"].is_array()) {
const auto roundCorners = styleDef["roundCorners"].template get<std::vector<std::string>>();

baseDrawStyle.drawFlags = std::accumulate(
roundCorners.begin(),
Expand All @@ -57,13 +66,11 @@ std::unique_ptr<Element> Element::makeElement(const json& nodeDef, ReactImgui* v
);
}

element->m_baseDrawStyle.emplace(baseDrawStyle);
m_baseDrawStyle.emplace(baseDrawStyle);
}
}
}

return element;
};
}

const char* Element::GetElementType() {
return "node";
Expand Down Expand Up @@ -184,7 +191,8 @@ void Element::PostRender(ReactImgui* view) {};

void Element::Patch(const json& nodeDef, ReactImgui* view) {
if (nodeDef.is_object() && nodeDef.contains("style") && nodeDef["style"].is_object()) {
m_layoutNode->ApplyStyle(nodeDef["style"]);
ResetStyle();
SetStyle(nodeDef["style"]);
}
};

Expand Down
230 changes: 121 additions & 109 deletions packages/dear-imgui/cpp/src/element/layout_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,147 +36,159 @@ size_t LayoutNode::GetChildCount() const {
return YGNodeGetChildCount(m_node);
};

void LayoutNode::ResetStyle() const {
SetDirection(YGDirectionInherit);
SetFlexDirection(YGFlexDirectionColumn);
SetJustifyContent(YGJustifyFlexStart);
SetAlignContent(YGAlignAuto);
SetAlignItems(YGAlignAuto);
SetAlignSelf(YGAlignAuto);
SetPositionType(YGPositionTypeStatic);
SetFlexWrap(YGWrapNoWrap);
SetOverflow(YGOverflowVisible);
SetDisplay(YGDisplayFlex);

SetPadding(YGEdgeAll, 0);
SetMargin(YGEdgeAll, 0);
SetPosition(YGEdgeAll, 0);
};

void LayoutNode::ApplyStyle(const json& styleDef) const {
ApplyOptionalStyleProperty<YGDirection>(styleDef, "direction", ResolveDirection);
ApplyOptionalStyleProperty<YGFlexDirection>(styleDef, "flexDirection", ResolveFlexDirection);
ApplyOptionalStyleProperty<YGJustify>(styleDef, "justifyContent", ResolveJustifyContent);
ApplyOptionalStyleProperty<YGAlign>(styleDef, "alignContent", ResolveAlignContent);
ApplyOptionalStyleProperty<YGAlign>(styleDef, "alignItems", ResolveAlignItems);
ApplyOptionalStyleProperty<YGAlign>(styleDef, "alignSelf", ResolveAlignItems);
ApplyOptionalStyleProperty<YGPositionType>(styleDef, "positionType", ResolvePositionType);
ApplyOptionalStyleProperty<YGWrap>(styleDef, "flexWrap", ResolveFlexWrap);
ApplyOptionalStyleProperty<YGOverflow>(styleDef, "overflow", ResolveOverflow);
ApplyOptionalStyleProperty<YGDisplay>(styleDef, "display", ResolveDisplay);

if (styleDef.contains("flex") && styleDef["flex"].is_number()) {
SetFlex(styleDef["flex"].template get<float>());
}

if (styleDef.contains("flexGrow") && styleDef["flexGrow"].is_number()) {
SetFlexGrow(styleDef["flexGrow"].template get<float>());
}

if (styleDef.contains("flexShrink") && styleDef["flexShrink"].is_number()) {
SetFlexShrink(styleDef["flexShrink"].template get<float>());
}

if (styleDef.contains("flexBasis")) {
if (styleDef["flexBasis"].is_number()) {
SetFlexBasis(styleDef["flexBasis"].template get<float>());
} else if (styleDef["flexBasis"].is_string()) {
auto flexBasis = styleDef["flexBasis"].template get<std::string>();

if (flexBasis == "auto") {
SetFlexBasisAuto();
} else if (auto maybePct = charPercentageToFloat(flexBasis.c_str()); maybePct.has_value()) {
SetFlexBasisPercent(maybePct.value());
}
if (styleDef.is_object()) {
ApplyOptionalStyleProperty<YGDirection>(styleDef, "direction", ResolveDirection);
ApplyOptionalStyleProperty<YGFlexDirection>(styleDef, "flexDirection", ResolveFlexDirection);
ApplyOptionalStyleProperty<YGJustify>(styleDef, "justifyContent", ResolveJustifyContent);
ApplyOptionalStyleProperty<YGAlign>(styleDef, "alignContent", ResolveAlignContent);
ApplyOptionalStyleProperty<YGAlign>(styleDef, "alignItems", ResolveAlignItems);
ApplyOptionalStyleProperty<YGAlign>(styleDef, "alignSelf", ResolveAlignItems);
ApplyOptionalStyleProperty<YGPositionType>(styleDef, "positionType", ResolvePositionType);
ApplyOptionalStyleProperty<YGWrap>(styleDef, "flexWrap", ResolveFlexWrap);
ApplyOptionalStyleProperty<YGOverflow>(styleDef, "overflow", ResolveOverflow);
ApplyOptionalStyleProperty<YGDisplay>(styleDef, "display", ResolveDisplay);

if (styleDef.contains("flex") && styleDef["flex"].is_number()) {
SetFlex(styleDef["flex"].template get<float>());
}
}

ApplyOptionalMultiEdgeStyleProperty<YGEdge, float>(styleDef, "position", ResolveEdge);
ApplyOptionalMultiEdgeStyleProperty<YGEdge, float>(styleDef, "margin", ResolveEdge);
ApplyOptionalMultiEdgeStyleProperty<YGEdge, float>(styleDef, "padding", ResolveEdge);

// TODO: Border must be applied equally on all 4 sides
if (styleDef.contains("border") && styleDef["border"].is_object()) {
for (auto& [key, item] : styleDef["border"].items()) {
if (item.is_number()) {
std::optional<YGEdge> edge = ResolveEdge(key);
if (edge.has_value()) {
SetBorder(edge.value(), item.template get<float>());
if (styleDef.contains("flexGrow") && styleDef["flexGrow"].is_number()) {
SetFlexGrow(styleDef["flexGrow"].template get<float>());
}

if (styleDef.contains("flexShrink") && styleDef["flexShrink"].is_number()) {
SetFlexShrink(styleDef["flexShrink"].template get<float>());
}

if (styleDef.contains("flexBasis")) {
if (styleDef["flexBasis"].is_number()) {
SetFlexBasis(styleDef["flexBasis"].template get<float>());
} else if (styleDef["flexBasis"].is_string()) {
auto flexBasis = styleDef["flexBasis"].template get<std::string>();

if (flexBasis == "auto") {
SetFlexBasisAuto();
} else if (auto maybePct = charPercentageToFloat(flexBasis.c_str()); maybePct.has_value()) {
SetFlexBasisPercent(maybePct.value());
}
}
}
}

if (styleDef.contains("gap") && styleDef["gap"].is_object()) {
for (auto& [key, item] : styleDef["gap"].items()) {
if (item.is_number()) {
std::optional<YGGutter> gutter = ResolveGutter(key);
if (gutter.has_value()) {
SetGap(gutter.value(), item.template get<float>());

ApplyOptionalMultiEdgeStyleProperty<YGEdge, float>(styleDef, "position", ResolveEdge);
ApplyOptionalMultiEdgeStyleProperty<YGEdge, float>(styleDef, "margin", ResolveEdge);
ApplyOptionalMultiEdgeStyleProperty<YGEdge, float>(styleDef, "padding", ResolveEdge);

// Currently we support only same thickness borders
if (styleDef.contains("borderThickness") && styleDef["borderThickness"].is_number()) {
SetBorder(YGEdgeAll, styleDef["borderThickness"].template get<float>());
}

if (styleDef.contains("gap") && styleDef["gap"].is_object()) {
for (auto& [key, item] : styleDef["gap"].items()) {
if (item.is_number()) {
std::optional<YGGutter> gutter = ResolveGutter(key);
if (gutter.has_value()) {
SetGap(gutter.value(), item.template get<float>());
}
}
}
}
}

if (styleDef.contains("aspectRatio") && styleDef["aspectRatio"].is_number()) {
SetAspectRatio(styleDef["aspectRatio"].template get<float>());
}
if (styleDef.contains("aspectRatio") && styleDef["aspectRatio"].is_number()) {
SetAspectRatio(styleDef["aspectRatio"].template get<float>());
}

if (styleDef.contains("width")) {
if (styleDef["width"].is_number()) {
SetWidth(styleDef["width"].template get<float>());
} else if (styleDef["width"].is_string()) {
auto width = styleDef["width"].template get<std::string>();
if (styleDef.contains("width")) {
if (styleDef["width"].is_number()) {
SetWidth(styleDef["width"].template get<float>());
} else if (styleDef["width"].is_string()) {
auto width = styleDef["width"].template get<std::string>();

if (width == "auto") {
SetWidthAuto();
} else if (auto maybePct = charPercentageToFloat(width.c_str()); maybePct.has_value()) {
SetWidthPercent(maybePct.value());
if (width == "auto") {
SetWidthAuto();
} else if (auto maybePct = charPercentageToFloat(width.c_str()); maybePct.has_value()) {
SetWidthPercent(maybePct.value());
}
}
}
}

if (styleDef.contains("minWidth")) {
if (styleDef["minWidth"].is_number()) {
SetMinWidth(styleDef["minWidth"].template get<float>());
} else if (styleDef["minWidth"].is_string()) {
auto minWidth = styleDef["minWidth"].template get<std::string>();
if (styleDef.contains("minWidth")) {
if (styleDef["minWidth"].is_number()) {
SetMinWidth(styleDef["minWidth"].template get<float>());
} else if (styleDef["minWidth"].is_string()) {
auto minWidth = styleDef["minWidth"].template get<std::string>();

if (auto maybePct = charPercentageToFloat(minWidth.c_str()); maybePct.has_value()) {
SetMinWidthPercent(maybePct.value());
if (auto maybePct = charPercentageToFloat(minWidth.c_str()); maybePct.has_value()) {
SetMinWidthPercent(maybePct.value());
}
}
}
}

if (styleDef.contains("maxWidth")) {
if (styleDef["maxWidth"].is_number()) {
SetMaxWidth(styleDef["maxWidth"].template get<float>());
} else if (styleDef["maxWidth"].is_string()) {
auto maxWidth = styleDef["maxWidth"].template get<std::string>();
if (styleDef.contains("maxWidth")) {
if (styleDef["maxWidth"].is_number()) {
SetMaxWidth(styleDef["maxWidth"].template get<float>());
} else if (styleDef["maxWidth"].is_string()) {
auto maxWidth = styleDef["maxWidth"].template get<std::string>();

if (auto maybePct = charPercentageToFloat(maxWidth.c_str()); maybePct.has_value()) {
SetMaxWidthPercent(maybePct.value());
if (auto maybePct = charPercentageToFloat(maxWidth.c_str()); maybePct.has_value()) {
SetMaxWidthPercent(maybePct.value());
}
}
}
}

if (styleDef.contains("height")) {
if (styleDef["height"].is_number()) {
SetHeight(styleDef["height"].template get<float>());
} else if (styleDef["height"].is_string()) {
auto height = styleDef["height"].template get<std::string>();
if (styleDef.contains("height")) {
if (styleDef["height"].is_number()) {
SetHeight(styleDef["height"].template get<float>());
} else if (styleDef["height"].is_string()) {
auto height = styleDef["height"].template get<std::string>();

if (height == "auto") {
SetHeightAuto();
} else if (auto maybePct = charPercentageToFloat(height.c_str()); maybePct.has_value()) {
SetHeightPercent(maybePct.value());
if (height == "auto") {
SetHeightAuto();
} else if (auto maybePct = charPercentageToFloat(height.c_str()); maybePct.has_value()) {
SetHeightPercent(maybePct.value());
}
}
}
}

if (styleDef.contains("minHeight")) {
if (styleDef["minHeight"].is_number()) {
SetMinHeight(styleDef["minHeight"].template get<float>());
} else if (styleDef["minHeight"].is_string()) {
auto minHeight = styleDef["minHeight"].template get<std::string>();
if (styleDef.contains("minHeight")) {
if (styleDef["minHeight"].is_number()) {
SetMinHeight(styleDef["minHeight"].template get<float>());
} else if (styleDef["minHeight"].is_string()) {
auto minHeight = styleDef["minHeight"].template get<std::string>();

if (auto maybePct = charPercentageToFloat(minHeight.c_str()); maybePct.has_value()) {
SetMinHeightPercent(maybePct.value());
if (auto maybePct = charPercentageToFloat(minHeight.c_str()); maybePct.has_value()) {
SetMinHeightPercent(maybePct.value());
}
}
}
}

if (styleDef.contains("maxHeight")) {
if (styleDef["maxHeight"].is_number()) {
SetMaxHeight(styleDef["maxHeight"].template get<float>());
} else if (styleDef["maxHeight"].is_string()) {
auto maxHeight = styleDef["maxHeight"].template get<std::string>();
if (styleDef.contains("maxHeight")) {
if (styleDef["maxHeight"].is_number()) {
SetMaxHeight(styleDef["maxHeight"].template get<float>());
} else if (styleDef["maxHeight"].is_string()) {
auto maxHeight = styleDef["maxHeight"].template get<std::string>();

if (auto maybePct = charPercentageToFloat(maxHeight.c_str()); maybePct.has_value()) {
SetMaxHeightPercent(maybePct.value());
if (auto maybePct = charPercentageToFloat(maxHeight.c_str()); maybePct.has_value()) {
SetMaxHeightPercent(maybePct.value());
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/dear-imgui/cpp/src/reactimgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ void ReactImgui::CreateElement(const json& elementDef) {
m_hierarchy[id] = std::vector<int>();

if (elementDef.is_object() && elementDef.contains("style") && elementDef["style"].is_object()) {
m_elements[id]->m_layoutNode->ApplyStyle(elementDef["style"]);
m_elements[id]->SetStyle(elementDef["style"]);
}
} else {
printf("unrecognised element type: '%s'\n", type.c_str());
Expand Down
Loading

0 comments on commit ed7542b

Please sign in to comment.