mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-15 00:11:55 +07:00
basic layout system impl
This commit is contained in:
@@ -13,36 +13,36 @@ namespace e2d
|
|||||||
class layout final {
|
class layout final {
|
||||||
public:
|
public:
|
||||||
ENUM_HPP_CLASS_DECL(modes, u8,
|
ENUM_HPP_CLASS_DECL(modes, u8,
|
||||||
(vertical)
|
(horizontal)
|
||||||
(horizontal))
|
(vertical))
|
||||||
|
|
||||||
ENUM_HPP_CLASS_DECL(valigns, u8,
|
|
||||||
(top)
|
|
||||||
(center)
|
|
||||||
(bottom))
|
|
||||||
|
|
||||||
ENUM_HPP_CLASS_DECL(haligns, u8,
|
ENUM_HPP_CLASS_DECL(haligns, u8,
|
||||||
(left)
|
(left)
|
||||||
(center)
|
(center)
|
||||||
(right))
|
(right))
|
||||||
|
|
||||||
|
ENUM_HPP_CLASS_DECL(valigns, u8,
|
||||||
|
(top)
|
||||||
|
(center)
|
||||||
|
(bottom))
|
||||||
public:
|
public:
|
||||||
layout() = default;
|
layout() = default;
|
||||||
|
|
||||||
layout& mode(modes value) noexcept;
|
layout& mode(modes value) noexcept;
|
||||||
[[nodiscard]] modes mode() const noexcept;
|
[[nodiscard]] modes mode() const noexcept;
|
||||||
|
|
||||||
layout& valign(valigns value) noexcept;
|
|
||||||
[[nodiscard]] valigns valign() const noexcept;
|
|
||||||
|
|
||||||
layout& halign(haligns value) noexcept;
|
layout& halign(haligns value) noexcept;
|
||||||
[[nodiscard]] haligns halign() const noexcept;
|
[[nodiscard]] haligns halign() const noexcept;
|
||||||
|
|
||||||
|
layout& valign(valigns value) noexcept;
|
||||||
|
[[nodiscard]] valigns valign() const noexcept;
|
||||||
|
|
||||||
layout& spacing(f32 value) noexcept;
|
layout& spacing(f32 value) noexcept;
|
||||||
[[nodiscard]] f32 spacing() const noexcept;
|
[[nodiscard]] f32 spacing() const noexcept;
|
||||||
private:
|
private:
|
||||||
modes mode_ = modes::vertical;
|
modes mode_ = modes::horizontal;
|
||||||
valigns valign_ = valigns::center;
|
|
||||||
haligns halign_ = haligns::center;
|
haligns halign_ = haligns::center;
|
||||||
|
valigns valign_ = valigns::center;
|
||||||
f32 spacing_ = 0.f;
|
f32 spacing_ = 0.f;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,15 +123,6 @@ namespace e2d
|
|||||||
return mode_;
|
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 {
|
inline layout& layout::halign(haligns value) noexcept {
|
||||||
halign_ = value;
|
halign_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
@@ -141,6 +132,15 @@ namespace e2d
|
|||||||
return halign_;
|
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 {
|
inline layout& layout::spacing(f32 value) noexcept {
|
||||||
spacing_ = value;
|
spacing_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -13,29 +13,22 @@ local layout = {
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
|
|
||||||
---@type layout_modes
|
---@type layout_modes
|
||||||
mode = layout.modes.vertical,
|
mode = layout.modes.horizontal,
|
||||||
|
|
||||||
---@type layout_valigns
|
|
||||||
valign = layout.valigns.center,
|
|
||||||
|
|
||||||
---@type layout_haligns
|
---@type layout_haligns
|
||||||
halign = layout.haligns.center,
|
halign = layout.haligns.center,
|
||||||
|
|
||||||
|
---@type layout_valigns
|
||||||
|
valign = layout.valigns.center,
|
||||||
|
|
||||||
---@type number
|
---@type number
|
||||||
spacing = 0.0
|
spacing = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
---@class layout_modes
|
---@class layout_modes
|
||||||
layout.modes = {
|
layout.modes = {
|
||||||
vertical = "vertical",
|
horizontal = "horizontal",
|
||||||
horizontal = "horizontal"
|
vertical = "vertical"
|
||||||
}
|
|
||||||
|
|
||||||
---@class layout_valigns
|
|
||||||
layout.valigns = {
|
|
||||||
top = "top",
|
|
||||||
center = "center",
|
|
||||||
bottom = "bottom"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---@class layout_haligns
|
---@class layout_haligns
|
||||||
@@ -45,6 +38,13 @@ layout.haligns = {
|
|||||||
right = "right"
|
right = "right"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---@class layout_valigns
|
||||||
|
layout.valigns = {
|
||||||
|
top = "top",
|
||||||
|
center = "center",
|
||||||
|
bottom = "bottom"
|
||||||
|
}
|
||||||
|
|
||||||
---@overload fun(self: layout)
|
---@overload fun(self: layout)
|
||||||
---@param self layout
|
---@param self layout
|
||||||
function layout.enable(self) end
|
function layout.enable(self) end
|
||||||
|
|||||||
@@ -58,14 +58,6 @@ namespace e2d::bindings::high
|
|||||||
c->mode(v);
|
c->mode(v);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"valign", sol::property(
|
|
||||||
[](const gcomponent<layout>& c) -> layout::valigns {
|
|
||||||
return c->valign();
|
|
||||||
},
|
|
||||||
[](gcomponent<layout>& c, layout::valigns v){
|
|
||||||
c->valign(v);
|
|
||||||
}),
|
|
||||||
|
|
||||||
"halign", sol::property(
|
"halign", sol::property(
|
||||||
[](const gcomponent<layout>& c) -> layout::haligns {
|
[](const gcomponent<layout>& c) -> layout::haligns {
|
||||||
return c->halign();
|
return c->halign();
|
||||||
@@ -74,6 +66,14 @@ namespace e2d::bindings::high
|
|||||||
c->halign(v);
|
c->halign(v);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
"valign", sol::property(
|
||||||
|
[](const gcomponent<layout>& c) -> layout::valigns {
|
||||||
|
return c->valign();
|
||||||
|
},
|
||||||
|
[](gcomponent<layout>& c, layout::valigns v){
|
||||||
|
c->valign(v);
|
||||||
|
}),
|
||||||
|
|
||||||
"spacing", sol::property(
|
"spacing", sol::property(
|
||||||
[](const gcomponent<layout>& c) -> f32 {
|
[](const gcomponent<layout>& c) -> f32 {
|
||||||
return c->spacing();
|
return c->spacing();
|
||||||
|
|||||||
@@ -14,24 +14,16 @@ namespace e2d
|
|||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
"properties" : {
|
"properties" : {
|
||||||
"mode" : { "$ref": "#/definitions/modes" },
|
"mode" : { "$ref": "#/definitions/modes" },
|
||||||
"valign" : { "$ref": "#/definitions/valigns" },
|
|
||||||
"halign" : { "$ref": "#/definitions/haligns" },
|
"halign" : { "$ref": "#/definitions/haligns" },
|
||||||
|
"valign" : { "$ref": "#/definitions/valigns" },
|
||||||
"spacing" : { "type" : "number" }
|
"spacing" : { "type" : "number" }
|
||||||
},
|
},
|
||||||
"definitions" : {
|
"definitions" : {
|
||||||
"modes" : {
|
"modes" : {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"enum" : [
|
"enum" : [
|
||||||
"vertical",
|
"horizontal",
|
||||||
"horizontal"
|
"vertical"
|
||||||
]
|
|
||||||
},
|
|
||||||
"valigns" : {
|
|
||||||
"type" : "string",
|
|
||||||
"enum" : [
|
|
||||||
"top",
|
|
||||||
"center",
|
|
||||||
"bottom"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"haligns" : {
|
"haligns" : {
|
||||||
@@ -41,6 +33,14 @@ namespace e2d
|
|||||||
"center",
|
"center",
|
||||||
"right"
|
"right"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"valigns" : {
|
||||||
|
"type" : "string",
|
||||||
|
"enum" : [
|
||||||
|
"top",
|
||||||
|
"center",
|
||||||
|
"bottom"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})json";
|
})json";
|
||||||
@@ -58,15 +58,6 @@ namespace e2d
|
|||||||
component.mode(mode);
|
component.mode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ctx.root.HasMember("valign") ) {
|
|
||||||
layout::valigns valign = component.valign();
|
|
||||||
if ( !json_utils::try_parse_value(ctx.root["valign"], valign) ) {
|
|
||||||
the<debug>().error("LAYOUT: Incorrect formatting of 'valign' property");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
component.valign(valign);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ctx.root.HasMember("halign") ) {
|
if ( ctx.root.HasMember("halign") ) {
|
||||||
layout::haligns halign = component.halign();
|
layout::haligns halign = component.halign();
|
||||||
if ( !json_utils::try_parse_value(ctx.root["halign"], halign) ) {
|
if ( !json_utils::try_parse_value(ctx.root["halign"], halign) ) {
|
||||||
@@ -76,6 +67,15 @@ namespace e2d
|
|||||||
component.halign(halign);
|
component.halign(halign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ctx.root.HasMember("valign") ) {
|
||||||
|
layout::valigns valign = component.valign();
|
||||||
|
if ( !json_utils::try_parse_value(ctx.root["valign"], valign) ) {
|
||||||
|
the<debug>().error("LAYOUT: Incorrect formatting of 'valign' property");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
component.valign(valign);
|
||||||
|
}
|
||||||
|
|
||||||
if ( ctx.root.HasMember("spacing") ) {
|
if ( ctx.root.HasMember("spacing") ) {
|
||||||
f32 spacing = component.spacing();
|
f32 spacing = component.spacing();
|
||||||
if ( !json_utils::try_parse_value(ctx.root["spacing"], spacing) ) {
|
if ( !json_utils::try_parse_value(ctx.root["spacing"], spacing) ) {
|
||||||
@@ -144,18 +144,18 @@ namespace e2d
|
|||||||
c->mode(mode);
|
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();
|
if ( layout::haligns halign = c->halign();
|
||||||
imgui_utils::show_enum_combo_box("halign", &halign) )
|
imgui_utils::show_enum_combo_box("halign", &halign) )
|
||||||
{
|
{
|
||||||
c->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();
|
if ( f32 spacing = c->spacing();
|
||||||
ImGui::DragFloat("spacing", &spacing, 1.f) )
|
ImGui::DragFloat("spacing", &spacing, 1.f) )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,8 +6,141 @@
|
|||||||
|
|
||||||
#include <enduro2d/high/systems/layout_system.hpp>
|
#include <enduro2d/high/systems/layout_system.hpp>
|
||||||
|
|
||||||
|
#include <enduro2d/high/components/actor.hpp>
|
||||||
|
#include <enduro2d/high/components/disabled.hpp>
|
||||||
#include <enduro2d/high/components/layout.hpp>
|
#include <enduro2d/high/components/layout.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using namespace e2d;
|
||||||
|
|
||||||
|
bool is_layout_item_enabled(const const_gcomponent<layout_item>& item) noexcept {
|
||||||
|
const auto filter = !ecs::exists_any<
|
||||||
|
disabled<actor>,
|
||||||
|
disabled<layout_item>
|
||||||
|
>() && ecs::exists_all<
|
||||||
|
actor,
|
||||||
|
layout_item
|
||||||
|
>();
|
||||||
|
|
||||||
|
return item
|
||||||
|
|| filter(item.owner().raw_entity())
|
||||||
|
|| item.owner().component<actor>()->node();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_layout_items(const layout& layout, const const_node_iptr& layout_node) {
|
||||||
|
static thread_local vector<gcomponent<layout_item>> items;
|
||||||
|
E2D_DEFER([](){ items.clear(); });
|
||||||
|
|
||||||
|
nodes::extract_components_from_children<layout_item>(
|
||||||
|
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<layout_item>& 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<layout_item>& item = items[i];
|
||||||
|
if ( !is_layout_item_enabled(item) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const node_iptr& item_node = item.owner().component<actor>()->node();
|
||||||
|
item_node->translation(item_cursor + item->size() * size_offset_mul);
|
||||||
|
item_cursor += (item->size() + layout.spacing()) * cursor_offset_mul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@@ -20,7 +153,15 @@ namespace e2d
|
|||||||
~internal_state() noexcept = default;
|
~internal_state() noexcept = default;
|
||||||
|
|
||||||
void process_update(ecs::registry& owner) {
|
void process_update(ecs::registry& owner) {
|
||||||
E2D_UNUSED(owner);
|
owner.for_joined_components<layout, actor>([](
|
||||||
|
const ecs::const_entity&,
|
||||||
|
const layout& layout,
|
||||||
|
const actor& layout_actor)
|
||||||
|
{
|
||||||
|
update_layout_items(layout, layout_actor.node());
|
||||||
|
}, !ecs::exists_any<
|
||||||
|
disabled<actor>,
|
||||||
|
disabled<layout>>());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user