From 7075fb4fb4fe7183a51569a76ad124e9179afd21 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 7 Feb 2020 11:13:20 +0700 Subject: [PATCH] basic layout system impl --- headers/enduro2d/high/components/layout.hpp | 42 ++--- .../scripts/emmy/components/layout.lua | 26 ++-- .../high_binds/components/layout_binds.cpp | 16 +- sources/enduro2d/high/components/layout.cpp | 52 +++---- .../enduro2d/high/systems/layout_system.cpp | 143 +++++++++++++++++- 5 files changed, 210 insertions(+), 69 deletions(-) diff --git a/headers/enduro2d/high/components/layout.hpp b/headers/enduro2d/high/components/layout.hpp index c165f384..4057ab63 100644 --- a/headers/enduro2d/high/components/layout.hpp +++ b/headers/enduro2d/high/components/layout.hpp @@ -13,36 +13,36 @@ namespace e2d class layout final { public: ENUM_HPP_CLASS_DECL(modes, u8, - (vertical) - (horizontal)) - - ENUM_HPP_CLASS_DECL(valigns, u8, - (top) - (center) - (bottom)) + (horizontal) + (vertical)) ENUM_HPP_CLASS_DECL(haligns, u8, (left) (center) (right)) + + ENUM_HPP_CLASS_DECL(valigns, u8, + (top) + (center) + (bottom)) public: layout() = default; layout& mode(modes value) noexcept; [[nodiscard]] modes mode() const noexcept; - layout& valign(valigns value) noexcept; - [[nodiscard]] valigns valign() const noexcept; - layout& halign(haligns value) noexcept; [[nodiscard]] haligns halign() const noexcept; + layout& valign(valigns value) noexcept; + [[nodiscard]] valigns valign() const noexcept; + layout& spacing(f32 value) noexcept; [[nodiscard]] f32 spacing() const noexcept; private: - modes mode_ = modes::vertical; - valigns valign_ = valigns::center; + modes mode_ = modes::horizontal; haligns halign_ = haligns::center; + valigns valign_ = valigns::center; f32 spacing_ = 0.f; }; @@ -123,15 +123,6 @@ namespace e2d return mode_; } - inline layout& layout::valign(valigns value) noexcept { - valign_ = value; - return *this; - } - - inline layout::valigns layout::valign() const noexcept { - return valign_; - } - inline layout& layout::halign(haligns value) noexcept { halign_ = value; return *this; @@ -141,6 +132,15 @@ namespace e2d return halign_; } + inline layout& layout::valign(valigns value) noexcept { + valign_ = value; + return *this; + } + + inline layout::valigns layout::valign() const noexcept { + return valign_; + } + inline layout& layout::spacing(f32 value) noexcept { spacing_ = value; return *this; diff --git a/samples/bin/library/scripts/emmy/components/layout.lua b/samples/bin/library/scripts/emmy/components/layout.lua index 29ba7be9..5e3e8ba5 100644 --- a/samples/bin/library/scripts/emmy/components/layout.lua +++ b/samples/bin/library/scripts/emmy/components/layout.lua @@ -13,29 +13,22 @@ local layout = { disabled = false, ---@type layout_modes - mode = layout.modes.vertical, - - ---@type layout_valigns - valign = layout.valigns.center, + mode = layout.modes.horizontal, ---@type layout_haligns halign = layout.haligns.center, + ---@type layout_valigns + valign = layout.valigns.center, + ---@type number spacing = 0.0 } ---@class layout_modes layout.modes = { - vertical = "vertical", - horizontal = "horizontal" -} - ----@class layout_valigns -layout.valigns = { - top = "top", - center = "center", - bottom = "bottom" + horizontal = "horizontal", + vertical = "vertical" } ---@class layout_haligns @@ -45,6 +38,13 @@ layout.haligns = { right = "right" } +---@class layout_valigns +layout.valigns = { + top = "top", + center = "center", + bottom = "bottom" +} + ---@overload fun(self: layout) ---@param self layout function layout.enable(self) end diff --git a/sources/enduro2d/high/bindings/high_binds/components/layout_binds.cpp b/sources/enduro2d/high/bindings/high_binds/components/layout_binds.cpp index 24e41a3a..5e5ce37c 100644 --- a/sources/enduro2d/high/bindings/high_binds/components/layout_binds.cpp +++ b/sources/enduro2d/high/bindings/high_binds/components/layout_binds.cpp @@ -58,14 +58,6 @@ namespace e2d::bindings::high c->mode(v); }), - "valign", sol::property( - [](const gcomponent& c) -> layout::valigns { - return c->valign(); - }, - [](gcomponent& c, layout::valigns v){ - c->valign(v); - }), - "halign", sol::property( [](const gcomponent& c) -> layout::haligns { return c->halign(); @@ -74,6 +66,14 @@ namespace e2d::bindings::high c->halign(v); }), + "valign", sol::property( + [](const gcomponent& c) -> layout::valigns { + return c->valign(); + }, + [](gcomponent& c, layout::valigns v){ + c->valign(v); + }), + "spacing", sol::property( [](const gcomponent& c) -> f32 { return c->spacing(); diff --git a/sources/enduro2d/high/components/layout.cpp b/sources/enduro2d/high/components/layout.cpp index 6d17b2e9..151b64c4 100644 --- a/sources/enduro2d/high/components/layout.cpp +++ b/sources/enduro2d/high/components/layout.cpp @@ -14,24 +14,16 @@ namespace e2d "additionalProperties" : false, "properties" : { "mode" : { "$ref": "#/definitions/modes" }, - "valign" : { "$ref": "#/definitions/valigns" }, "halign" : { "$ref": "#/definitions/haligns" }, + "valign" : { "$ref": "#/definitions/valigns" }, "spacing" : { "type" : "number" } }, "definitions" : { "modes" : { "type" : "string", "enum" : [ - "vertical", - "horizontal" - ] - }, - "valigns" : { - "type" : "string", - "enum" : [ - "top", - "center", - "bottom" + "horizontal", + "vertical" ] }, "haligns" : { @@ -41,6 +33,14 @@ namespace e2d "center", "right" ] + }, + "valigns" : { + "type" : "string", + "enum" : [ + "top", + "center", + "bottom" + ] } } })json"; @@ -58,15 +58,6 @@ namespace e2d component.mode(mode); } - if ( ctx.root.HasMember("valign") ) { - layout::valigns valign = component.valign(); - if ( !json_utils::try_parse_value(ctx.root["valign"], valign) ) { - the().error("LAYOUT: Incorrect formatting of 'valign' property"); - return false; - } - component.valign(valign); - } - if ( ctx.root.HasMember("halign") ) { layout::haligns halign = component.halign(); if ( !json_utils::try_parse_value(ctx.root["halign"], halign) ) { @@ -76,6 +67,15 @@ namespace e2d component.halign(halign); } + if ( ctx.root.HasMember("valign") ) { + layout::valigns valign = component.valign(); + if ( !json_utils::try_parse_value(ctx.root["valign"], valign) ) { + the().error("LAYOUT: Incorrect formatting of 'valign' property"); + return false; + } + component.valign(valign); + } + if ( ctx.root.HasMember("spacing") ) { f32 spacing = component.spacing(); if ( !json_utils::try_parse_value(ctx.root["spacing"], spacing) ) { @@ -144,18 +144,18 @@ namespace e2d c->mode(mode); } - if ( layout::valigns valign = c->valign(); - imgui_utils::show_enum_combo_box("valign", &valign) ) - { - c->valign(valign); - } - if ( layout::haligns halign = c->halign(); imgui_utils::show_enum_combo_box("halign", &halign) ) { c->halign(halign); } + if ( layout::valigns valign = c->valign(); + imgui_utils::show_enum_combo_box("valign", &valign) ) + { + c->valign(valign); + } + if ( f32 spacing = c->spacing(); ImGui::DragFloat("spacing", &spacing, 1.f) ) { diff --git a/sources/enduro2d/high/systems/layout_system.cpp b/sources/enduro2d/high/systems/layout_system.cpp index 0ec52ea2..11f67f48 100644 --- a/sources/enduro2d/high/systems/layout_system.cpp +++ b/sources/enduro2d/high/systems/layout_system.cpp @@ -6,8 +6,141 @@ #include +#include +#include #include +namespace +{ + using namespace e2d; + + bool is_layout_item_enabled(const const_gcomponent& item) noexcept { + const auto filter = !ecs::exists_any< + disabled, + disabled + >() && ecs::exists_all< + actor, + layout_item + >(); + + return item + || filter(item.owner().raw_entity()) + || item.owner().component()->node(); + } + + void update_layout_items(const layout& layout, const const_node_iptr& layout_node) { + static thread_local vector> items; + E2D_DEFER([](){ items.clear(); }); + + nodes::extract_components_from_children( + layout_node, + std::back_inserter(items)); + + // + // layout size + // + + v2f layout_size = v2f::zero(); + + for ( std::size_t i = 0; i < items.size(); ++i ) { + const gcomponent& item = items[i]; + if ( !is_layout_item_enabled(item) ) { + continue; + } + layout_size += item->size(); + if ( i > 0u ) { + layout_size += layout.spacing(); + } + } + + // + // cursor offsets + // + + v2f item_cursor = v2f::zero(); + v2f size_offset_mul = v2f::zero(); + v2f cursor_offset_mul = v2f::zero(); + + if ( layout.mode() == layout::modes::horizontal ) { + cursor_offset_mul = v2f::unit_x(); + + switch ( layout.halign() ) { + case layout::haligns::left: + item_cursor = 0.0f * layout_size.x * cursor_offset_mul; + break; + case layout::haligns::center: + item_cursor = -0.5f * layout_size.x * cursor_offset_mul; + break; + case layout::haligns::right: + item_cursor = -1.0f * layout_size.x * cursor_offset_mul; + break; + default: + E2D_ASSERT_MSG(false, "unexpected layout halign"); + } + + switch ( layout.valign() ) { + case layout::valigns::top: + size_offset_mul = -1.0f * v2f::unit_y(); + break; + case layout::valigns::center: + size_offset_mul = -0.5f * v2f::unit_y(); + break; + case layout::valigns::bottom: + size_offset_mul = 0.0f * v2f::unit_y(); + break; + default: + E2D_ASSERT_MSG(false, "unexpected layout valign"); + } + } else if ( layout.mode() == layout::modes::vertical ) { + cursor_offset_mul = v2f::unit_y(); + + switch ( layout.valign() ) { + case layout::valigns::top: + item_cursor = -1.0f * layout_size.y * cursor_offset_mul; + break; + case layout::valigns::center: + item_cursor = -0.5f * layout_size.y * cursor_offset_mul; + break; + case layout::valigns::bottom: + item_cursor = 0.0f * layout_size.y * cursor_offset_mul; + break; + default: + E2D_ASSERT_MSG(false, "unexpected layout valign"); + } + + switch ( layout.halign() ) { + case layout::haligns::left: + size_offset_mul = 0.0f * v2f::unit_x(); + break; + case layout::haligns::center: + size_offset_mul = -0.5f * v2f::unit_x(); + break; + case layout::haligns::right: + size_offset_mul = -1.0f * v2f::unit_x(); + break; + default: + E2D_ASSERT_MSG(false, "unexpected layout halign"); + } + } else { + E2D_ASSERT_MSG(false, "unexpected layout mode"); + } + + // + // placing + // + + for ( std::size_t i = 0; i < items.size(); ++i ) { + const gcomponent& item = items[i]; + if ( !is_layout_item_enabled(item) ) { + continue; + } + const node_iptr& item_node = item.owner().component()->node(); + item_node->translation(item_cursor + item->size() * size_offset_mul); + item_cursor += (item->size() + layout.spacing()) * cursor_offset_mul; + } + } +} + namespace e2d { // @@ -20,7 +153,15 @@ namespace e2d ~internal_state() noexcept = default; void process_update(ecs::registry& owner) { - E2D_UNUSED(owner); + owner.for_joined_components([]( + const ecs::const_entity&, + const layout& layout, + const actor& layout_actor) + { + update_layout_items(layout, layout_actor.node()); + }, !ecs::exists_any< + disabled, + disabled>()); } };