From 03a826697203abc29878abfe359e3239e9fd94dd Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 19 Mar 2017 23:51:45 +0000 Subject: [PATCH] added checkbox, slider, layer panel, brushes panel --- data/layout.xml | 165 ++++++++++++------- engine/app.cpp | 99 +++++------ engine/app.h | 7 +- engine/layout.cpp | 144 ++++++++-------- engine/layout.h | 412 ++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 624 insertions(+), 203 deletions(-) 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 @@ + @@ -100,9 +175,22 @@ - + + + + + + + + + + + + + + @@ -125,6 +213,7 @@ + @@ -142,6 +231,7 @@ + @@ -163,25 +253,12 @@ - - - - - - - - - - - - - - + - + - + @@ -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; + } +};