diff --git a/data/layout.xml b/data/layout.xml
index b520fd3..18f8c4c 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -5,11 +5,13 @@
+
+
@@ -18,10 +20,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -38,6 +111,7 @@
+
@@ -75,6 +149,7 @@
+
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
@@ -219,29 +296,10 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
diff --git a/engine/app.cpp b/engine/app.cpp
index e94be0b..6b342df 100644
--- a/engine/app.cpp
+++ b/engine/app.cpp
@@ -13,26 +13,6 @@ App App::I; // singleton
#define SHADER_VERSION "#version 150\n"
#endif
-static std::vector FindAllBrushes(std::string folder)
-{
- std::vector names;
- std::string search_path = folder + "*.png";
- WIN32_FIND_DATAA fd;
- HANDLE hFind = ::FindFirstFileA(search_path.c_str(), &fd);
- if (hFind != INVALID_HANDLE_VALUE) {
- do {
- // read all (real) files in current folder
- // , delete '!' read other 2 default folder . and ..
- if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- names.push_back(fd.cFileName);
- }
- } while (::FindNextFileA(hFind, &fd));
- ::FindClose(hFind);
- }
- return names;
-}
-
-
void App::create()
{
width = 800;
@@ -169,33 +149,18 @@ void App::initLayout()
layout.on_loaded = [&] {
LOG("initializing layout updating after load");
- static auto icons = FindAllBrushes("data\\Icons\\");
- if (auto* container = layout[main_id]->find("brushes"))
- {
- if (auto* tpl = layout[const_hash("tpl-brush-icon")])
- {
- for (auto& i : icons)
- {
- NodeButtonCustom* btn = (NodeButtonCustom*)tpl->m_children[0]->clone();
- NodeImage* img = (NodeImage*)btn->m_children[0].get();
- img->m_path = "data\\Icons\\" + i;
- img->m_tex_id = const_hash(img->m_path.c_str());
- img->create();
- container->add_child(btn);
- }
- }
- }
layout[main_id]->update(width, height, zoom);
LOG("initializing layout components");
sidebar = layout[main_id]->find("sidebar");
+ brushes = layout[main_id]->find("panel-brushes");
if (auto* button = layout[main_id]->find("btn-close"))
{
- button->on_click = [] { exit(0); };
+ button->on_click = [](Node*) { exit(0); };
}
if (auto* button = layout[main_id]->find("btn-popup"))
{
- button->on_click = [this] {
+ button->on_click = [this](Node*) {
msgbox = new NodeMessageBox();
msgbox->m_manager = &layout;
msgbox->init();
@@ -205,7 +170,7 @@ void App::initLayout()
}
if (auto* button = layout[main_id]->find("btn-settings"))
{
- button->on_click = [this] {
+ button->on_click = [this](Node*) {
settings = new NodeSettings();
settings->m_manager = &layout;
settings->init();
@@ -215,35 +180,41 @@ void App::initLayout()
}
if (auto* menu_file = layout[main_id]->find("menu-file"))
{
- menu_file->on_click = [=] {
+ menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
popup = (NodePopupMenu*)layout[const_hash("file-menu")]->m_children[0]->clone();
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
layout[main_id]->update();
+ popup->mouse_capture();
+ popup->m_mouse_ignore = false;
};
}
if (auto* menu_file = layout[main_id]->find("menu-edit"))
{
- menu_file->on_click = [=] {
+ menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
popup = (NodePopupMenu*)layout[const_hash("edit-menu")]->m_children[0]->clone();
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
layout[main_id]->update();
+ popup->mouse_capture();
+ popup->m_mouse_ignore = false;
};
}
if (auto* menu_file = layout[main_id]->find("menu-layers"))
{
- menu_file->on_click = [=] {
+ menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
popup = (NodePopupMenu*)layout[const_hash("layers-menu")]->m_children[0]->clone();
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
layout[main_id]->update();
+ popup->mouse_capture();
+ popup->m_mouse_ignore = false;
};
}
if (auto* toolbar = layout[main_id]->find("toolbar"))
@@ -252,7 +223,11 @@ void App::initLayout()
}
};
LOG("initializing layout xml");
+#ifdef _WIN32
+ layout.load("C:\\Users\\omar\\Desktop\\new_engine\\data\\layout.xml");
+#else
layout.load("data/layout.xml");
+#endif
LOG("initializing layout completed");
}
@@ -344,41 +319,45 @@ void App::resize(float w, float h)
main->update(w , h, zoom);
}
-void App::mouse_down(int button, float x, float y)
+bool App::mouse_down(int button, float x, float y)
{
MouseEvent e;
e.m_type = button ? kEventType::MouseDownR : kEventType::MouseDownL;
e.m_pos = { x / zoom, y / zoom };
- layout[main_id]->on_event(&e);
+ auto ret = layout[main_id]->on_event(&e);
LOG("mouse click button%d pos %f %f\n", button, x, y);
- if (popup)
- {
- layout[main_id]->remove_child(popup);
- popup = nullptr;
- }
- if (button == 1)
- {
- popup = (NodePopupMenu*)layout[const_hash("popup-menu")]->m_children[0]->clone();
- popup->SetPositioning(YGPositionTypeAbsolute);
- popup->SetPosition(x / zoom, y / zoom);
- layout[main_id]->add_child(popup);
- }
+// if (popup)
+// {
+// layout[main_id]->remove_child(popup);
+// popup = nullptr;
+// }
+// if (button == 1)
+// {
+// popup = (NodePopupMenu*)layout[const_hash("popup-menu")]->m_children[0]->clone();
+// popup->SetPositioning(YGPositionTypeAbsolute);
+// popup->SetPosition(x / zoom, y / zoom);
+// layout[main_id]->add_child(popup);
+// }
layout[main_id]->update();
+ return ret == kEventResult::Consumed;
}
-void App::mouse_move(float x, float y)
+bool App::mouse_move(float x, float y)
{
MouseEvent e;
e.m_type = kEventType::MouseMove;
e.m_pos = { x / zoom, y / zoom };
+ kEventResult ret = kEventResult::Available;
if (auto* main = layout[main_id])
- main->on_event(&e);
+ ret = main->on_event(&e);
+ return ret == kEventResult::Consumed;
}
-void App::mouse_up(int button, float x, float y)
+bool App::mouse_up(int button, float x, float y)
{
MouseEvent e;
e.m_type = button ? kEventType::MouseUpR : kEventType::MouseUpL;
e.m_pos = { x / zoom, y / zoom };
- layout[main_id]->on_event(&e);
+ auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
+ return ret == kEventResult::Consumed;
}
diff --git a/engine/app.h b/engine/app.h
index ccc0a9a..75c503c 100644
--- a/engine/app.h
+++ b/engine/app.h
@@ -20,6 +20,7 @@ public:
NodePopupMenu* menu_edit = nullptr;
NodePopupMenu* menu_layers = nullptr;
NodeBorder* sidebar = nullptr;
+ NodePanelBrushes* brushes;
const uint16_t main_id = const_hash("main");
float width;
float height;
@@ -36,7 +37,7 @@ public:
void clear();
void update(float dt);
void resize(float w, float h);
- void mouse_down(int button, float x, float y);
- void mouse_move(float x, float y);
- void mouse_up(int button, float x, float y);
+ bool mouse_down(int button, float x, float y);
+ bool mouse_move(float x, float y);
+ bool mouse_up(int button, float x, float y);
};
diff --git a/engine/layout.cpp b/engine/layout.cpp
index a3826b5..3e52d8d 100644
--- a/engine/layout.cpp
+++ b/engine/layout.cpp
@@ -36,9 +36,12 @@ kEventResult Node::on_event(Event* e)
{
case kEventCategory::MouseEvent:
{
+ if (m_mouse_ignore)
+ break;
MouseEvent* me = static_cast(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:
@@ -55,7 +58,6 @@ kEventResult Node::on_event(Event* e)
e2.m_type = kEventType::MouseEnter;
handle_event(&e2);
}
- m_mouse_inside = inside;
if (inside || m_mouse_captured)
ret = handle_event(e);
if (inside_old == true && inside == false)
@@ -78,6 +80,21 @@ kEventResult Node::on_event(Event* e)
return ret;
}
+const Node* Node::init_template(const char* id)
+{
+ const auto& m_template = static_cast((*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);
@@ -86,16 +103,58 @@ void Node::add_child(Node* n)
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::remove_child(Node* n)
{
auto i = std::find_if(m_children.begin(), m_children.end(), [=](std::unique_ptr& ptr) { return ptr.get() == n; });
if (i != m_children.end())
{
- m_children.erase(i);
YGNodeRemoveChild(y_node, n->y_node);
+ m_children.erase(i);
}
}
+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(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;
@@ -358,71 +417,22 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
kWidget child_id = (kWidget)const_hash(x_child->Name());
switch (child_id)
{
- case kWidget::Border:
- {
- auto n = new NodeBorder();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- // case kWidget::Shape:
- // break;
- case kWidget::Image:
- {
- auto n = new NodeImage();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- case kWidget::Icon:
- {
- auto n = new NodeIcon();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- case kWidget::Text:
- {
- auto n = new NodeText();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- case kWidget::Button:
- {
- auto n = new NodeButton();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- case kWidget::ButtonCustom:
- {
- auto n = new NodeButtonCustom();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- case kWidget::SliderCursor:
- {
- auto n = new NodeSliderCursor();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- case kWidget::PopupMenu:
- {
- auto n = new NodePopupMenu();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
- case kWidget::Viewport:
- {
- auto n = new NodeViewport();
- add_child(n);
- n->load_internal(x_child);
- break;
- }
+#define CASE(W,C) case W: { auto n = new C(); add_child(n); n->load_internal(x_child); break; }
+ CASE(kWidget::Border, NodeBorder);
+ CASE(kWidget::Image, NodeImage);
+ CASE(kWidget::Icon, NodeIcon);
+ CASE(kWidget::Text, NodeText);
+ CASE(kWidget::Button , NodeButton);
+ CASE(kWidget::ButtonCustom, NodeButtonCustom);
+ CASE(kWidget::SliderCursor, NodeSliderCursor);
+ CASE(kWidget::Slider, NodeSlider);
+ CASE(kWidget::PopupMenu, NodePopupMenu);
+ CASE(kWidget::Viewport, NodeViewport);
+ CASE(kWidget::CheckBox, NodeCheckBox);
+ CASE(kWidget::Layer, NodeLayer);
+ CASE(kWidget::PanelLayers, NodePanelLayers);
+ CASE(kWidget::PanelBrushes, NodePanelBrushes);
+#undef CASE
case kWidget::Ref:
{
auto ids = x_child->Attribute("id");
diff --git a/engine/layout.h b/engine/layout.h
index fa2ab58..e968b17 100644
--- a/engine/layout.h
+++ b/engine/layout.h
@@ -40,6 +40,7 @@ enum class kAttribute : uint16_t
Positioning = const_hash("positioning"),
FloodEvents = const_hash("flood-events"),
Icon = const_hash("icon"),
+ Selected = const_hash("selected"),
};
enum class kWidget : uint16_t
@@ -52,9 +53,14 @@ enum class kWidget : uint16_t
Button = const_hash("button"),
ButtonCustom = const_hash("button-custom"),
SliderCursor = const_hash("slider-cursor"),
+ Slider = const_hash("slider"),
PopupMenu = const_hash("popup-menu"),
Viewport = const_hash("viewport"),
Ref = const_hash("ref"),
+ CheckBox = const_hash("checkbox"),
+ Layer = const_hash("layer"),
+ PanelLayers = const_hash("panel-layers"),
+ PanelBrushes = const_hash("panel-brushes"),
};
enum class kShapeType : uint16_t
@@ -136,6 +142,7 @@ public:
bool m_flood_events = false;
bool m_destroyed = false;
+ bool m_mouse_ignore = true;
float m_zoom = 1.f;
glm::vec2 m_scale{ 1.f };
glm::vec2 m_pos;
@@ -161,6 +168,7 @@ public:
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;
}
@@ -263,8 +271,13 @@ public:
virtual void create() { }
virtual void init() { }
virtual void loaded() { }
+ const Node* init_template(const char* id);
void add_child(Node* n);
+ void add_child(Node* n, int index);
void remove_child(Node* n);
+ void move_child(Node* n, int index);
+ void move_child_offset(Node* n, int offset);
+ int get_child_index(Node* n);
void mouse_capture() { root()->current_mouse_capture = this; m_mouse_captured = true; }
void mouse_release() { root()->current_mouse_capture = nullptr; m_mouse_captured = false; }
@@ -309,6 +322,7 @@ public:
glm::vec4 m_color{ 0, 0, 0, 1 };
glm::vec4 m_border_color{ 1, 1, 1, 1 };
float m_thinkness{ 0 };
+ NodeBorder() { m_mouse_ignore = false; }
static void static_init()
{
m_plane.create<1>(1, 1);
@@ -321,6 +335,7 @@ public:
n->m_color = m_color;
n->m_border_color = m_border_color;
n->m_thinkness = m_thinkness;
+ n->m_mouse_ignore = false;
}
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override
{
@@ -386,22 +401,25 @@ public:
std::string m_font;
glm::vec4 m_color{ 1, 1, 1, 1 };
int m_font_size;
+ kFont font_id;
virtual Node* clone_instantiate() const override { return new NodeText(); }
virtual void clone_copy(Node* dest) const override
{
Node::clone_copy(dest);
NodeText* n = static_cast(dest);
- n->m_text_mesh = m_text_mesh;
+ n->m_text_mesh.create();
+ n->m_text_mesh.update(font_id, m_text.c_str());
n->m_text = m_text;
n->m_font = m_font;
n->m_color = m_color;
n->m_font_size = m_font_size;
+ n->font_id = font_id;
}
virtual void create() override
{
char font[64];
sprintf(font, "%s-%d", m_font.c_str(), m_font_size);
- kFont font_id = (kFont)const_hash(font);
+ font_id = (kFont)const_hash(font);
m_text_mesh.create();
m_text_mesh.update(font_id, m_text.c_str());
SetSize(m_text_mesh.bb);
@@ -434,6 +452,12 @@ public:
break;
}
}
+ void set_text(const char* s)
+ {
+ m_text = s;
+ m_text_mesh.update(font_id, s);
+ SetSize(m_text_mesh.bb);
+ }
virtual void draw() override
{
using namespace ui;
@@ -543,7 +567,7 @@ public:
glm::vec4 color_normal{ .1, .1, .1, 1 };
glm::vec4 color_hover{ .2, .2, .2, 1 };
glm::vec4 color_down{ .3, .3, .3, 1 };
- std::function on_click;
+ std::function on_click;
virtual Node* clone_instantiate() const override { return new NodeButton(); }
virtual void clone_children(Node* dest) const override
{
@@ -562,6 +586,7 @@ public:
n->color_hover = color_hover;
n->color_down = color_down;
//n->on_click = on_click;
+ n->m_mouse_ignore = false;
}
virtual void init() override
{
@@ -576,17 +601,23 @@ public:
m_text->m_font_size = 11;
m_border->SetAlign(YGAlignCenter);
m_border->SetJustify(YGJustifyCenter);
+ m_border->m_mouse_ignore = false;
+ m_mouse_ignore = false;
}
virtual void create() override
{
m_border->create();
m_text->create();
+ m_border->m_mouse_ignore = false;
+ m_mouse_ignore = false;
}
virtual void loaded() override
{
m_border->m_thinkness = 1;
m_border->m_border_color = glm::vec4(0, 0, 0, 1);
m_border->m_color = color_normal;
+ m_border->m_mouse_ignore = false;
+ m_mouse_ignore = false;
}
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override
{
@@ -614,6 +645,7 @@ public:
}
virtual kEventResult handle_event(Event* e) override
{
+ Node::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseEnter:
@@ -628,7 +660,7 @@ public:
case kEventType::MouseUpL:
m_border->m_color = color_normal;
if (m_mouse_inside && on_click != nullptr)
- on_click();
+ on_click(this);
break;
default:
break;
@@ -652,7 +684,7 @@ public:
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 = [&] { destroy(); };
+ btnOk->on_click = [&](Node*) { destroy(); };
}
};
@@ -670,6 +702,20 @@ public:
}
virtual kEventResult handle_event(Event* e) override
{
+ switch (e->m_type)
+ {
+ case kEventType::MouseDownL:
+ if (!m_mouse_inside)
+ {
+ mouse_release();
+ destroy();
+ }
+ break;
+ case kEventType::MouseUpL:
+ break;
+ default:
+ break;
+ }
return kEventResult::Consumed;
}
};
@@ -677,10 +723,10 @@ public:
class NodeButtonCustom : public NodeBorder
{
public:
- glm::vec4 color_normal{ .1, .1, .1, 1 };
- glm::vec4 color_hover{ .2, .2, .2, 1 };
- glm::vec4 color_down{ .3, .3, .3, 1 };
- std::function on_click;
+ glm::vec4 color_normal{ .2, .2, .2, 1 };
+ glm::vec4 color_hover{ .3, .3, .3, 1 };
+ glm::vec4 color_down{ .4, .4, .4, 1 };
+ std::function on_click;
virtual Node* clone_instantiate() const override { return new NodeButtonCustom(); }
virtual void clone_copy(Node* dest) const override
{
@@ -689,6 +735,8 @@ public:
n->color_normal = color_normal;
n->color_hover = color_hover;
n->color_down = color_down;
+ n->m_mouse_ignore = false;
+ n->m_color = color_normal;
}
virtual void loaded() override
{
@@ -696,6 +744,7 @@ public:
//m_thinkness = 1;
//m_border_color = glm::vec4(0, 0, 0, 1);
m_color = color_normal;
+ m_mouse_ignore = false;
}
virtual kEventResult handle_event(Event* e) override
{
@@ -712,15 +761,27 @@ public:
m_color = color_down;
break;
case kEventType::MouseUpL:
- m_color = color_normal;
+ m_color = m_mouse_inside ? color_hover : color_normal;
if (m_mouse_inside && on_click != nullptr)
- on_click();
+ on_click(this);
break;
default:
break;
}
return kEventResult::Consumed;
}
+ virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override
+ {
+ NodeBorder::parse_attributes(ka, attr);
+ switch (ka)
+ {
+ case kAttribute::Color:
+ color_normal = m_color;
+ break;
+ default:
+ break;
+ }
+ }
};
class NodeSettings : public Node
@@ -738,7 +799,7 @@ public:
m_template = (*m_manager)[const_hash("settings")]->m_children[0]->clone();
add_child(m_template);
btnOk = m_template->find("btn-ok");
- btnOk->on_click = [&] { destroy(); };
+ btnOk->on_click = [&](Node*) { destroy(); };
}
virtual kEventResult handle_event(Event* e) override
{
@@ -906,6 +967,7 @@ public:
switch (e->m_type)
{
case kEventType::MouseDownL:
+ old_pos = GetPosition();
drag_start = ((MouseEvent*)e)->m_pos;
dragging = true;
mouse_capture();
@@ -919,7 +981,7 @@ public:
{
float pw = parent->GetWidth();
float w = GetWidth();
- drag_diff = ((MouseEvent*)e)->m_pos - drag_start;
+ drag_diff = old_pos + ((MouseEvent*)e)->m_pos - drag_start;
float x = glm::clamp(drag_diff.x, 0, pw - w);
SetPosition(x, 0);
}
@@ -930,3 +992,327 @@ public:
return kEventResult::Consumed;
}
};
+
+class NodeSlider : public NodeBorder
+{
+public:
+ NodeSliderCursor* m_cursor;
+ virtual Node* clone_instantiate() const override { return new NodeSlider(); }
+ virtual void init() override
+ {
+ const auto& m_template = (NodeBorder*)init_template("tpl-slider");
+ m_color = m_template->m_color;
+ m_border_color = m_template->m_border_color;
+ m_thinkness = m_thinkness;
+ m_cursor = find("cursor");
+ }
+};
+
+class NodeCheckBox : public Node
+{
+public:
+ NodeBorder* m_outer;
+ NodeBorder* m_inner;
+ bool checked = false;
+ virtual Node* clone_instantiate() const override { return new NodeCheckBox(); }
+ virtual void clone_children(Node* dest) const override
+ {
+ Node::clone_children(dest);
+ NodeCheckBox* n = static_cast(dest);
+ n->m_outer = (NodeBorder*)n->m_children[0].get();
+ n->m_inner = (NodeBorder*)n->m_outer->m_children[0].get();
+ n->m_mouse_ignore = false;
+ }
+ virtual void init() override
+ {
+ m_outer = new NodeBorder();
+ m_inner = new NodeBorder();
+ add_child(m_outer);
+ m_outer->add_child(m_inner);
+ m_outer->init();
+ m_outer->m_color = { .3, .3, .3, 1 };
+ m_outer->SetAlign(YGAlignCenter);
+ m_outer->SetJustify(YGJustifyCenter);
+ m_outer->SetPadding(5, 5, 5, 5);
+ m_outer->SetWidthP(100);
+ m_outer->SetHeightP(100);
+ m_outer->m_mouse_ignore = false;
+ m_inner->init();
+ m_inner->SetWidthP(100);
+ m_inner->SetHeightP(100);
+ m_inner->m_border_color = glm::vec4(.8, .8, .8, 1);
+ m_inner->m_thinkness = 1;
+ m_inner->m_color = glm::vec4(.8, .8, .8, 1);
+ m_mouse_ignore = false;
+ }
+ virtual void create() override
+ {
+ m_outer->create();
+ m_inner->create();
+ }
+ virtual kEventResult handle_event(Event* e) override
+ {
+ Node::handle_event(e);
+ switch (e->m_type)
+ {
+ case kEventType::MouseEnter:
+ break;
+ case kEventType::MouseLeave:
+ break;
+ case kEventType::MouseDownL:
+ break;
+ case kEventType::MouseUpL:
+ checked = !checked;
+ break;
+ default:
+ break;
+ }
+ return kEventResult::Consumed;
+ }
+ virtual void draw() override
+ {
+ m_inner->m_color = checked ? glm::vec4(.4, .4, .4, 1) : glm::vec4(.8, .8, .8, 1);
+ Node::draw();
+ }
+};
+
+class NodeLayer : public NodeBorder
+{
+public:
+ std::function on_selected;
+ bool m_selected = false;
+ glm::vec4 m_color_normal = glm::vec4(.4, .4, .4, 1);
+ glm::vec4 m_color_selected = glm::vec4(.3, .3, .3, 1);
+ glm::vec4 m_color_hover = glm::vec4(.5, .5, .5, 1);
+ std::string m_label_text;
+ NodeText* m_label;
+ NodeCheckBox* m_visibility;
+ virtual Node* clone_instantiate() const override { return new NodeLayer(); }
+ virtual void clone_children(Node* dest) const override
+ {
+ NodeBorder::clone_children(dest);
+ NodeLayer* n = static_cast(dest);
+ n->m_label = n->find("label");
+ n->m_visibility = n->find("cb");
+ }
+ virtual void clone_copy(Node* dest) const override
+ {
+ NodeBorder::clone_copy(dest);
+ NodeLayer* n = (NodeLayer*)dest;
+ n->m_selected = m_selected;
+ n->m_label_text = m_label_text;
+ }
+ virtual void init() override
+ {
+ const auto& m_template = (NodeBorder*)init_template("tpl-layer");
+ m_color = m_template->m_color;
+ m_border_color = m_template->m_border_color;
+ m_thinkness = m_template->m_thinkness;
+ m_label = find("label");
+ m_visibility = find("cb");
+ }
+ virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override
+ {
+ NodeBorder::parse_attributes(ka, attr);
+ switch (ka)
+ {
+ case kAttribute::Text:
+ m_label_text = attr->Value();
+ break;
+ case kAttribute::Selected:
+ m_selected = attr->BoolValue();
+ default:
+ break;
+ }
+ }
+ virtual void loaded() override
+ {
+ NodeBorder::loaded();
+ if (!m_label_text.empty())
+ m_label->set_text(m_label_text.c_str());
+ }
+ virtual kEventResult handle_event(Event* e) override
+ {
+ NodeBorder::handle_event(e);
+ switch (e->m_type)
+ {
+ case kEventType::MouseEnter:
+ break;
+ case kEventType::MouseLeave:
+ break;
+ case kEventType::MouseDownL:
+ m_selected = true;
+ if (on_selected)
+ on_selected(this);
+ break;
+ case kEventType::MouseUpL:
+ break;
+ default:
+ break;
+ }
+ return kEventResult::Consumed;
+ }
+ virtual void draw() override
+ {
+ auto c = m_selected ? m_color_selected : m_color_normal;
+ m_thinkness = m_selected ? 1 : 0;
+ m_color = m_mouse_inside ? m_color_hover : c;
+ NodeBorder::draw();
+ }
+ void set_name(const char* s)
+ {
+ m_label_text = s;
+ m_label->set_text(s);
+ }
+};
+
+class NodePanelLayers : public Node
+{
+ NodeButtonCustom* btn_add;
+ NodeButtonCustom* btn_remove;
+ NodeButtonCustom* btn_up;
+ NodeButtonCustom* btn_down;
+public:
+ NodeLayer* m_current_layer = nullptr;
+ std::vector m_layers;
+ NodeBorder* m_layers_container;
+ virtual Node* clone_instantiate() const override { return new NodePanelLayers(); }
+ virtual void init() override
+ {
+ init_template("tpl-panel-layers");
+ m_layers_container = find("layers-container");
+ for (int i = 0; i < 5; i++)
+ {
+ static char s[64];
+ sprintf(s, "Layer-%d", i);
+ add_layer(s);
+ }
+ m_current_layer = m_layers[0];
+ m_layers[0]->m_selected = true;
+ btn_add = find("btn-add");
+ btn_remove = find("btn-remove");
+ btn_up = find("btn-up");
+ btn_down = find("btn-down");
+ btn_add->on_click = [this](Node*) { add_layer("New Layer"); };
+ btn_remove->on_click = [this](Node*) {
+ if (m_layers.size() == 1)
+ return; // dont' delete the last layer
+ auto it = std::find(m_layers.begin(), m_layers.end(), m_current_layer);
+ auto i = m_layers_container->get_child_index(m_current_layer);
+ m_layers_container->remove_child(m_current_layer);
+ m_layers.erase(it);
+ i = std::min(i, m_layers.size() - 1);
+ m_current_layer = m_layers[i];
+ m_current_layer->m_selected = true;
+ };
+ btn_up->on_click = [this](Node*) { m_layers_container->move_child_offset(m_current_layer, -1); };
+ btn_down->on_click = [this](Node*) { m_layers_container->move_child_offset(m_current_layer, +1); };
+ }
+ void add_layer(const char* name)
+ {
+ NodeLayer* l = new NodeLayer;
+ m_layers_container->add_child(l);
+ l->init();
+ l->create();
+ l->loaded();
+ l->set_name(name);
+ l->on_selected = std::bind(&NodePanelLayers::handle_layer_selected, this, std::placeholders::_1);
+ m_layers.push_back(l);
+ }
+ void handle_layer_selected(NodeLayer* target)
+ {
+ if (m_current_layer)
+ m_current_layer->m_selected = false;
+ m_current_layer = target;
+ m_current_layer->m_selected = true;
+ }
+};
+
+class NodeButtonBrush : public NodeButtonCustom
+{
+public:
+ int m_brushID;
+ bool m_selected = false;
+ NodeImage* img;
+ virtual Node* clone_instantiate() const override { return new NodeButtonBrush(); }
+ virtual void init() override
+ {
+ init_template("tpl-brush-icon");
+ color_hover = glm::vec4(.7, .7, .7, 1);
+ color_normal = glm::vec4(.3, .3, .3, 1);
+ m_color = color_normal;
+ img = (NodeImage*)m_children[0].get();
+ }
+ void set_icon(const char* path)
+ {
+ img->m_path = path;
+ img->m_tex_id = const_hash(img->m_path.c_str());
+ img->create();
+ }
+ virtual void draw() override
+ {
+ m_color = m_selected ? glm::vec4(1, 0, 0, 1) : color_normal;
+ NodeButtonCustom::draw();
+ }
+};
+
+class NodePanelBrushes : public Node
+{
+ std::vector m_brushes;
+ NodeButtonBrush* m_current = nullptr;
+ Node* m_container;
+public:
+ std::function on_brush_changed;
+ virtual Node* clone_instantiate() const override { return new NodePanelLayers(); }
+ virtual void init() override
+ {
+ init_template("tpl-panel-brushes");
+ //m_layers_container = find("layers-container");
+ static auto icons = FindAllBrushes("data\\Icons\\");
+ if (m_container = find("brushes"))
+ {
+ int count = 0;
+ for (auto& i : icons)
+ {
+ std::string path = "data\\Icons\\" + i;
+ NodeButtonBrush* brush = new NodeButtonBrush;
+ m_container->add_child(brush);
+ brush->init();
+ brush->create();
+ brush->loaded();
+ brush->set_icon(path.c_str());
+ brush->m_brushID = count++;
+ m_brushes.push_back(brush);
+ brush->on_click = std::bind(&NodePanelBrushes::handle_click, this, std::placeholders::_1);
+ }
+ }
+ }
+ void handle_click(Node* target)
+ {
+ if (target == m_current)
+ return;
+ if (m_current)
+ m_current->m_selected = false;
+ m_current = (NodeButtonBrush*)target;
+ m_current->m_selected = true;
+ on_brush_changed(this, m_current->m_brushID);
+ }
+ std::vector FindAllBrushes(std::string folder)
+ {
+ std::vector names;
+ std::string search_path = folder + "*.png";
+ WIN32_FIND_DATAA fd;
+ HANDLE hFind = ::FindFirstFileA(search_path.c_str(), &fd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ // read all (real) files in current folder
+ // , delete '!' read other 2 default folder . and ..
+ if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ names.push_back(fd.cFileName);
+ }
+ } while (::FindNextFileA(hFind, &fd));
+ ::FindClose(hFind);
+ }
+ return names;
+ }
+};