diff --git a/data/layout.xml b/data/layout.xml
index 7870803..029580a 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -22,6 +22,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -30,8 +44,9 @@
-
-
+
+
+
@@ -93,5 +108,5 @@
-
+
diff --git a/engine/app.cpp b/engine/app.cpp
index 42ffedf..bb4971f 100644
--- a/engine/app.cpp
+++ b/engine/app.cpp
@@ -128,6 +128,35 @@ void App::init()
{
button->on_click = [] { exit(0); };
}
+ if (auto* button = layout[main_id].find("btn-popup"))
+ {
+ button->on_click = [this] {
+// auto nb = new NodeButton();
+// nb->init();
+// nb->SetWidth(50);
+// nb->SetHeightP(100);
+// nb->m_border->SetWidthP(100);
+// nb->m_border->SetHeightP(100);
+// nb->m_text->m_text = "NB";
+// nb->create();
+// layout[main_id].find("toolbar")->add_child(nb);
+// layout[main_id].update(width, height);
+ msgbox = new NodeMessageBox();
+ msgbox->m_manager = &layout;
+ msgbox->init();
+ layout[main_id].add_child(msgbox);
+ layout[main_id].update(width, height);
+ };
+ }
+
+ msgbox = new NodeMessageBox();
+ msgbox->m_manager = &layout;
+ msgbox->init();
+ layout[main_id].add_child(msgbox);
+
+ //msgbox->find("btn-ok")->on_click = [] { exit(0); };
+// msgbox->find("btn-ok")->m_text->m_text = "DO";
+// msgbox->find("btn-ok")->m_text->create();
sampler.create(GL_NEAREST);
ShaderManager::create(kShader::Texture, shader_v, shader_f);
@@ -171,28 +200,29 @@ void App::update(float dt)
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glClear(GL_COLOR_BUFFER_BIT);
- if (layout.reload())
- {
- layout[main_id].update(width, height);
- }
+// if (layout.reload())
+// {
+// layout[main_id].update(width, height);
+// }
+ auto observer = [this](Node* n)
+ {
+ if (n->m_display)
+ {
+ auto box = n->m_clip;
+ glScissor((int)box.x-1, (int)(height - box.y - box.w)-1, (int)box.z+2, (int)box.w+2);
+ n->draw();
+ }
+ };
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_SCISSOR_TEST);
- for (auto& n : layout[main_id])
- {
- if (n.m_display)
- {
- auto box = n.m_clip;
- glScissor((int)box.x, (int)(height - box.y - box.w), (int)box.z, (int)box.w);
- n.draw();
- }
- }
+ layout[main_id].watch(observer);
+ //msgbox->watch(observer);
glDisable(GL_SCISSOR_TEST);
}
void App::resize(float w, float h)
{
- constexpr auto main_id = const_hash("main");
width = w;
height = h;
layout[main_id].update(w, h);
diff --git a/engine/app.h b/engine/app.h
index 35c3986..ca8f2a3 100644
--- a/engine/app.h
+++ b/engine/app.h
@@ -11,6 +11,7 @@ class App
Sampler sampler;
Texture2D tex;
LayoutManager layout;
+ NodeMessageBox* msgbox;
const uint16_t main_id = const_hash("main");
public:
static App I;
diff --git a/engine/layout.cpp b/engine/layout.cpp
index 6f63df9..1887426 100644
--- a/engine/layout.cpp
+++ b/engine/layout.cpp
@@ -62,6 +62,16 @@ void Node::add_child(Node* n)
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
}
+void Node::remove_child(Node* n)
+{
+ auto i = std::find_if(m_children.begin(), m_children.end(), [=](std::unique_ptr& ptr)
+ {
+ return ptr.get() == n;
+ });
+ m_children.erase(i);
+ YGNodeRemoveChild(y_node, n->y_node);
+}
+
void Node::update(float width, float height)
{
YGNodeStyleSetWidth(y_node, width);
@@ -212,6 +222,34 @@ void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
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;
@@ -333,6 +371,7 @@ Node* Node::clone()
{
Node* n = clone_instantiate();
clone_copy(n);
+ clone_children(n);
return n;
}
@@ -345,11 +384,24 @@ 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;
+}
+
+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 = m_manager;
YGNodeInsertChild(dest->y_node, cn->y_node, YGNodeGetChildCount(dest->y_node));
}
}
diff --git a/engine/layout.h b/engine/layout.h
index a97d49e..ea64d64 100644
--- a/engine/layout.h
+++ b/engine/layout.h
@@ -33,6 +33,8 @@ enum class kAttribute : uint16_t
Align = const_hash("align"),
Path = const_hash("path"),
Region = const_hash("region"),
+ Position = const_hash("position"),
+ Positioning = const_hash("positioning"),
};
enum class kWidget : uint16_t
@@ -105,15 +107,25 @@ public:
virtual kEventResult on_event(Event* e) { return kEventResult::Available; }
};
+class LayoutManager
+{
+ std::map> m_layouts;
+ std::string m_path;
+ struct stat m_file_info { 0 };
+public:
+ bool load(const char* path);
+ bool reload();
+ class Node& operator[](uint16_t id) { return *m_layouts[id]; }
+ //Node& operator[](const char* ids) { return m_layouts[const_hash(ids)]; }
+};
+
class Node
{
friend class LayoutManager;
-
- const Node* parent{ nullptr };
+public:
+ Node* parent{ nullptr };
YGNodeRef y_node{ nullptr };
class LayoutManager* m_manager;
-
-public:
uint16_t m_nodeID;
std::string m_nodeID_s;
std::vector> m_children;
@@ -168,6 +180,18 @@ public:
YGNodeStyleSetPadding(y_node, YGEdgeBottom, b);
YGNodeStyleSetPadding(y_node, YGEdgeLeft, l);
}
+ void SetPosition(float l, float t, float r, float b)
+ {
+ YGNodeStyleSetPadding(y_node, YGEdgeTop, t);
+ YGNodeStyleSetPadding(y_node, YGEdgeRight, r);
+ YGNodeStyleSetPadding(y_node, YGEdgeBottom, b);
+ YGNodeStyleSetPadding(y_node, YGEdgeLeft, l);
+ }
+ void SetPosition(float l, float t)
+ {
+ YGNodeStyleSetPadding(y_node, YGEdgeTop, t);
+ YGNodeStyleSetPadding(y_node, YGEdgeLeft, l);
+ }
void SetFlexGrow(float value) { YGNodeStyleSetFlexGrow(y_node, value); }
void SetFlexShrink(float value) { YGNodeStyleSetFlexShrink(y_node, value); }
@@ -175,6 +199,7 @@ public:
void SetFlexWrap(YGWrap value) { YGNodeStyleSetFlexWrap(y_node, value); }
void SetJustify(YGJustify value) { YGNodeStyleSetJustifyContent(y_node, value); }
void SetAlign(YGAlign value) { YGNodeStyleSetAlignItems(y_node, value); }
+ void SetPositioning(YGPositionType value) { YGNodeStyleSetPositionType(y_node, value); }
glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b)
{
@@ -194,64 +219,72 @@ public:
Node* clone();
virtual Node* clone_instantiate() const;
virtual void clone_copy(Node* dest) const;
+ virtual void clone_children(Node* dest) const;
+ void watch(std::function observer)
+ {
+ observer(this);
+ for (auto& c : m_children)
+ c->watch(observer);
+ }
- template T* find(const char* ids)
+ template T* find(const char* ids)
{
uint16_t id = const_hash(ids);
if (id == m_nodeID)
return static_cast(this);
- for (auto& c : *this)
- if (c.m_nodeID == id)
- return static_cast(&c);
+ for (auto& c : m_children)
+ if (auto found = c->find(ids))
+ return static_cast(found);
return nullptr;
}
- kEventResult on_event(Event* e);
+ virtual kEventResult on_event(Event* e);
virtual kEventResult handle_event(Event* e) { return kEventResult::Available; }
virtual void create() { }
virtual void init() { }
void add_child(Node* n);
+ void remove_child(Node* n);
- class iterator
- {
- std::stack m_nodes;
- Node* m_current;
- public:
- iterator(Node* root)
- {
- m_current = root;
- if (root)
- m_nodes.push(root);
- }
- iterator& operator++()
- {
- m_nodes.pop();
- for (auto& c : m_current->m_children)
- m_nodes.push(c.get());
- m_current = m_nodes.size() ? m_nodes.top() : nullptr;
- return *this;
- }
- Node& operator*() { return *m_current; }
- Node* operator->() { return m_current; }
- bool operator==(const iterator& rhs) { return m_current == rhs.m_current; }
- bool operator!=(const iterator& rhs) { return m_current != rhs.m_current; }
- };
- iterator begin()
- {
- return this;
- }
- iterator end()
- {
- return nullptr;
- }
+// class iterator
+// {
+// std::stack m_nodes;
+// Node* m_current;
+// public:
+// iterator(Node* root)
+// {
+// m_current = root;
+// if (root)
+// m_nodes.push(root);
+// }
+// iterator& operator++()
+// {
+// m_nodes.pop();
+// for (auto& c : m_current->m_children)
+// m_nodes.push(c.get());
+// m_current = m_nodes.size() ? m_nodes.top() : nullptr;
+// return *this;
+// }
+// Node& operator*() { return *m_current; }
+// Node* operator->() { return m_current; }
+// bool operator==(const iterator& rhs) { return m_current == rhs.m_current; }
+// bool operator!=(const iterator& rhs) { return m_current != rhs.m_current; }
+// };
+// iterator begin()
+// {
+// return this;
+// }
+// iterator end()
+// {
+// return nullptr;
+// }
};
class NodeBorder : public Node
{
public:
static Plane m_plane;
- glm::vec4 m_color;
- glm::vec4 m_border_color;
+ glm::vec4 m_color{ 0, 0, 0, 1 };
+ glm::vec4 m_border_color{ 1, 1, 1, 1 };
float m_thinkness{ 1 };
static void static_init()
{
@@ -303,12 +336,18 @@ public:
ShaderManager::use(kShader::Color);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
+ if (m_color.a != 1.f)
+ glEnable(GL_BLEND);
+
ShaderManager::u_vec4(kShaderUniform::Col, m_color);
m_plane.draw_fill();
-
+
glLineWidth(m_thinkness);
ShaderManager::u_vec4(kShaderUniform::Col, m_border_color);
m_plane.draw_stroke();
+
+ if (m_color.a != 1.f)
+ glDisable(GL_BLEND);
}
};
@@ -325,6 +364,11 @@ public:
{
Node::clone_copy(dest);
NodeText* n = static_cast(dest);
+ n->m_text_mesh = m_text_mesh;
+ n->m_text = m_text;
+ n->m_font = m_font;
+ n->m_color = m_color;
+ n->m_font_size = m_font_size;
}
virtual void create() override
{
@@ -387,7 +431,7 @@ public:
glm::vec2 m_off;
glm::vec2 m_sz;
std::string m_path;
- uint16_t m_id;
+ uint16_t m_tex_id;
static void static_init()
{
m_plane.create<1>(1, 1);
@@ -398,12 +442,18 @@ public:
{
Node::clone_copy(dest);
NodeImage* n = static_cast(dest);
+ n->m_use_atlas = m_use_atlas;
+ n->m_region = m_region;
+ n->m_off = m_off;
+ n->m_sz = m_sz;
+ n->m_path = m_path;
+ n->m_tex_id = m_tex_id;
}
virtual void create() override
{
if (TextureManager::load(m_path.c_str()))
{
- auto tex_sz = TextureManager::get(m_id).size();
+ auto tex_sz = TextureManager::get(m_tex_id).size();
m_off = m_region.xy / tex_sz;
m_sz = (m_region.zw - m_region.xy) / tex_sz;
}
@@ -415,7 +465,7 @@ public:
{
case kAttribute::Path:
m_path = attr->Value();
- m_id = const_hash(attr->Value());
+ m_tex_id = const_hash(attr->Value());
break;
case kAttribute::Region:
{
@@ -434,7 +484,7 @@ public:
}
virtual void draw() override
{
- TextureManager::get(m_id).bind();
+ TextureManager::get(m_tex_id).bind();
m_sampler.bind(0);
glEnable(GL_BLEND);
if (m_use_atlas)
@@ -451,7 +501,7 @@ public:
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
m_plane.draw_fill();
m_sampler.unbind();
- TextureManager::get(m_id).unbind();
+ TextureManager::get(m_tex_id).unbind();
glDisable(GL_BLEND);
}
};
@@ -465,11 +515,24 @@ public:
glm::vec4 color_hover{ .2, .2, .2, 1 };
glm::vec4 color_down{ .3, .3, .3, 1 };
std::function on_click;
- virtual Node* clone_instantiate() const override { return new NodeImage(); }
+ virtual Node* clone_instantiate() const override { return new NodeButton(); }
+ virtual void clone_children(Node* dest) const override
+ {
+ Node::clone_children(dest);
+ NodeButton* n = static_cast(dest);
+ n->m_border = (NodeBorder*)n->m_children[0].get();
+ n->m_text = (NodeText*)n->m_border->m_children[0].get();
+ }
virtual void clone_copy(Node* dest) const override
{
Node::clone_copy(dest);
- NodeImage* n = static_cast(dest);
+ NodeButton* n = static_cast(dest);
+ //n->m_border = (NodeBorder*)m_border->clone();
+ //n->m_text = (NodeText*)m_text->clone();
+ n->color_normal = color_normal;
+ n->color_hover = color_hover;
+ n->color_down = color_down;
+ //n->on_click = on_click;
}
virtual void init() override
{
@@ -478,6 +541,7 @@ public:
add_child(m_border);
m_border->add_child(m_text);
m_border->init();
+ m_border->m_color = color_normal;
m_text->init();
m_text->m_font = "arial";
m_text->m_font_size = 11;
@@ -491,9 +555,9 @@ public:
}
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override
{
- Node::parse_attributes(ka, attr);
switch (ka)
{
+ case kAttribute::Padding:
case kAttribute::Width:
case kAttribute::Height:
case kAttribute::Color:
@@ -507,16 +571,12 @@ public:
m_text->parse_attributes(ka, attr);
break;
default:
+ Node::parse_attributes(ka, attr);
break;
}
// m_border->parse_attributes(ka, attr);
// m_text->parse_attributes(ka, attr);
}
- virtual void draw() override
- {
- m_border->draw();
- m_text->draw();
- }
virtual kEventResult handle_event(Event* e) override
{
switch (e->m_type)
@@ -542,14 +602,43 @@ public:
}
};
-class LayoutManager
+class NodeMessageBox : public Node
{
- std::map> m_layouts;
- std::string m_path;
- struct stat m_file_info { 0 };
public:
- bool load(const char* path);
- bool reload();
- Node& operator[](uint16_t id) { return *m_layouts[id]; }
- //Node& operator[](const char* ids) { return m_layouts[const_hash(ids)]; }
+ Node* m_template;
+ NodeButton* btnOk;
+ virtual Node* clone_instantiate() const override { return new NodeMessageBox(); }
+ virtual void clone_copy(Node* dest) const override
+ {
+ Node::clone_copy(dest);
+ NodeMessageBox* n = static_cast(dest);
+ }
+ virtual void init() override
+ {
+ SetPosition(0, 0);
+ SetWidthP(100);
+ SetHeightP(100);
+ SetPositioning(YGPositionTypeAbsolute);
+ m_template = (*m_manager)[const_hash("message-box")].m_children[0]->clone();
+ add_child(m_template);
+ btnOk = m_template->find("btn-ok");
+ btnOk->on_click = [&] { parent->remove_child(this); };
+// btnOk = (NodeButton*)n;
+// btnOk->m_display = false;
+ }
+ virtual void create() override
+ {
+ }
+ virtual void draw() override
+ {
+ //m_template->draw();
+ }
+// virtual kEventResult handle_event(Event* e) override
+// {
+// return kEventResult::Available;
+// }
+ virtual kEventResult on_event(Event* e)
+ {
+ return Node::on_event(e);
+ }
};