868 lines
23 KiB
C++
868 lines
23 KiB
C++
#include "pch.h"
|
|
#include "log.h"
|
|
#include "node.h"
|
|
#include "layout.h"
|
|
#include "util.h"
|
|
#include "asset.h"
|
|
#include "node_border.h"
|
|
#include "node_image.h"
|
|
#include "node_image_texture.h"
|
|
#include "node_icon.h"
|
|
#include "node_text.h"
|
|
#include "node_text_input.h"
|
|
#include "node_button.h"
|
|
#include "node_button_custom.h"
|
|
#include "node_slider.h"
|
|
#include "node_popup_menu.h"
|
|
#include "node_viewport.h"
|
|
#include "node_checkbox.h"
|
|
#include "node_panel_layer.h"
|
|
#include "node_panel_brush.h"
|
|
#include "node_panel_color.h"
|
|
#include "node_panel_stroke.h"
|
|
#include "node_color_quad.h"
|
|
#include "node_stroke_preview.h"
|
|
#include "node_canvas.h"
|
|
#include "node_scroll.h"
|
|
|
|
void Node::watch(std::function<void(Node*)> observer)
|
|
{
|
|
observer(this);
|
|
for (auto& c : m_children)
|
|
c->watch(observer);
|
|
}
|
|
|
|
void Node::destroy()
|
|
{
|
|
m_destroyed = true;
|
|
}
|
|
|
|
Node* Node::root()
|
|
{
|
|
|
|
Node* ret = this;
|
|
while (ret->parent)
|
|
ret = ret->parent;
|
|
return ret;
|
|
}
|
|
|
|
kEventResult Node::on_event(Event* e)
|
|
{
|
|
kEventResult ret = kEventResult::Available;
|
|
|
|
if (current_mouse_capture)
|
|
return current_mouse_capture->on_event(e);
|
|
|
|
bool skip_children = false;
|
|
skip_children |= (e->m_cat == kEventCategory::MouseEvent) &&
|
|
(m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children;
|
|
|
|
if (!skip_children)
|
|
{
|
|
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::MouseScroll:
|
|
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;
|
|
}
|
|
|
|
kEventResult Node::handle_event(Event* e)
|
|
{
|
|
return kEventResult::Available;
|
|
}
|
|
|
|
void Node::handle_resize(glm::vec2 old_size, glm::vec2 new_size)
|
|
{
|
|
|
|
}
|
|
|
|
void Node::create()
|
|
{
|
|
|
|
}
|
|
|
|
void Node::init()
|
|
{
|
|
|
|
}
|
|
|
|
void Node::loaded()
|
|
{
|
|
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
Node* Node::get_child_at(int index)
|
|
{
|
|
auto n = YGNodeGetChild(y_node, index);
|
|
for (auto& c : m_children)
|
|
{
|
|
if (c->y_node == n)
|
|
return c.get();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
glm::vec4 Node::get_children_rect() const
|
|
{
|
|
if (m_children.empty())
|
|
return glm::vec4(0);
|
|
glm::vec4 ret = m_children[0]->m_clip_uncut;
|
|
for (auto& c : m_children)
|
|
ret = rect_union(ret, c->m_clip_uncut);
|
|
return ret;
|
|
}
|
|
|
|
void Node::mouse_capture()
|
|
{
|
|
root()->current_mouse_capture = this;
|
|
m_mouse_captured = true;
|
|
}
|
|
|
|
void Node::mouse_release()
|
|
{
|
|
if (root()->current_mouse_capture == this)
|
|
root()->current_mouse_capture = nullptr;
|
|
m_mouse_captured = false;
|
|
}
|
|
|
|
void Node::key_capture()
|
|
{
|
|
root()->current_key_capture = this;
|
|
m_key_captured = true;
|
|
}
|
|
|
|
void Node::key_release()
|
|
{
|
|
root()->current_key_capture = nullptr;
|
|
m_key_captured = false;
|
|
}
|
|
|
|
Node&& Node::operator=(Node&& o)
|
|
{
|
|
return std::forward<Node>(o);
|
|
}
|
|
|
|
Node::Node()
|
|
{
|
|
y_node = YGNodeNew();
|
|
}
|
|
|
|
Node::Node(Node&& o)
|
|
{
|
|
m_name = std::move(o.m_name);
|
|
m_nodeID_s = std::move(o.m_nodeID_s);
|
|
m_children = std::move(o.m_children);
|
|
for (auto& c : m_children)
|
|
c->parent = this;
|
|
m_nodeID = o.m_nodeID;
|
|
m_display = o.m_display;
|
|
parent = o.parent;
|
|
y_node = o.y_node;
|
|
m_pos = o.m_pos;
|
|
m_size = o.m_size;
|
|
m_clip = o.m_clip;
|
|
m_zoom = o.m_zoom;
|
|
m_mouse_ignore = o.m_mouse_ignore;
|
|
o.y_node = nullptr;
|
|
o.parent = nullptr;
|
|
}
|
|
|
|
Node::~Node()
|
|
{
|
|
m_children.clear();
|
|
if (y_node)
|
|
YGNodeFree(y_node);
|
|
}
|
|
|
|
void Node::SetWidth(float value)
|
|
{
|
|
YGNodeStyleSetWidth(y_node, value);
|
|
}
|
|
|
|
void Node::SetWidthP(float value)
|
|
{
|
|
YGNodeStyleSetWidthPercent(y_node, value);
|
|
}
|
|
|
|
void Node::SetHeight(float value)
|
|
{
|
|
YGNodeStyleSetHeight(y_node, value);
|
|
}
|
|
|
|
void Node::SetHeightP(float value)
|
|
{
|
|
YGNodeStyleSetHeightPercent(y_node, value);
|
|
}
|
|
|
|
void Node::SetSize(float w, float h)
|
|
{
|
|
SetWidth(w); SetHeight(h);
|
|
}
|
|
|
|
void Node::SetSize(glm::vec2 value)
|
|
{
|
|
SetWidth(value.x); SetHeight(value.y);
|
|
}
|
|
|
|
void Node::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);
|
|
}
|
|
|
|
glm::vec4 Node::GetPadding() const
|
|
{
|
|
float t = YGNodeLayoutGetPadding(y_node, YGEdgeTop);
|
|
float r = YGNodeLayoutGetPadding(y_node, YGEdgeRight);
|
|
float b = YGNodeLayoutGetPadding(y_node, YGEdgeBottom);
|
|
float l = YGNodeLayoutGetPadding(y_node, YGEdgeLeft);
|
|
return{ t, r, b, l };
|
|
}
|
|
|
|
void Node::SetPosition(const glm::vec2 pos)
|
|
{
|
|
SetPosition(pos.x, pos.y);
|
|
}
|
|
|
|
void Node::SetPosition(float l, float t)
|
|
{
|
|
YGNodeStyleSetPosition(y_node, YGEdgeTop, t);
|
|
YGNodeStyleSetPosition(y_node, YGEdgeLeft, l);
|
|
}
|
|
|
|
void Node::SetPosition(float l, float t, float r, float b)
|
|
{
|
|
YGNodeStyleSetPosition(y_node, YGEdgeTop, t);
|
|
YGNodeStyleSetPosition(y_node, YGEdgeRight, r);
|
|
YGNodeStyleSetPosition(y_node, YGEdgeBottom, b);
|
|
YGNodeStyleSetPosition(y_node, YGEdgeLeft, l);
|
|
}
|
|
|
|
void Node::SetFlexGrow(float value)
|
|
{
|
|
YGNodeStyleSetFlexGrow(y_node, value);
|
|
}
|
|
|
|
void Node::SetFlexShrink(float value)
|
|
{
|
|
YGNodeStyleSetFlexShrink(y_node, value);
|
|
}
|
|
|
|
void Node::SetFlexDir(YGFlexDirection value)
|
|
{
|
|
YGNodeStyleSetFlexDirection(y_node, value);
|
|
}
|
|
|
|
void Node::SetFlexWrap(YGWrap value)
|
|
{
|
|
YGNodeStyleSetFlexWrap(y_node, value);
|
|
}
|
|
|
|
void Node::SetJustify(YGJustify value)
|
|
{
|
|
YGNodeStyleSetJustifyContent(y_node, value);
|
|
}
|
|
|
|
void Node::SetAlign(YGAlign value)
|
|
{
|
|
YGNodeStyleSetAlignItems(y_node, value);
|
|
}
|
|
|
|
void Node::SetPositioning(YGPositionType value)
|
|
{
|
|
YGNodeStyleSetPositionType(y_node, value);
|
|
}
|
|
|
|
void Node::SetAspectRatio(float ar)
|
|
{
|
|
YGNodeStyleSetAspectRatio(y_node, ar);
|
|
}
|
|
|
|
glm::vec2 Node::GetPosition()
|
|
{
|
|
return{ YGNodeLayoutGetLeft(y_node), YGNodeLayoutGetTop(y_node) };
|
|
}
|
|
|
|
float Node::GetWidth()
|
|
{
|
|
return YGNodeLayoutGetWidth(y_node);
|
|
}
|
|
|
|
float Node::GetHeight()
|
|
{
|
|
return YGNodeLayoutGetHeight(y_node);
|
|
}
|
|
|
|
glm::vec2 Node::GetSize()
|
|
{
|
|
return{ GetWidth(), GetHeight() };
|
|
}
|
|
|
|
glm::vec4 Node::rect_intersection(glm::vec4 a, glm::vec4 b) const
|
|
{
|
|
// 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());
|
|
// compute intersection
|
|
auto o = glm::vec4(glm::max(a.xy(), b.xy()), glm::min(a.zw(), b.zw()));
|
|
// back to rect form
|
|
o = glm::vec4(o.xy(), glm::max({ 0, 0 }, o.zw() - o.xy()));
|
|
return o;
|
|
}
|
|
|
|
glm::vec4 Node::rect_union(glm::vec4 a, glm::vec4 b) const
|
|
{
|
|
// convert from rect [x,y,w,h] to bb [x1,y1,x2,y1]
|
|
a = glm::vec4(a.xy(), a.xy() + a.zw());
|
|
b = glm::vec4(b.xy(), b.xy() + b.zw());
|
|
// compute union
|
|
glm::vec4 o = { glm::min(a.xy(), b.xy()), glm::max(a.zw(), b.zw()) };
|
|
// back to rect form
|
|
o = glm::vec4(o.xy(), glm::max({ 0, 0 }, o.zw() - o.xy()));
|
|
return o;
|
|
}
|
|
|
|
void Node::restore_context()
|
|
{
|
|
for (auto& c : m_children)
|
|
c->restore_context();
|
|
}
|
|
|
|
void Node::clear_context()
|
|
{
|
|
for (auto& c : m_children)
|
|
c->clear_context();
|
|
}
|
|
|
|
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;
|
|
glm::vec2 parent_offset = parent ? parent->m_pos_offset_childred : glm::vec2(0.f);
|
|
m_pos = glm::floor(origin + glm::vec2(x, y) + m_pos_offset + parent_offset);
|
|
m_pos_origin = 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_uncut = 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);
|
|
CASE(kWidget::Scroll, NodeScroll);
|
|
#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();
|
|
}
|
|
|
|
void Node::draw()
|
|
{
|
|
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
void Node::clone_finalize(Node* dest) const
|
|
{
|
|
/* find controllers and stuff */
|
|
}
|