refactor layout.h into single file per Node* classes
This commit is contained in:
@@ -3,537 +3,8 @@
|
||||
#include "layout.h"
|
||||
#include "util.h"
|
||||
#include "asset.h"
|
||||
|
||||
using namespace ui;
|
||||
|
||||
Plane NodeBorder::m_plane;
|
||||
Plane NodeImage::m_plane;
|
||||
Sampler NodeImage::m_sampler;
|
||||
std::map<std::string, glm::vec4> NodeIcon::m_icons;
|
||||
|
||||
kEventResult Node::on_event(Event* e)
|
||||
{
|
||||
if (current_mouse_capture)
|
||||
return current_mouse_capture->on_event(e);
|
||||
|
||||
kEventResult ret = kEventResult::Available;
|
||||
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it)
|
||||
{
|
||||
if ((*it)->on_event(e) == kEventResult::Consumed)
|
||||
{
|
||||
if (m_flood_events)
|
||||
{
|
||||
ret = kEventResult::Consumed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return kEventResult::Consumed;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == kEventResult::Consumed)
|
||||
return ret;
|
||||
switch (e->m_cat)
|
||||
{
|
||||
case kEventCategory::MouseEvent:
|
||||
{
|
||||
if (m_mouse_ignore)
|
||||
break;
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
bool inside = point_in_rect(me->m_pos, m_clip);
|
||||
bool inside_old = m_mouse_inside;
|
||||
m_mouse_inside = inside;
|
||||
switch (e->m_type)
|
||||
{
|
||||
case kEventType::MouseDownL:
|
||||
case kEventType::MouseDownR:
|
||||
case kEventType::MouseUpL:
|
||||
case kEventType::MouseUpR:
|
||||
if ((inside || m_mouse_captured) && handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (inside_old == false && inside == true)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseEnter;
|
||||
handle_event(&e2);
|
||||
}
|
||||
if (inside || m_mouse_captured)
|
||||
ret = handle_event(e);
|
||||
if (inside_old == true && inside == false)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseLeave;
|
||||
handle_event(&e2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const Node* Node::init_template(const char* id)
|
||||
{
|
||||
const auto& m_template = static_cast<Node*>((*m_manager)[const_hash(id)]->m_children[0].get());
|
||||
for (auto& c : m_template->m_children)
|
||||
{
|
||||
auto node = c->clone();
|
||||
add_child(node);
|
||||
node->init();
|
||||
node->create();
|
||||
node->loaded();
|
||||
}
|
||||
YGNodeCopyStyle(y_node, m_template->y_node);
|
||||
return m_template;
|
||||
}
|
||||
|
||||
void Node::add_child(Node* n)
|
||||
{
|
||||
m_children.emplace_back(n);
|
||||
n->parent = this;
|
||||
n->m_manager = m_manager;
|
||||
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
|
||||
}
|
||||
|
||||
void Node::add_child(Node* n, int index)
|
||||
{
|
||||
m_children.emplace_back(n);
|
||||
n->parent = this;
|
||||
n->m_manager = m_manager;
|
||||
YGNodeInsertChild(y_node, n->y_node, index);
|
||||
}
|
||||
|
||||
void Node::add_child(std::shared_ptr<Node> n)
|
||||
{
|
||||
m_children.push_back(n);
|
||||
n->parent = this;
|
||||
n->m_manager = m_manager;
|
||||
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
|
||||
}
|
||||
void Node::add_child(std::shared_ptr<Node> n, int index)
|
||||
{
|
||||
m_children.push_back(n);
|
||||
n->parent = this;
|
||||
n->m_manager = m_manager;
|
||||
YGNodeInsertChild(y_node, n->y_node, index);
|
||||
}
|
||||
void Node::remove_child(Node* n)
|
||||
{
|
||||
auto i = std::find_if(m_children.begin(), m_children.end(), [=](auto& ptr) { return ptr.get() == n; });
|
||||
if (i != m_children.end())
|
||||
{
|
||||
YGNodeRemoveChild(y_node, n->y_node);
|
||||
m_children.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::remove_all_children()
|
||||
{
|
||||
for (auto& n : m_children)
|
||||
YGNodeRemoveChild(y_node, n->y_node);
|
||||
m_children.clear();
|
||||
}
|
||||
void Node::move_child(Node* n, int index)
|
||||
{
|
||||
YGNodeRemoveChild(y_node, n->y_node);
|
||||
YGNodeInsertChild(y_node, n->y_node, index);
|
||||
}
|
||||
|
||||
void Node::move_child_offset(Node* n, int offset)
|
||||
{
|
||||
int count = YGNodeGetChildCount(y_node);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (YGNodeGetChild(y_node, i) == n->y_node)
|
||||
{
|
||||
int new_index = glm::clamp<int>(i + offset, 0, count - 1);
|
||||
YGNodeRemoveChild(y_node, n->y_node);
|
||||
YGNodeInsertChild(y_node, n->y_node, new_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Node::get_child_index(Node* n)
|
||||
{
|
||||
int count = YGNodeGetChildCount(y_node);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (YGNodeGetChild(y_node, i) == n->y_node)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Node::update(float width, float height, float zoom)
|
||||
{
|
||||
m_zoom = zoom;
|
||||
YGNodeStyleSetWidth(y_node, width / zoom);
|
||||
YGNodeStyleSetHeight(y_node, height / zoom);
|
||||
YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR);
|
||||
m_proj = glm::ortho(0.f, width / zoom, height / zoom, 0.f, -1.f, 1.f);
|
||||
update_internal({ 0, 0 }, m_proj);
|
||||
}
|
||||
|
||||
void Node::update()
|
||||
{
|
||||
YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR);
|
||||
update_internal({ 0, 0 }, m_proj);
|
||||
}
|
||||
|
||||
void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj)
|
||||
{
|
||||
float x = YGNodeLayoutGetLeft(y_node);
|
||||
float y = YGNodeLayoutGetTop(y_node);
|
||||
float w = YGNodeLayoutGetWidth(y_node);
|
||||
float h = YGNodeLayoutGetHeight(y_node);
|
||||
auto old_size = m_size;
|
||||
m_pos = glm::floor(origin + glm::vec2(x, y));
|
||||
m_size = glm::floor(glm::vec2(w, h));
|
||||
|
||||
if (parent)
|
||||
{
|
||||
// correct the padding clip
|
||||
// should not clip the padded area
|
||||
// useful to draw decorations
|
||||
float pt = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeTop);
|
||||
float pr = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeRight);
|
||||
float pb = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeBottom);
|
||||
float pl = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeLeft);
|
||||
glm::vec2 off_p(pl, pt);
|
||||
glm::vec2 off_s(pr, pb);
|
||||
m_clip_uncut = glm::vec4(m_pos - off_p, m_size + off_p + off_s);
|
||||
m_clip = rect_intersection(m_clip_uncut, parent->m_clip);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_clip = glm::vec4(m_pos, m_size);
|
||||
}
|
||||
|
||||
glm::mat4 pivot = glm::translate(glm::vec3(.5f, .5f, 0.f));
|
||||
glm::mat4 scale = glm::scale(glm::vec3(m_size, 1.f));
|
||||
glm::mat4 prescale = glm::scale(glm::vec3(m_scale, 1.f));
|
||||
glm::mat4 pos = glm::translate(glm::vec3(m_pos, 0));
|
||||
m_mvp = proj * pos * scale * pivot * prescale;
|
||||
m_proj = proj;
|
||||
|
||||
for (int i = 0; i < m_children.size(); i++)
|
||||
{
|
||||
if (m_children[i]->m_destroyed)
|
||||
{
|
||||
remove_child(m_children[i].get());
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_size != old_size)
|
||||
handle_resize(old_size, m_size);
|
||||
|
||||
for (auto& c : m_children)
|
||||
c->update_internal(m_pos, proj);
|
||||
}
|
||||
|
||||
void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
|
||||
{
|
||||
switch (ka)
|
||||
{
|
||||
case kAttribute::id:
|
||||
m_nodeID_s = attr->Value();
|
||||
m_nodeID = const_hash(attr->Value());
|
||||
break;
|
||||
case 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 kAttribute::MinWidth:
|
||||
YGNodeStyleSetMinWidth(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::MaxWidth:
|
||||
YGNodeStyleSetMaxWidth(y_node, attr->FloatValue());
|
||||
break;
|
||||
case 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 kAttribute::MinHeight:
|
||||
YGNodeStyleSetMinHeight(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::MaxHeight:
|
||||
YGNodeStyleSetMaxHeight(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Grow:
|
||||
YGNodeStyleSetFlexGrow(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Shrink:
|
||||
YGNodeStyleSetFlexShrink(y_node, attr->FloatValue());
|
||||
break;
|
||||
case 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 kAttribute::FlexWrap:
|
||||
YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap);
|
||||
break;
|
||||
case kAttribute::Justify:
|
||||
{
|
||||
YGJustify v = YGJustifyFlexStart;
|
||||
if (strcmp("center", attr->Value()) == 0)
|
||||
v = YGJustifyCenter;
|
||||
else if (strcmp("flex-start", attr->Value()) == 0)
|
||||
v = YGJustifyFlexStart;
|
||||
else if (strcmp("flex-end", attr->Value()) == 0)
|
||||
v = YGJustifyFlexEnd;
|
||||
else if (strcmp("space-around", attr->Value()) == 0)
|
||||
v = YGJustifySpaceAround;
|
||||
else if (strcmp("space-between", attr->Value()) == 0)
|
||||
v = YGJustifySpaceBetween;
|
||||
YGNodeStyleSetJustifyContent(y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Align:
|
||||
{
|
||||
YGAlign v = YGAlignStretch;
|
||||
if (strcmp("stretch", attr->Value()) == 0)
|
||||
v = YGAlignStretch;
|
||||
else if (strcmp("flex-start", attr->Value()) == 0)
|
||||
v = YGAlignFlexStart;
|
||||
else if (strcmp("flex-end", attr->Value()) == 0)
|
||||
v = YGAlignFlexEnd;
|
||||
else if (strcmp("center", attr->Value()) == 0)
|
||||
v = YGAlignCenter;
|
||||
YGNodeStyleSetAlignItems(y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Positioning:
|
||||
{
|
||||
YGPositionType v = YGPositionTypeRelative;
|
||||
if (strcmp("relative", attr->Value()) == 0)
|
||||
v = YGPositionTypeRelative;
|
||||
else if (strcmp("absolute", attr->Value()) == 0)
|
||||
v = YGPositionTypeAbsolute;
|
||||
YGNodeStyleSetPositionType(y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Position:
|
||||
{
|
||||
glm::vec4 v;
|
||||
int n = sscanf(attr->Value(), "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
|
||||
if (n == 2)
|
||||
{
|
||||
YGNodeStyleSetPosition(y_node, YGEdgeLeft, v.x);
|
||||
YGNodeStyleSetPosition(y_node, YGEdgeTop, v.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeLeft, v.x);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeTop, v.y);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeRight, v.z);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeBottom, v.w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 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 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 kAttribute::FloodEvents:
|
||||
m_flood_events = attr->IntValue() > 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Node::load_internal(const tinyxml2::XMLElement* x_node)
|
||||
{
|
||||
m_name = x_node->Name();
|
||||
|
||||
init();
|
||||
|
||||
auto attr = x_node->FirstAttribute();
|
||||
while (attr)
|
||||
{
|
||||
parse_attributes((kAttribute)const_hash(attr->Name()), attr);
|
||||
attr = attr->Next();
|
||||
}
|
||||
|
||||
create();
|
||||
|
||||
auto x_child = x_node->FirstChildElement();
|
||||
while (x_child)
|
||||
{
|
||||
kWidget child_id = (kWidget)const_hash(x_child->Name());
|
||||
switch (child_id)
|
||||
{
|
||||
#define CASE(W,C) case W: { auto n = new C(); add_child(n); n->load_internal(x_child); break; }
|
||||
CASE(kWidget::Node, Node);
|
||||
CASE(kWidget::Border, NodeBorder);
|
||||
CASE(kWidget::Image, NodeImage);
|
||||
CASE(kWidget::ImageTexture, NodeImageTexture);
|
||||
CASE(kWidget::Icon, NodeIcon);
|
||||
CASE(kWidget::Text, NodeText);
|
||||
CASE(kWidget::TextInput, NodeTextInput);
|
||||
CASE(kWidget::Button , NodeButton);
|
||||
CASE(kWidget::ButtonCustom, NodeButtonCustom);
|
||||
CASE(kWidget::SliderH, NodeSliderH);
|
||||
CASE(kWidget::SliderV, NodeSliderV);
|
||||
CASE(kWidget::SliderHue, NodeSliderHue);
|
||||
CASE(kWidget::PopupMenu, NodePopupMenu);
|
||||
CASE(kWidget::Viewport, NodeViewport);
|
||||
CASE(kWidget::CheckBox, NodeCheckBox);
|
||||
CASE(kWidget::Layer, NodeLayer);
|
||||
CASE(kWidget::PanelLayer, NodePanelLayer);
|
||||
CASE(kWidget::PanelBrush, NodePanelBrush);
|
||||
CASE(kWidget::PanelColor, NodePanelColor);
|
||||
CASE(kWidget::PanelStroke, NodePanelStroke);
|
||||
CASE(kWidget::ColorQuad, NodeColorQuad);
|
||||
CASE(kWidget::StrokePreview, NodeStrokePreview);
|
||||
CASE(kWidget::Canvas, NodeCanvas);
|
||||
#undef CASE
|
||||
case kWidget::Ref:
|
||||
{
|
||||
auto ids = x_child->Attribute("id");
|
||||
auto id = const_hash(ids);
|
||||
auto& ref = (*m_manager)[id]->m_children[0];
|
||||
auto n = ref->clone();
|
||||
n->m_nodeID_s = ids;
|
||||
n->m_nodeID = id;
|
||||
add_child(n);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG("instancing UNKNOWN node: %s", x_child->Name());
|
||||
auto n = new Node();
|
||||
add_child(n);
|
||||
n->load_internal(x_child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
x_child = x_child->NextSiblingElement();
|
||||
}
|
||||
loaded();
|
||||
}
|
||||
|
||||
Node* Node::clone()
|
||||
{
|
||||
Node* n = clone_instantiate();
|
||||
clone_copy(n);
|
||||
clone_children(n);
|
||||
clone_finalize(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
Node* Node::clone_instantiate() const
|
||||
{
|
||||
return new Node();
|
||||
}
|
||||
|
||||
void Node::clone_copy(Node* dest) const
|
||||
{
|
||||
YGNodeCopyStyle(dest->y_node, y_node);
|
||||
dest->m_manager = m_manager;
|
||||
|
||||
dest->m_name = m_name;
|
||||
dest->m_nodeID_s = m_nodeID_s;
|
||||
dest->m_nodeID = m_nodeID;
|
||||
dest->m_display = m_display;
|
||||
dest->m_pos = m_pos;
|
||||
dest->m_size = m_size;
|
||||
dest->m_clip = m_clip;
|
||||
dest->m_flood_events = m_flood_events;
|
||||
}
|
||||
|
||||
void Node::clone_children(Node* dest) const
|
||||
{
|
||||
for (auto& c : m_children)
|
||||
{
|
||||
Node* cn = c->clone();
|
||||
dest->m_children.emplace_back(cn);
|
||||
cn->parent = dest;
|
||||
cn->m_manager = dest->m_manager;
|
||||
YGNodeInsertChild(dest->y_node, cn->y_node, YGNodeGetChildCount(dest->y_node));
|
||||
}
|
||||
}
|
||||
#include "node.h"
|
||||
#include "node_border.h"
|
||||
|
||||
bool LayoutManager::load(const char* path)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user