Merge pull request #120 from enduro2d/feature/widget_size

Feature/widget size
This commit is contained in:
2020-04-16 02:41:18 +07:00
committed by GitHub
35 changed files with 1251 additions and 645 deletions

View File

@@ -45,6 +45,7 @@
#include "components/spine_player.hpp" #include "components/spine_player.hpp"
#include "components/sprite_renderer.hpp" #include "components/sprite_renderer.hpp"
#include "components/touchable.hpp" #include "components/touchable.hpp"
#include "components/widget.hpp"
#include "resources/atlas.hpp" #include "resources/atlas.hpp"
#include "resources/flipbook.hpp" #include "resources/flipbook.hpp"

View File

@@ -65,6 +65,7 @@ namespace e2d
class spine_player; class spine_player;
class sprite_renderer; class sprite_renderer;
class touchable; class touchable;
class widget;
class atlas; class atlas;
class flipbook; class flipbook;

View File

@@ -14,23 +14,31 @@ namespace e2d
public: public:
class dirty final {}; class dirty final {};
public: public:
ENUM_HPP_CLASS_DECL(haligns, u8,
(left)
(center)
(right)
(space_around)
(space_evenly)
(space_between))
ENUM_HPP_CLASS_DECL(valigns, u8,
(top)
(center)
(bottom)
(space_around)
(space_evenly)
(space_between))
ENUM_HPP_CLASS_DECL(directions, u8, ENUM_HPP_CLASS_DECL(directions, u8,
(ltr)
(rtl))
ENUM_HPP_CLASS_DECL(align_modes, u8,
(flex_start)
(center)
(flex_end)
(space_between)
(space_around))
ENUM_HPP_CLASS_DECL(justify_modes, u8,
(flex_start)
(center)
(flex_end)
(space_between)
(space_around)
(space_evenly))
ENUM_HPP_CLASS_DECL(flex_wraps, u8,
(no_wrap)
(wrap)
(wrap_reversed))
ENUM_HPP_CLASS_DECL(flex_directions, u8,
(row) (row)
(row_reversed) (row_reversed)
(column) (column)
@@ -38,37 +46,38 @@ namespace e2d
public: public:
layout() = default; layout() = default;
layout& halign(haligns value) noexcept;
[[nodiscard]] haligns halign() const noexcept;
layout& valign(valigns value) noexcept;
[[nodiscard]] valigns valign() const noexcept;
layout& direction(directions value) noexcept; layout& direction(directions value) noexcept;
[[nodiscard]] directions direction() const noexcept; [[nodiscard]] directions direction() const noexcept;
public:
layout& size(const v2f& value) noexcept;
[[nodiscard]] const v2f& size() const noexcept;
layout& margin(const v2f& value) noexcept; layout& align_items(align_modes value) noexcept;
[[nodiscard]] const v2f& margin() const noexcept; [[nodiscard]] align_modes align_items() const noexcept;
layout& padding(const v2f& value) noexcept; layout& align_content(align_modes value) noexcept;
[[nodiscard]] const v2f& padding() const noexcept; [[nodiscard]] align_modes align_content() const noexcept;
layout& justify_content(justify_modes value) noexcept;
[[nodiscard]] justify_modes justify_content() const noexcept;
layout& flex_wrap(flex_wraps value) noexcept;
[[nodiscard]] flex_wraps flex_wrap() const noexcept;
layout& flex_direction(flex_directions value) noexcept;
[[nodiscard]] flex_directions flex_direction() const noexcept;
private: private:
haligns halign_ = haligns::center; directions direction_ = directions::ltr;
valigns valign_ = valigns::center; align_modes align_items_ = align_modes::flex_start;
directions direction_ = directions::row; align_modes align_content_ = align_modes::flex_start;
private: justify_modes justify_content_ = justify_modes::flex_start;
v2f size_ = v2f::zero(); flex_wraps flex_wrap_ = flex_wraps::no_wrap;
v2f margin_ = v2f::zero(); flex_directions flex_direction_ = flex_directions::row;
v2f padding_ = v2f::zero();
}; };
} }
ENUM_HPP_REGISTER_TRAITS(e2d::layout::haligns)
ENUM_HPP_REGISTER_TRAITS(e2d::layout::valigns)
ENUM_HPP_REGISTER_TRAITS(e2d::layout::directions) ENUM_HPP_REGISTER_TRAITS(e2d::layout::directions)
ENUM_HPP_REGISTER_TRAITS(e2d::layout::align_modes)
ENUM_HPP_REGISTER_TRAITS(e2d::layout::justify_modes)
ENUM_HPP_REGISTER_TRAITS(e2d::layout::flex_wraps)
ENUM_HPP_REGISTER_TRAITS(e2d::layout::flex_directions)
namespace e2d namespace e2d
{ {
@@ -109,30 +118,11 @@ namespace e2d
static const char* title; static const char* title;
void operator()(gcomponent<layout>& c) const; void operator()(gcomponent<layout>& c) const;
void operator()(gcomponent<layout>& c, gizmos_context& ctx) const;
}; };
} }
namespace e2d namespace e2d
{ {
inline layout& layout::halign(haligns value) noexcept {
halign_ = value;
return *this;
}
inline layout::haligns layout::halign() const noexcept {
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::direction(directions value) noexcept { inline layout& layout::direction(directions value) noexcept {
direction_ = value; direction_ = value;
return *this; return *this;
@@ -142,31 +132,49 @@ namespace e2d
return direction_; return direction_;
} }
inline layout& layout::size(const v2f& value) noexcept { inline layout& layout::align_items(align_modes value) noexcept {
size_ = value; align_items_ = value;
return *this; return *this;
} }
inline const v2f& layout::size() const noexcept { inline layout::align_modes layout::align_items() const noexcept {
return size_; return align_items_;
} }
inline layout& layout::margin(const v2f& value) noexcept { inline layout& layout::align_content(align_modes value) noexcept {
margin_ = value; align_content_ = value;
return *this; return *this;
} }
inline const v2f& layout::margin() const noexcept { inline layout::align_modes layout::align_content() const noexcept {
return margin_; return align_content_;
} }
inline layout& layout::padding(const v2f& value) noexcept { inline layout& layout::justify_content(justify_modes value) noexcept {
padding_ = value; justify_content_ = value;
return *this; return *this;
} }
inline const v2f& layout::padding() const noexcept { inline layout::justify_modes layout::justify_content() const noexcept {
return padding_; return justify_content_;
}
inline layout& layout::flex_wrap(flex_wraps value) noexcept {
flex_wrap_ = value;
return *this;
}
inline layout::flex_wraps layout::flex_wrap() const noexcept {
return flex_wrap_;
}
inline layout& layout::flex_direction(flex_directions value) noexcept {
flex_direction_ = value;
return *this;
}
inline layout::flex_directions layout::flex_direction() const noexcept {
return flex_direction_;
} }
} }
@@ -176,13 +184,12 @@ namespace e2d::layouts
gcomponent<layout> unmark_dirty(gcomponent<layout> self); gcomponent<layout> unmark_dirty(gcomponent<layout> self);
bool is_dirty(const const_gcomponent<layout>& self) noexcept; bool is_dirty(const const_gcomponent<layout>& self) noexcept;
gcomponent<layout> change_halign(gcomponent<layout> self, layout::haligns value);
gcomponent<layout> change_valign(gcomponent<layout> self, layout::valigns value);
gcomponent<layout> change_direction(gcomponent<layout> self, layout::directions value); gcomponent<layout> change_direction(gcomponent<layout> self, layout::directions value);
gcomponent<layout> change_align_items(gcomponent<layout> self, layout::align_modes value);
gcomponent<layout> change_size(gcomponent<layout> self, const v2f& value); gcomponent<layout> change_align_content(gcomponent<layout> self, layout::align_modes value);
gcomponent<layout> change_margin(gcomponent<layout> self, const v2f& value); gcomponent<layout> change_justify_content(gcomponent<layout> self, layout::justify_modes value);
gcomponent<layout> change_padding(gcomponent<layout> self, const v2f& value); gcomponent<layout> change_flex_wrap(gcomponent<layout> self, layout::flex_wraps value);
gcomponent<layout> change_flex_direction(gcomponent<layout> self, layout::flex_directions value);
gcomponent<layout> find_parent_layout(const_gcomponent<layout> self) noexcept; gcomponent<layout> find_parent_layout(const_gcomponent<layout> self) noexcept;
} }

View File

@@ -0,0 +1,118 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "_components.hpp"
namespace e2d
{
class widget final {
public:
class dirty final {};
public:
widget() = default;
widget& size(const v2f& value) noexcept;
[[nodiscard]] const v2f& size() const noexcept;
widget& margin(const v2f& value) noexcept;
[[nodiscard]] const v2f& margin() const noexcept;
widget& padding(const v2f& value) noexcept;
[[nodiscard]] const v2f& padding() const noexcept;
private:
v2f size_ = v2f::zero();
v2f margin_ = v2f::zero();
v2f padding_ = v2f::zero();
};
}
namespace e2d
{
template <>
class factory_loader<widget> final : factory_loader<> {
public:
static const char* schema_source;
bool operator()(
widget& component,
const fill_context& ctx) const;
bool operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const;
};
template <>
class factory_loader<widget::dirty> final : factory_loader<> {
public:
static const char* schema_source;
bool operator()(
widget::dirty& component,
const fill_context& ctx) const;
bool operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const;
};
}
namespace e2d
{
template <>
class component_inspector<widget> final : component_inspector<> {
public:
static const char* title;
void operator()(gcomponent<widget>& c) const;
void operator()(gcomponent<widget>& c, gizmos_context& ctx) const;
};
}
namespace e2d
{
inline widget& widget::size(const v2f& value) noexcept {
size_ = value;
return *this;
}
inline const v2f& widget::size() const noexcept {
return size_;
}
inline widget& widget::margin(const v2f& value) noexcept {
margin_ = value;
return *this;
}
inline const v2f& widget::margin() const noexcept {
return margin_;
}
inline widget& widget::padding(const v2f& value) noexcept {
padding_ = value;
return *this;
}
inline const v2f& widget::padding() const noexcept {
return padding_;
}
}
namespace e2d::widgets
{
gcomponent<widget> mark_dirty(gcomponent<widget> self);
gcomponent<widget> unmark_dirty(gcomponent<widget> self);
bool is_dirty(const const_gcomponent<widget>& self) noexcept;
gcomponent<widget> change_size(gcomponent<widget> self, const v2f& value);
gcomponent<widget> change_margin(gcomponent<widget> self, const v2f& value);
gcomponent<widget> change_padding(gcomponent<widget> self, const v2f& value);
gcomponent<layout> find_parent_layout(const_gcomponent<widget> self) noexcept;
}

View File

@@ -94,6 +94,12 @@ namespace e2d
gobject owner() const noexcept; gobject owner() const noexcept;
explicit operator bool() const noexcept; explicit operator bool() const noexcept;
template < typename U >
gcomponent<U> component() noexcept;
template < typename U >
const_gcomponent<U> component() const noexcept;
private: private:
gobject owner_; gobject owner_;
}; };
@@ -116,6 +122,9 @@ namespace e2d
gobject owner() const noexcept; gobject owner() const noexcept;
explicit operator bool() const noexcept; explicit operator bool() const noexcept;
template < typename U >
const_gcomponent<U> component() const noexcept;
private: private:
gobject owner_; gobject owner_;
}; };
@@ -239,6 +248,18 @@ namespace e2d
gcomponent<T>::operator bool() const noexcept { gcomponent<T>::operator bool() const noexcept {
return exists(); return exists();
} }
template < typename T >
template < typename U >
gcomponent<U> gcomponent<T>::component() noexcept {
return owner_.component<U>();
}
template < typename T >
template < typename U >
const_gcomponent<U> gcomponent<T>::component() const noexcept {
return owner_.component<U>();
}
} }
namespace e2d namespace e2d
@@ -294,4 +315,10 @@ namespace e2d
const_gcomponent<T>::operator bool() const noexcept { const_gcomponent<T>::operator bool() const noexcept {
return exists(); return exists();
} }
template < typename T >
template < typename U >
const_gcomponent<U> const_gcomponent<T>::component() const noexcept {
return owner_.component<U>();
}
} }

View File

@@ -0,0 +1,26 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "_systems.hpp"
namespace e2d
{
class widget_system final
: public ecs::system<ecs::after<systems::update_event>> {
public:
widget_system();
~widget_system() noexcept final;
void process(
ecs::registry& owner,
const ecs::after<systems::update_event>& trigger) override;
private:
class internal_state;
std::unique_ptr<internal_state> state_;
};
}

View File

@@ -24,12 +24,15 @@ namespace e2d
const ecs::registry& registry() const noexcept; const ecs::registry& registry() const noexcept;
gobject instantiate(); gobject instantiate();
gobject instantiate(const prefab& prefab); gobject instantiate(const t2f& transform);
gobject instantiate(const node_iptr& parent); gobject instantiate(const node_iptr& parent);
gobject instantiate(const prefab& prefab, const node_iptr& parent);
gobject instantiate(const node_iptr& parent, const t2f& transform); gobject instantiate(const node_iptr& parent, const t2f& transform);
gobject instantiate(const prefab& prefab);
gobject instantiate(const prefab& prefab, const t2f& transform);
gobject instantiate(const prefab& prefab, const node_iptr& parent);
gobject instantiate(const prefab& prefab, const node_iptr& parent, const t2f& transform); gobject instantiate(const prefab& prefab, const node_iptr& parent, const t2f& transform);
void destroy_instance(gobject inst) noexcept; void destroy_instance(gobject inst) noexcept;

View File

@@ -1,4 +1,5 @@
{ {
"prototype" : "widget_prefab.json",
"components" : { "components" : {
"named" : { "named" : {
"name" : "layout" "name" : "layout"

View File

@@ -0,0 +1,9 @@
{
"components" : {
"named" : {
"name" : "widget"
},
"widget" : {},
"widget.dirty" : {}
}
}

View File

@@ -15,14 +15,16 @@
"prototype" : "../prefabs/layout_prefab.json", "prototype" : "../prefabs/layout_prefab.json",
"components" : { "components" : {
"layout" : { "layout" : {
"size" : [400,200], "justify_content" : "space_evenly"
"halign" : "space_evenly" },
"widget" : {
"size" : [400,200]
} }
}, },
"children" : [{ "children" : [{
"prototype" : "../prefabs/layout_prefab.json", "prototype" : "../prefabs/widget_prefab.json",
"components" : { "components" : {
"layout" : { "widget" : {
"size" : [66,113] "size" : [66,113]
} }
}, },
@@ -35,9 +37,9 @@
} }
}] }]
},{ },{
"prototype" : "../prefabs/layout_prefab.json", "prototype" : "../prefabs/widget_prefab.json",
"components" : { "components" : {
"layout" : { "widget" : {
"size" : [66,113] "size" : [66,113]
} }
}, },
@@ -50,9 +52,9 @@
} }
}] }]
},{ },{
"prototype" : "../prefabs/layout_prefab.json", "prototype" : "../prefabs/widget_prefab.json",
"components" : { "components" : {
"layout" : { "widget" : {
"size" : [66,113] "size" : [66,113]
} }
}, },

View File

@@ -9,47 +9,59 @@ local layout = {
---@type boolean ---@type boolean
dirty = false, dirty = false,
---@type layout_haligns
halign = layout.haligns.center,
---@type layout_valigns
valign = layout.valigns.center,
---@type layout_directions ---@type layout_directions
direction = layout.directions.row, direction = layout.directions.ltr,
---@type v2f ---@type layout_align_modes
size = v2f.zero(), align_items = layout.align_modes.flex_start,
---@type v2f ---@type layout_align_modes
margin = v2f.zero(), align_conten = layout.align_modes.flex_start,
---@type v2f ---@type layout_justify_modes
padding = v2f.zero() justify_content = layout.justify_modes.flex_start,
}
---@class layout_haligns ---@type layout_flex_wraps
layout.haligns = { flex_wrap = layout.flex_wraps.no_wrap,
left = "left",
center = "center",
right = "right",
space_around = "space_around",
space_evenly = "space_evenly",
space_between = "space_between"
}
---@class layout_valigns ---@type layout_flex_directions
layout.valigns = { flex_direction = layout.flex_directions.row
top = "top",
center = "center",
bottom = "bottom",
space_around = "space_around",
space_evenly = "space_evenly",
space_between = "space_between"
} }
---@class layout_directions ---@class layout_directions
layout.directions = { layout.directions = {
ltr = "ltr",
rtl = "rtl"
}
---@class layout_align_modes
layout.align_modes = {
flex_start = "flex_start",
center = "center",
flex_end = "flex_end",
space_between = "space_between",
space_around = "space_around"
}
---@class layout_justify_modes
layout.justify_modes = {
flex_start = "flex_start",
center = "center",
flex_end = "flex_end",
space_between = "space_between",
space_around = "space_around",
space_evenly = "space_evenly"
}
---@class layout_flex_wraps
layout.flex_wraps = {
no_wrap = "no_wrap",
wrap = "wrap",
wrap_reversed = "wrap_reversed"
}
---@class layout_flex_directions
layout.flex_directions = {
row = "row", row = "row",
row_reversed = "row_reversed", row_reversed = "row_reversed",
column = "column", column = "column",

View File

@@ -0,0 +1,31 @@
---@class widget
local widget = {
---@type boolean
enabled = true,
---@type boolean
disabled = false,
---@type boolean
dirty = false,
---@type v2f
size = v2f.zero(),
---@type v2f
margin = v2f.zero(),
---@type v2f
padding = v2f.zero()
}
---@overload fun(self: widget)
---@param self widget
function widget.enable(self) end
---@overload fun(self: widget)
---@param self widget
function widget.disable(self) end
---@type widget
_G.widget = _G.widget or widget

View File

@@ -52,7 +52,10 @@ local gobject = {
sprite_renderer = nil, sprite_renderer = nil,
---@type touchable ---@type touchable
touchable = nil touchable = nil,
---@type widget
widget = nil
} }
---@param self gobject ---@param self gobject

View File

@@ -2,7 +2,12 @@
local world = { local world = {
} }
---@overload fun(): gobject
---@overload fun(transform: t2f): gobject
---@overload fun(parent: node): gobject
---@overload fun(parent: node, transform: t2f): gobject
---@overload fun(prefab: prefab): gobject ---@overload fun(prefab: prefab): gobject
---@overload fun(prefab: prefab, transform: t2f): gobject
---@overload fun(prefab: prefab, parent: node): gobject ---@overload fun(prefab: prefab, parent: node): gobject
---@overload fun(prefab: prefab, parent: node, transform: t2f): gobject ---@overload fun(prefab: prefab, parent: node, transform: t2f): gobject
---@return gobject ---@return gobject

View File

@@ -32,6 +32,7 @@ namespace e2d::bindings::high
void bind_spine_player(sol::state& l); void bind_spine_player(sol::state& l);
void bind_sprite_renderer(sol::state& l); void bind_sprite_renderer(sol::state& l);
void bind_touchable(sol::state& l); void bind_touchable(sol::state& l);
void bind_widget(sol::state& l);
} }
namespace e2d::bindings namespace e2d::bindings
@@ -59,5 +60,6 @@ namespace e2d::bindings
high::bind_spine_player(l); high::bind_spine_player(l);
high::bind_sprite_renderer(l); high::bind_sprite_renderer(l);
high::bind_touchable(l); high::bind_touchable(l);
high::bind_widget(l);
} }
} }

View File

@@ -17,35 +17,35 @@ namespace e2d::bindings::high
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<behaviour>& c){ "enable", [](gcomponent<behaviour>& c){
c.owner().component<disabled<behaviour>>().remove(); c.component<disabled<behaviour>>().remove();
}, },
"disable", [](gcomponent<behaviour>& c){ "disable", [](gcomponent<behaviour>& c){
c.owner().component<disabled<behaviour>>().ensure(); c.component<disabled<behaviour>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<behaviour>& c) -> bool { [](const gcomponent<behaviour>& c) -> bool {
return !c.owner().component<disabled<behaviour>>().exists(); return !c.component<disabled<behaviour>>().exists();
}, },
[](gcomponent<behaviour>& c, bool yesno){ [](gcomponent<behaviour>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<behaviour>>().remove(); c.component<disabled<behaviour>>().remove();
} else { } else {
c.owner().component<disabled<behaviour>>().ensure(); c.component<disabled<behaviour>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<behaviour>& c) -> bool { [](const gcomponent<behaviour>& c) -> bool {
return c.owner().component<disabled<behaviour>>().exists(); return c.component<disabled<behaviour>>().exists();
}, },
[](gcomponent<behaviour>& c, bool yesno){ [](gcomponent<behaviour>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<behaviour>>().ensure(); c.component<disabled<behaviour>>().ensure();
} else { } else {
c.owner().component<disabled<behaviour>>().remove(); c.component<disabled<behaviour>>().remove();
} }
} }
), ),

View File

@@ -17,61 +17,61 @@ namespace e2d::bindings::high
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<camera>& c){ "enable", [](gcomponent<camera>& c){
c.owner().component<disabled<camera>>().remove(); c.component<disabled<camera>>().remove();
}, },
"disable", [](gcomponent<camera>& c){ "disable", [](gcomponent<camera>& c){
c.owner().component<disabled<camera>>().ensure(); c.component<disabled<camera>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<camera>& c) -> bool { [](const gcomponent<camera>& c) -> bool {
return !c.owner().component<disabled<camera>>().exists(); return !c.component<disabled<camera>>().exists();
}, },
[](gcomponent<camera>& c, bool yesno){ [](gcomponent<camera>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<camera>>().remove(); c.component<disabled<camera>>().remove();
} else { } else {
c.owner().component<disabled<camera>>().ensure(); c.component<disabled<camera>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<camera>& c) -> bool { [](const gcomponent<camera>& c) -> bool {
return c.owner().component<disabled<camera>>().exists(); return c.component<disabled<camera>>().exists();
}, },
[](gcomponent<camera>& c, bool yesno){ [](gcomponent<camera>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<camera>>().ensure(); c.component<disabled<camera>>().ensure();
} else { } else {
c.owner().component<disabled<camera>>().remove(); c.component<disabled<camera>>().remove();
} }
} }
), ),
"input", sol::property( "input", sol::property(
[](const gcomponent<camera>& c) -> bool { [](const gcomponent<camera>& c) -> bool {
return c.owner().component<camera::input>().exists(); return c.component<camera::input>().exists();
}, },
[](gcomponent<camera>& c, bool yesno){ [](gcomponent<camera>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<camera::input>().ensure(); c.component<camera::input>().ensure();
} else { } else {
c.owner().component<camera::input>().remove(); c.component<camera::input>().remove();
} }
} }
), ),
"gizmos", sol::property( "gizmos", sol::property(
[](const gcomponent<camera>& c) -> bool { [](const gcomponent<camera>& c) -> bool {
return c.owner().component<camera::gizmos>().exists(); return c.component<camera::gizmos>().exists();
}, },
[](gcomponent<camera>& c, bool yesno){ [](gcomponent<camera>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<camera::gizmos>().ensure(); c.component<camera::gizmos>().ensure();
} else { } else {
c.owner().component<camera::gizmos>().remove(); c.component<camera::gizmos>().remove();
} }
} }
), ),

View File

@@ -19,35 +19,35 @@ namespace
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<rect_collider>& c){ "enable", [](gcomponent<rect_collider>& c){
c.owner().component<disabled<rect_collider>>().remove(); c.component<disabled<rect_collider>>().remove();
}, },
"disable", [](gcomponent<rect_collider>& c){ "disable", [](gcomponent<rect_collider>& c){
c.owner().component<disabled<rect_collider>>().ensure(); c.component<disabled<rect_collider>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<rect_collider>& c) -> bool { [](const gcomponent<rect_collider>& c) -> bool {
return !c.owner().component<disabled<rect_collider>>().exists(); return !c.component<disabled<rect_collider>>().exists();
}, },
[](gcomponent<rect_collider>& c, bool yesno){ [](gcomponent<rect_collider>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<rect_collider>>().remove(); c.component<disabled<rect_collider>>().remove();
} else { } else {
c.owner().component<disabled<rect_collider>>().ensure(); c.component<disabled<rect_collider>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<rect_collider>& c) -> bool { [](const gcomponent<rect_collider>& c) -> bool {
return c.owner().component<disabled<rect_collider>>().exists(); return c.component<disabled<rect_collider>>().exists();
}, },
[](gcomponent<rect_collider>& c, bool yesno){ [](gcomponent<rect_collider>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<rect_collider>>().ensure(); c.component<disabled<rect_collider>>().ensure();
} else { } else {
c.owner().component<disabled<rect_collider>>().remove(); c.component<disabled<rect_collider>>().remove();
} }
} }
), ),
@@ -75,35 +75,35 @@ namespace
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<circle_collider>& c){ "enable", [](gcomponent<circle_collider>& c){
c.owner().component<disabled<circle_collider>>().remove(); c.component<disabled<circle_collider>>().remove();
}, },
"disable", [](gcomponent<circle_collider>& c){ "disable", [](gcomponent<circle_collider>& c){
c.owner().component<disabled<circle_collider>>().ensure(); c.component<disabled<circle_collider>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<circle_collider>& c) -> bool { [](const gcomponent<circle_collider>& c) -> bool {
return !c.owner().component<disabled<circle_collider>>().exists(); return !c.component<disabled<circle_collider>>().exists();
}, },
[](gcomponent<circle_collider>& c, bool yesno){ [](gcomponent<circle_collider>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<circle_collider>>().remove(); c.component<disabled<circle_collider>>().remove();
} else { } else {
c.owner().component<disabled<circle_collider>>().ensure(); c.component<disabled<circle_collider>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<circle_collider>& c) -> bool { [](const gcomponent<circle_collider>& c) -> bool {
return c.owner().component<disabled<circle_collider>>().exists(); return c.component<disabled<circle_collider>>().exists();
}, },
[](gcomponent<circle_collider>& c, bool yesno){ [](gcomponent<circle_collider>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<circle_collider>>().ensure(); c.component<disabled<circle_collider>>().ensure();
} else { } else {
c.owner().component<disabled<circle_collider>>().remove(); c.component<disabled<circle_collider>>().remove();
} }
} }
), ),
@@ -131,35 +131,35 @@ namespace
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<polygon_collider>& c){ "enable", [](gcomponent<polygon_collider>& c){
c.owner().component<disabled<polygon_collider>>().remove(); c.component<disabled<polygon_collider>>().remove();
}, },
"disable", [](gcomponent<polygon_collider>& c){ "disable", [](gcomponent<polygon_collider>& c){
c.owner().component<disabled<polygon_collider>>().ensure(); c.component<disabled<polygon_collider>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<polygon_collider>& c) -> bool { [](const gcomponent<polygon_collider>& c) -> bool {
return !c.owner().component<disabled<polygon_collider>>().exists(); return !c.component<disabled<polygon_collider>>().exists();
}, },
[](gcomponent<polygon_collider>& c, bool yesno){ [](gcomponent<polygon_collider>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<polygon_collider>>().remove(); c.component<disabled<polygon_collider>>().remove();
} else { } else {
c.owner().component<disabled<polygon_collider>>().ensure(); c.component<disabled<polygon_collider>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<polygon_collider>& c) -> bool { [](const gcomponent<polygon_collider>& c) -> bool {
return c.owner().component<disabled<polygon_collider>>().exists(); return c.component<disabled<polygon_collider>>().exists();
}, },
[](gcomponent<polygon_collider>& c, bool yesno){ [](gcomponent<polygon_collider>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<polygon_collider>>().ensure(); c.component<disabled<polygon_collider>>().ensure();
} else { } else {
c.owner().component<disabled<polygon_collider>>().remove(); c.component<disabled<polygon_collider>>().remove();
} }
} }
), ),

View File

@@ -17,24 +17,24 @@ namespace e2d::bindings::high
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<layout>& c){ "enable", [](gcomponent<layout>& c){
c.owner().component<disabled<layout>>().remove(); c.component<disabled<layout>>().remove();
layouts::mark_dirty(c); layouts::mark_dirty(c);
}, },
"disable", [](gcomponent<layout>& c){ "disable", [](gcomponent<layout>& c){
c.owner().component<disabled<layout>>().ensure(); c.component<disabled<layout>>().ensure();
layouts::mark_dirty(c); layouts::mark_dirty(c);
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<layout>& c) -> bool { [](const gcomponent<layout>& c) -> bool {
return !c.owner().component<disabled<layout>>().exists(); return !c.component<disabled<layout>>().exists();
}, },
[](gcomponent<layout>& c, bool yesno){ [](gcomponent<layout>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<layout>>().remove(); c.component<disabled<layout>>().remove();
} else { } else {
c.owner().component<disabled<layout>>().ensure(); c.component<disabled<layout>>().ensure();
} }
layouts::mark_dirty(c); layouts::mark_dirty(c);
} }
@@ -42,13 +42,13 @@ namespace e2d::bindings::high
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<layout>& c) -> bool { [](const gcomponent<layout>& c) -> bool {
return c.owner().component<disabled<layout>>().exists(); return c.component<disabled<layout>>().exists();
}, },
[](gcomponent<layout>& c, bool yesno){ [](gcomponent<layout>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<layout>>().ensure(); c.component<disabled<layout>>().ensure();
} else { } else {
c.owner().component<disabled<layout>>().remove(); c.component<disabled<layout>>().remove();
} }
layouts::mark_dirty(c); layouts::mark_dirty(c);
} }
@@ -67,22 +67,6 @@ namespace e2d::bindings::high
} }
), ),
"halign", sol::property(
[](const gcomponent<layout>& c) -> layout::haligns {
return c->halign();
},
[](gcomponent<layout>& c, layout::haligns v){
layouts::change_halign(c, v);
}),
"valign", sol::property(
[](const gcomponent<layout>& c) -> layout::valigns {
return c->valign();
},
[](gcomponent<layout>& c, layout::valigns v){
layouts::change_valign(c, v);
}),
"direction", sol::property( "direction", sol::property(
[](const gcomponent<layout>& c) -> layout::directions { [](const gcomponent<layout>& c) -> layout::directions {
return c->direction(); return c->direction();
@@ -91,63 +75,95 @@ namespace e2d::bindings::high
layouts::change_direction(c, v); layouts::change_direction(c, v);
}), }),
"size", sol::property( "align_items", sol::property(
[](const gcomponent<layout>& c) -> v2f { [](const gcomponent<layout>& c) -> layout::align_modes {
return c->size(); return c->align_items();
}, },
[](gcomponent<layout>& c, const v2f& v){ [](gcomponent<layout>& c, layout::align_modes v){
layouts::change_size(c, v); layouts::change_align_items(c, v);
}), }),
"margin", sol::property( "align_content", sol::property(
[](const gcomponent<layout>& c) -> v2f { [](const gcomponent<layout>& c) -> layout::align_modes {
return c->margin(); return c->align_content();
}, },
[](gcomponent<layout>& c, const v2f& v){ [](gcomponent<layout>& c, layout::align_modes v){
layouts::change_margin(c, v); layouts::change_align_content(c, v);
}), }),
"padding", sol::property( "justify_content", sol::property(
[](const gcomponent<layout>& c) -> v2f { [](const gcomponent<layout>& c) -> layout::justify_modes {
return c->padding(); return c->justify_content();
}, },
[](gcomponent<layout>& c, const v2f& v){ [](gcomponent<layout>& c, layout::justify_modes v){
layouts::change_padding(c, v); layouts::change_justify_content(c, v);
}),
"flex_wrap", sol::property(
[](const gcomponent<layout>& c) -> layout::flex_wraps {
return c->flex_wrap();
},
[](gcomponent<layout>& c, layout::flex_wraps v){
layouts::change_flex_wrap(c, v);
}),
"flex_direction", sol::property(
[](const gcomponent<layout>& c) -> layout::flex_directions {
return c->flex_direction();
},
[](gcomponent<layout>& c, layout::flex_directions v){
layouts::change_flex_direction(c, v);
}) })
); );
#define LAYOUT_HALIGN_PAIR(x) {#x, layout::haligns::x},
l["layout"].get_or_create<sol::table>()
.new_enum<layout::haligns>("haligns", {
LAYOUT_HALIGN_PAIR(left)
LAYOUT_HALIGN_PAIR(center)
LAYOUT_HALIGN_PAIR(right)
LAYOUT_HALIGN_PAIR(space_around)
LAYOUT_HALIGN_PAIR(space_evenly)
LAYOUT_HALIGN_PAIR(space_between)
});
#undef LAYOUT_HALIGN_PAIR
#define LAYOUT_VALIGN_PAIR(x) {#x, layout::valigns::x},
l["layout"].get_or_create<sol::table>()
.new_enum<layout::valigns>("valigns", {
LAYOUT_VALIGN_PAIR(top)
LAYOUT_VALIGN_PAIR(center)
LAYOUT_VALIGN_PAIR(bottom)
LAYOUT_VALIGN_PAIR(space_around)
LAYOUT_VALIGN_PAIR(space_evenly)
LAYOUT_VALIGN_PAIR(space_between)
});
#undef LAYOUT_VALIGN_PAIR
#define LAYOUT_DIRECTION_PAIR(x) {#x, layout::directions::x}, #define LAYOUT_DIRECTION_PAIR(x) {#x, layout::directions::x},
l["layout"].get_or_create<sol::table>() l["layout"].get_or_create<sol::table>()
.new_enum<layout::directions>("directions", { .new_enum<layout::directions>("directions", {
LAYOUT_DIRECTION_PAIR(row) LAYOUT_DIRECTION_PAIR(ltr)
LAYOUT_DIRECTION_PAIR(row_reversed) LAYOUT_DIRECTION_PAIR(rtl)
LAYOUT_DIRECTION_PAIR(column)
LAYOUT_DIRECTION_PAIR(column_reversed)
}); });
#undef LAYOUT_DIRECTION_PAIR #undef LAYOUT_DIRECTION_PAIR
#define LAYOUT_ALIGN_MODE_PAIR(x) {#x, layout::align_modes::x},
l["layout"].get_or_create<sol::table>()
.new_enum<layout::align_modes>("align_modes", {
LAYOUT_ALIGN_MODE_PAIR(flex_start)
LAYOUT_ALIGN_MODE_PAIR(center)
LAYOUT_ALIGN_MODE_PAIR(flex_end)
LAYOUT_ALIGN_MODE_PAIR(space_between)
LAYOUT_ALIGN_MODE_PAIR(space_around)
});
#undef LAYOUT_ALIGN_MODE_PAIR
#define LAYOUT_JUSTIFY_MODE_PAIR(x) {#x, layout::justify_modes::x},
l["layout"].get_or_create<sol::table>()
.new_enum<layout::justify_modes>("justify_modes", {
LAYOUT_JUSTIFY_MODE_PAIR(flex_start)
LAYOUT_JUSTIFY_MODE_PAIR(center)
LAYOUT_JUSTIFY_MODE_PAIR(flex_end)
LAYOUT_JUSTIFY_MODE_PAIR(space_between)
LAYOUT_JUSTIFY_MODE_PAIR(space_around)
LAYOUT_JUSTIFY_MODE_PAIR(space_evenly)
});
#undef LAYOUT_JUSTIFY_MODE_PAIR
#define LAYOUT_FLEX_WRAP_PAIR(x) {#x, layout::flex_wraps::x},
l["layout"].get_or_create<sol::table>()
.new_enum<layout::flex_wraps>("flex_wraps", {
LAYOUT_FLEX_WRAP_PAIR(no_wrap)
LAYOUT_FLEX_WRAP_PAIR(wrap)
LAYOUT_FLEX_WRAP_PAIR(wrap_reversed)
});
#undef LAYOUT_FLEX_WRAP_PAIR
#define LAYOUT_FLEX_DIRECTION_PAIR(x) {#x, layout::flex_directions::x},
l["layout"].get_or_create<sol::table>()
.new_enum<layout::flex_directions>("flex_directions", {
LAYOUT_FLEX_DIRECTION_PAIR(row)
LAYOUT_FLEX_DIRECTION_PAIR(row_reversed)
LAYOUT_FLEX_DIRECTION_PAIR(column)
LAYOUT_FLEX_DIRECTION_PAIR(column_reversed)
});
#undef LAYOUT_FLEX_DIRECTION_PAIR
} }
} }

View File

@@ -17,35 +17,35 @@ namespace e2d::bindings::high
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<renderer>& c){ "enable", [](gcomponent<renderer>& c){
c.owner().component<disabled<renderer>>().remove(); c.component<disabled<renderer>>().remove();
}, },
"disable", [](gcomponent<renderer>& c){ "disable", [](gcomponent<renderer>& c){
c.owner().component<disabled<renderer>>().ensure(); c.component<disabled<renderer>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<renderer>& c) -> bool { [](const gcomponent<renderer>& c) -> bool {
return !c.owner().component<disabled<renderer>>().exists(); return !c.component<disabled<renderer>>().exists();
}, },
[](gcomponent<renderer>& c, bool yesno){ [](gcomponent<renderer>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<renderer>>().remove(); c.component<disabled<renderer>>().remove();
} else { } else {
c.owner().component<disabled<renderer>>().ensure(); c.component<disabled<renderer>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<renderer>& c) -> bool { [](const gcomponent<renderer>& c) -> bool {
return c.owner().component<disabled<renderer>>().exists(); return c.component<disabled<renderer>>().exists();
}, },
[](gcomponent<renderer>& c, bool yesno){ [](gcomponent<renderer>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<renderer>>().ensure(); c.component<disabled<renderer>>().ensure();
} else { } else {
c.owner().component<disabled<renderer>>().remove(); c.component<disabled<renderer>>().remove();
} }
} }
), ),

View File

@@ -17,35 +17,35 @@ namespace e2d::bindings::high
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<scene>& c){ "enable", [](gcomponent<scene>& c){
c.owner().component<disabled<scene>>().remove(); c.component<disabled<scene>>().remove();
}, },
"disable", [](gcomponent<scene>& c){ "disable", [](gcomponent<scene>& c){
c.owner().component<disabled<scene>>().ensure(); c.component<disabled<scene>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<scene>& c) -> bool { [](const gcomponent<scene>& c) -> bool {
return !c.owner().component<disabled<scene>>().exists(); return !c.component<disabled<scene>>().exists();
}, },
[](gcomponent<scene>& c, bool yesno){ [](gcomponent<scene>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<scene>>().remove(); c.component<disabled<scene>>().remove();
} else { } else {
c.owner().component<disabled<scene>>().ensure(); c.component<disabled<scene>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<scene>& c) -> bool { [](const gcomponent<scene>& c) -> bool {
return c.owner().component<disabled<scene>>().exists(); return c.component<disabled<scene>>().exists();
}, },
[](gcomponent<scene>& c, bool yesno){ [](gcomponent<scene>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<scene>>().ensure(); c.component<disabled<scene>>().ensure();
} else { } else {
c.owner().component<disabled<scene>>().remove(); c.component<disabled<scene>>().remove();
} }
} }
), ),

View File

@@ -17,35 +17,35 @@ namespace e2d::bindings::high
sol::no_constructor, sol::no_constructor,
"enable", [](gcomponent<touchable>& c){ "enable", [](gcomponent<touchable>& c){
c.owner().component<disabled<touchable>>().remove(); c.component<disabled<touchable>>().remove();
}, },
"disable", [](gcomponent<touchable>& c){ "disable", [](gcomponent<touchable>& c){
c.owner().component<disabled<touchable>>().ensure(); c.component<disabled<touchable>>().ensure();
}, },
"enabled", sol::property( "enabled", sol::property(
[](const gcomponent<touchable>& c) -> bool { [](const gcomponent<touchable>& c) -> bool {
return !c.owner().component<disabled<touchable>>().exists(); return !c.component<disabled<touchable>>().exists();
}, },
[](gcomponent<touchable>& c, bool yesno){ [](gcomponent<touchable>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<touchable>>().remove(); c.component<disabled<touchable>>().remove();
} else { } else {
c.owner().component<disabled<touchable>>().ensure(); c.component<disabled<touchable>>().ensure();
} }
} }
), ),
"disabled", sol::property( "disabled", sol::property(
[](const gcomponent<touchable>& c) -> bool { [](const gcomponent<touchable>& c) -> bool {
return c.owner().component<disabled<touchable>>().exists(); return c.component<disabled<touchable>>().exists();
}, },
[](gcomponent<touchable>& c, bool yesno){ [](gcomponent<touchable>& c, bool yesno){
if ( yesno ) { if ( yesno ) {
c.owner().component<disabled<touchable>>().ensure(); c.component<disabled<touchable>>().ensure();
} else { } else {
c.owner().component<disabled<touchable>>().remove(); c.component<disabled<touchable>>().remove();
} }
} }
), ),

View File

@@ -0,0 +1,91 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../_high_binds.hpp"
#include <enduro2d/high/gobject.hpp>
#include <enduro2d/high/components/disabled.hpp>
#include <enduro2d/high/components/widget.hpp>
namespace e2d::bindings::high
{
void bind_widget(sol::state& l) {
l.new_usertype<gcomponent<widget>>("widget",
sol::no_constructor,
"enable", [](gcomponent<widget>& c){
c.component<disabled<widget>>().remove();
},
"disable", [](gcomponent<widget>& c){
c.component<disabled<widget>>().ensure();
},
"enabled", sol::property(
[](const gcomponent<widget>& c) -> bool {
return !c.component<disabled<widget>>().exists();
},
[](gcomponent<widget>& c, bool yesno){
if ( yesno ) {
c.component<disabled<widget>>().remove();
} else {
c.component<disabled<widget>>().ensure();
}
}
),
"disabled", sol::property(
[](const gcomponent<widget>& c) -> bool {
return c.component<disabled<widget>>().exists();
},
[](gcomponent<widget>& c, bool yesno){
if ( yesno ) {
c.component<disabled<widget>>().ensure();
} else {
c.component<disabled<widget>>().remove();
}
}
),
"dirty", sol::property(
[](const gcomponent<widget>& c) -> bool {
return widgets::is_dirty(c);
},
[](gcomponent<widget>& c, bool yesno){
if ( yesno ) {
widgets::mark_dirty(c);
} else {
widgets::unmark_dirty(c);
}
}
),
"size", sol::property(
[](const gcomponent<widget>& c) -> v2f {
return c->size();
},
[](gcomponent<widget>& c, const v2f& v){
widgets::change_size(c, v);
}),
"margin", sol::property(
[](const gcomponent<widget>& c) -> v2f {
return c->margin();
},
[](gcomponent<widget>& c, const v2f& v){
widgets::change_margin(c, v);
}),
"padding", sol::property(
[](const gcomponent<widget>& c) -> v2f {
return c->padding();
},
[](gcomponent<widget>& c, const v2f& v){
widgets::change_padding(c, v);
})
);
}
}

View File

@@ -21,6 +21,7 @@
#include <enduro2d/high/components/spine_player.hpp> #include <enduro2d/high/components/spine_player.hpp>
#include <enduro2d/high/components/sprite_renderer.hpp> #include <enduro2d/high/components/sprite_renderer.hpp>
#include <enduro2d/high/components/touchable.hpp> #include <enduro2d/high/components/touchable.hpp>
#include <enduro2d/high/components/widget.hpp>
namespace e2d::bindings::high namespace e2d::bindings::high
{ {
@@ -54,7 +55,8 @@ namespace e2d::bindings::high
"scene", sol::property([](gobject& go){ return component_wrapper<scene>{go}; }), "scene", sol::property([](gobject& go){ return component_wrapper<scene>{go}; }),
"spine_player", sol::property([](gobject& go){ return component_wrapper<spine_player>{go}; }), "spine_player", sol::property([](gobject& go){ return component_wrapper<spine_player>{go}; }),
"sprite_renderer", sol::property([](gobject& go){ return component_wrapper<sprite_renderer>{go}; }), "sprite_renderer", sol::property([](gobject& go){ return component_wrapper<sprite_renderer>{go}; }),
"touchable", sol::property([](gobject& go){ return component_wrapper<touchable>{go}; }) "touchable", sol::property([](gobject& go){ return component_wrapper<touchable>{go}; }),
"widget", sol::property([](gobject& go){ return component_wrapper<widget>{go}; })
); );
} }
} }

View File

@@ -15,9 +15,24 @@ namespace e2d::bindings::high
sol::no_constructor, sol::no_constructor,
"instantiate", sol::overload( "instantiate", sol::overload(
[](world& w) -> gobject {
return w.instantiate();
},
[](world& w, const t2f& transform) -> gobject {
return w.instantiate(transform);
},
[](world& w, const node_iptr& parent) -> gobject {
return w.instantiate(parent);
},
[](world& w, const node_iptr& parent, const t2f& transform) -> gobject {
return w.instantiate(parent, transform);
},
[](world& w, const prefab& prefab) -> gobject { [](world& w, const prefab& prefab) -> gobject {
return w.instantiate(prefab); return w.instantiate(prefab);
}, },
[](world& w, const prefab& prefab, const t2f& transform) -> gobject {
return w.instantiate(prefab, transform);
},
[](world& w, const prefab& prefab, const node_iptr& parent) -> gobject { [](world& w, const prefab& prefab, const node_iptr& parent) -> gobject {
return w.instantiate(prefab, parent); return w.instantiate(prefab, parent);
}, },

View File

@@ -185,25 +185,25 @@ namespace e2d
const char* component_inspector<camera>::title = ICON_FA_VIDEO " camera"; const char* component_inspector<camera>::title = ICON_FA_VIDEO " camera";
void component_inspector<camera>::operator()(gcomponent<camera>& c) const { void component_inspector<camera>::operator()(gcomponent<camera>& c) const {
if ( bool input = c.owner().component<camera::input>().exists(); if ( bool input = c.component<camera::input>().exists();
ImGui::Checkbox("input", &input) ) ImGui::Checkbox("input", &input) )
{ {
if ( input ) { if ( input ) {
c.owner().component<camera::input>().ensure(); c.component<camera::input>().ensure();
} else { } else {
c.owner().component<camera::input>().remove(); c.component<camera::input>().remove();
} }
} }
ImGui::SameLine(); ImGui::SameLine();
if ( bool gizmos = c.owner().component<camera::gizmos>().exists(); if ( bool gizmos = c.component<camera::gizmos>().exists();
ImGui::Checkbox("gizmos", &gizmos) ) ImGui::Checkbox("gizmos", &gizmos) )
{ {
if ( gizmos ) { if ( gizmos ) {
c.owner().component<camera::gizmos>().ensure(); c.component<camera::gizmos>().ensure();
} else { } else {
c.owner().component<camera::gizmos>().remove(); c.component<camera::gizmos>().remove();
} }
} }

View File

@@ -201,7 +201,7 @@ namespace e2d
const char* component_inspector<label>::title = ICON_FA_PARAGRAPH " label"; const char* component_inspector<label>::title = ICON_FA_PARAGRAPH " label";
void component_inspector<label>::operator()(gcomponent<label>& c) const { void component_inspector<label>::operator()(gcomponent<label>& c) const {
if ( bool dirty = c.owner().component<label::dirty>().exists(); if ( bool dirty = c.component<label::dirty>().exists();
ImGui::Checkbox("dirty", &dirty) ) ImGui::Checkbox("dirty", &dirty) )
{ {
if ( dirty ) { if ( dirty ) {
@@ -337,20 +337,20 @@ namespace e2d::labels
{ {
gcomponent<label> mark_dirty(gcomponent<label> self) { gcomponent<label> mark_dirty(gcomponent<label> self) {
if ( self ) { if ( self ) {
self.owner().component<label::dirty>().ensure(); self.component<label::dirty>().ensure();
} }
return self; return self;
} }
gcomponent<label> unmark_dirty(gcomponent<label> self) { gcomponent<label> unmark_dirty(gcomponent<label> self) {
if ( self ) { if ( self ) {
self.owner().component<label::dirty>().remove(); self.component<label::dirty>().remove();
} }
return self; return self;
} }
bool is_dirty(const const_gcomponent<label>& self) noexcept { bool is_dirty(const const_gcomponent<label>& self) noexcept {
return self.owner().component<label::dirty>().exists(); return self.component<label::dirty>().exists();
} }
gcomponent<label> change_text(gcomponent<label> self, str value) { gcomponent<label> change_text(gcomponent<label> self, str value) {

View File

@@ -15,37 +15,51 @@ namespace e2d
"required" : [], "required" : [],
"additionalProperties" : false, "additionalProperties" : false,
"properties" : { "properties" : {
"halign" : { "$ref": "#/definitions/haligns" },
"valign" : { "$ref": "#/definitions/valigns" },
"direction" : { "$ref": "#/definitions/directions" }, "direction" : { "$ref": "#/definitions/directions" },
"size" : { "$ref": "#/common_definitions/v2" }, "align_items" : { "$ref": "#/definitions/align_modes" },
"margin" : { "$ref": "#/common_definitions/v2" }, "align_content" : { "$ref": "#/definitions/align_modes" },
"padding" : { "$ref": "#/common_definitions/v2" } "justify_content" : { "$ref": "#/definitions/justify_modes" },
"flex_wrap" : { "$ref": "#/definitions/flex_wraps" },
"flex_direction" : { "$ref": "#/definitions/flex_directions" }
}, },
"definitions" : { "definitions" : {
"haligns" : {
"type" : "string",
"enum" : [
"left",
"center",
"right",
"space_around",
"space_evenly",
"space_between"
]
},
"valigns" : {
"type" : "string",
"enum" : [
"top",
"center",
"bottom",
"space_around",
"space_evenly",
"space_between"
]
},
"directions" : { "directions" : {
"type" : "string",
"enum" : [
"ltr",
"rtl"
]
},
"align_modes" : {
"type" : "string",
"enum" : [
"flex_start",
"center",
"flex_end",
"space_between",
"space_around"
]
},
"justify_modes" : {
"type" : "string",
"enum" : [
"flex_start",
"center",
"flex_end",
"space_between",
"space_around",
"space_evenly"
]
},
"flex_wraps" : {
"type" : "string",
"enum" : [
"no_wrap",
"wrap",
"wrap_reversed"
]
},
"flex_directions" : {
"type" : "string", "type" : "string",
"enum" : [ "enum" : [
"row", "row",
@@ -61,24 +75,6 @@ namespace e2d
layout& component, layout& component,
const fill_context& ctx) const const fill_context& ctx) const
{ {
if ( ctx.root.HasMember("halign") ) {
layout::haligns halign = component.halign();
if ( !json_utils::try_parse_value(ctx.root["halign"], halign) ) {
the<debug>().error("LAYOUT: Incorrect formatting of 'halign' property");
return false;
}
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("direction") ) { if ( ctx.root.HasMember("direction") ) {
layout::directions direction = component.direction(); layout::directions direction = component.direction();
if ( !json_utils::try_parse_value(ctx.root["direction"], direction) ) { if ( !json_utils::try_parse_value(ctx.root["direction"], direction) ) {
@@ -88,31 +84,49 @@ namespace e2d
component.direction(direction); component.direction(direction);
} }
if ( ctx.root.HasMember("size") ) { if ( ctx.root.HasMember("align_items") ) {
v2f size = component.size(); layout::align_modes align_items = component.align_items();
if ( !json_utils::try_parse_value(ctx.root["size"], size) ) { if ( !json_utils::try_parse_value(ctx.root["align_items"], align_items) ) {
the<debug>().error("LAYOUT: Incorrect formatting of 'size' property"); the<debug>().error("LAYOUT: Incorrect formatting of 'align_items' property");
return false; return false;
} }
component.size(size); component.align_items(align_items);
} }
if ( ctx.root.HasMember("margin") ) { if ( ctx.root.HasMember("align_content") ) {
v2f margin = component.margin(); layout::align_modes align_content = component.align_content();
if ( !json_utils::try_parse_value(ctx.root["margin"], margin) ) { if ( !json_utils::try_parse_value(ctx.root["align_content"], align_content) ) {
the<debug>().error("LAYOUT: Incorrect formatting of 'margin' property"); the<debug>().error("LAYOUT: Incorrect formatting of 'align_content' property");
return false; return false;
} }
component.margin(margin); component.align_content(align_content);
} }
if ( ctx.root.HasMember("padding") ) { if ( ctx.root.HasMember("justify_content") ) {
v2f padding = component.padding(); layout::justify_modes justify_content = component.justify_content();
if ( !json_utils::try_parse_value(ctx.root["padding"], padding) ) { if ( !json_utils::try_parse_value(ctx.root["justify_content"], justify_content) ) {
the<debug>().error("LAYOUT: Incorrect formatting of 'padding' property"); the<debug>().error("LAYOUT: Incorrect formatting of 'justify_content' property");
return false; return false;
} }
component.padding(padding); component.justify_content(justify_content);
}
if ( ctx.root.HasMember("flex_wrap") ) {
layout::flex_wraps flex_wrap = component.flex_wrap();
if ( !json_utils::try_parse_value(ctx.root["flex_wrap"], flex_wrap) ) {
the<debug>().error("LAYOUT: Incorrect formatting of 'flex_wrap' property");
return false;
}
component.flex_wrap(flex_wrap);
}
if ( ctx.root.HasMember("flex_direction") ) {
layout::flex_directions flex_direction = component.flex_direction();
if ( !json_utils::try_parse_value(ctx.root["flex_direction"], flex_direction) ) {
the<debug>().error("LAYOUT: Incorrect formatting of 'flex_direction' property");
return false;
}
component.flex_direction(flex_direction);
} }
return true; return true;
@@ -158,7 +172,7 @@ namespace e2d
const char* component_inspector<layout>::title = ICON_FA_BARS " layout"; const char* component_inspector<layout>::title = ICON_FA_BARS " layout";
void component_inspector<layout>::operator()(gcomponent<layout>& c) const { void component_inspector<layout>::operator()(gcomponent<layout>& c) const {
if ( bool dirty = c.owner().component<layout::dirty>().exists(); if ( bool dirty = c.component<layout::dirty>().exists();
ImGui::Checkbox("dirty", &dirty) ) ImGui::Checkbox("dirty", &dirty) )
{ {
if ( dirty ) { if ( dirty ) {
@@ -170,66 +184,40 @@ namespace e2d
ImGui::Separator(); ImGui::Separator();
if ( layout::haligns halign = c->halign();
imgui_utils::show_enum_combo_box("halign", &halign) )
{
layouts::change_halign(c, halign);
}
if ( layout::valigns valign = c->valign();
imgui_utils::show_enum_combo_box("valign", &valign) )
{
layouts::change_valign(c, valign);
}
if ( layout::directions direction = c->direction(); if ( layout::directions direction = c->direction();
imgui_utils::show_enum_combo_box("direction", &direction) ) imgui_utils::show_enum_combo_box("direction", &direction) )
{ {
layouts::change_direction(c, direction); layouts::change_direction(c, direction);
} }
if ( v2f size = c->size(); if ( layout::align_modes align_items = c->align_items();
ImGui::DragFloat2("size", size.data(), 1.f) ) imgui_utils::show_enum_combo_box("align_items", &align_items) )
{ {
layouts::change_size(c, size); layouts::change_align_items(c, align_items);
} }
if ( v2f margin = c->margin(); if ( layout::align_modes align_content = c->align_content();
ImGui::DragFloat2("margin", margin.data(), 1.f) ) imgui_utils::show_enum_combo_box("align_content", &align_content) )
{ {
layouts::change_margin(c, margin); layouts::change_align_content(c, align_content);
} }
if ( v2f padding = c->padding(); if ( layout::justify_modes justify_content = c->justify_content();
ImGui::DragFloat2("padding", padding.data(), 1.f) ) imgui_utils::show_enum_combo_box("justify_content", &justify_content) )
{ {
layouts::change_padding(c, padding); layouts::change_justify_content(c, justify_content);
} }
}
void component_inspector<layout>::operator()( if ( layout::flex_wraps flex_wrap = c->flex_wrap();
gcomponent<layout>& c, imgui_utils::show_enum_combo_box("flex_wrap", &flex_wrap) )
gizmos_context& ctx) const {
{ layouts::change_flex_wrap(c, flex_wrap);
ctx.draw_wire_rect( }
c->size() * 0.5f,
c->size(),
ctx.selected() ? color32(255,255,255) : color32(127,127,127));
if ( ctx.selected() ) { if ( layout::flex_directions flex_direction = c->flex_direction();
if ( c->margin() != v2f::zero() ) { imgui_utils::show_enum_combo_box("flex_direction", &flex_direction) )
ctx.draw_wire_rect( {
c->size() * 0.5f, layouts::change_flex_direction(c, flex_direction);
c->size() + c->margin() * 2.f,
ctx.selected() ? color32(255,255,255) : color32(127,127,127));
}
if ( c->padding() != v2f::zero() ) {
ctx.draw_wire_rect(
c->size() * 0.5f,
c->size() - c->padding() * 2.f,
ctx.selected() ? color32(255,255,255) : color32(127,127,127));
}
} }
} }
} }
@@ -238,34 +226,20 @@ namespace e2d::layouts
{ {
gcomponent<layout> mark_dirty(gcomponent<layout> self) { gcomponent<layout> mark_dirty(gcomponent<layout> self) {
if ( self ) { if ( self ) {
self.owner().component<layout::dirty>().ensure(); self.component<layout::dirty>().ensure();
} }
return self; return self;
} }
gcomponent<layout> unmark_dirty(gcomponent<layout> self) { gcomponent<layout> unmark_dirty(gcomponent<layout> self) {
if ( self ) { if ( self ) {
self.owner().component<layout::dirty>().remove(); self.component<layout::dirty>().remove();
} }
return self; return self;
} }
bool is_dirty(const const_gcomponent<layout>& self) noexcept { bool is_dirty(const const_gcomponent<layout>& self) noexcept {
return self.owner().component<layout::dirty>().exists(); return self.component<layout::dirty>().exists();
}
gcomponent<layout> change_halign(gcomponent<layout> self, layout::haligns value) {
if ( self ) {
self->halign(value);
}
return mark_dirty(self);
}
gcomponent<layout> change_valign(gcomponent<layout> self, layout::valigns value) {
if ( self ) {
self->valign(value);
}
return mark_dirty(self);
} }
gcomponent<layout> change_direction(gcomponent<layout> self, layout::directions value) { gcomponent<layout> change_direction(gcomponent<layout> self, layout::directions value) {
@@ -275,32 +249,43 @@ namespace e2d::layouts
return mark_dirty(self); return mark_dirty(self);
} }
gcomponent<layout> change_size(gcomponent<layout> self, const v2f& value) { gcomponent<layout> change_align_items(gcomponent<layout> self, layout::align_modes value) {
if ( self ) { if ( self ) {
self->size(value); self->align_items(value);
} }
mark_dirty(find_parent_layout(self));
return mark_dirty(self); return mark_dirty(self);
} }
gcomponent<layout> change_margin(gcomponent<layout> self, const v2f& value) { gcomponent<layout> change_align_content(gcomponent<layout> self, layout::align_modes value) {
if ( self ) { if ( self ) {
self->margin(value); self->align_content(value);
} }
mark_dirty(find_parent_layout(self));
return mark_dirty(self); return mark_dirty(self);
} }
gcomponent<layout> change_padding(gcomponent<layout> self, const v2f& value) { gcomponent<layout> change_justify_content(gcomponent<layout> self, layout::justify_modes value) {
if ( self ) { if ( self ) {
self->padding(value); self->justify_content(value);
}
return mark_dirty(self);
}
gcomponent<layout> change_flex_wrap(gcomponent<layout> self, layout::flex_wraps value) {
if ( self ) {
self->flex_wrap(value);
}
return mark_dirty(self);
}
gcomponent<layout> change_flex_direction(gcomponent<layout> self, layout::flex_directions value) {
if ( self ) {
self->flex_direction(value);
} }
mark_dirty(find_parent_layout(self));
return mark_dirty(self); return mark_dirty(self);
} }
gcomponent<layout> find_parent_layout(const_gcomponent<layout> self) noexcept { gcomponent<layout> find_parent_layout(const_gcomponent<layout> self) noexcept {
const_gcomponent<actor> self_actor = self.owner().component<actor>(); const_gcomponent<actor> self_actor = self.component<actor>();
return self_actor return self_actor
? nodes::find_component_from_parents<layout>(self_actor->node()) ? nodes::find_component_from_parents<layout>(self_actor->node())
: gcomponent<layout>(); : gcomponent<layout>();

View File

@@ -0,0 +1,207 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <enduro2d/high/components/widget.hpp>
#include <enduro2d/high/components/actor.hpp>
#include <enduro2d/high/components/layout.hpp>
namespace e2d
{
const char* factory_loader<widget>::schema_source = R"json({
"type" : "object",
"required" : [],
"additionalProperties" : false,
"properties" : {
"size" : { "$ref": "#/common_definitions/v2" },
"margin" : { "$ref": "#/common_definitions/v2" },
"padding" : { "$ref": "#/common_definitions/v2" }
}
})json";
bool factory_loader<widget>::operator()(
widget& component,
const fill_context& ctx) const
{
if ( ctx.root.HasMember("size") ) {
v2f size = component.size();
if ( !json_utils::try_parse_value(ctx.root["size"], size) ) {
the<debug>().error("WIDGET: Incorrect formatting of 'size' property");
return false;
}
component.size(size);
}
if ( ctx.root.HasMember("margin") ) {
v2f margin = component.margin();
if ( !json_utils::try_parse_value(ctx.root["margin"], margin) ) {
the<debug>().error("WIDGET: Incorrect formatting of 'margin' property");
return false;
}
component.margin(margin);
}
if ( ctx.root.HasMember("padding") ) {
v2f padding = component.padding();
if ( !json_utils::try_parse_value(ctx.root["padding"], padding) ) {
the<debug>().error("WIDGET: Incorrect formatting of 'padding' property");
return false;
}
component.padding(padding);
}
return true;
}
bool factory_loader<widget>::operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const
{
E2D_UNUSED(dependencies, ctx);
return true;
}
}
namespace e2d
{
const char* factory_loader<widget::dirty>::schema_source = R"json({
"type" : "object",
"required" : [],
"additionalProperties" : false,
"properties" : {}
})json";
bool factory_loader<widget::dirty>::operator()(
widget::dirty& component,
const fill_context& ctx) const
{
E2D_UNUSED(component, ctx);
return true;
}
bool factory_loader<widget::dirty>::operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const
{
E2D_UNUSED(dependencies, ctx);
return true;
}
}
namespace e2d
{
const char* component_inspector<widget>::title = ICON_FA_VECTOR_SQUARE " widget";
void component_inspector<widget>::operator()(gcomponent<widget>& c) const {
if ( bool dirty = c.component<widget::dirty>().exists();
ImGui::Checkbox("dirty", &dirty) )
{
if ( dirty ) {
widgets::mark_dirty(c);
} else {
widgets::unmark_dirty(c);
}
}
ImGui::Separator();
if ( v2f size = c->size();
ImGui::DragFloat2("size", size.data(), 1.f) )
{
widgets::change_size(c, size);
}
if ( v2f margin = c->margin();
ImGui::DragFloat2("margin", margin.data(), 1.f) )
{
widgets::change_margin(c, margin);
}
if ( v2f padding = c->padding();
ImGui::DragFloat2("padding", padding.data(), 1.f) )
{
widgets::change_padding(c, padding);
}
}
void component_inspector<widget>::operator()(
gcomponent<widget>& c,
gizmos_context& ctx) const
{
const color32 white_c{255,255,255};
const color32 gray_c{255,255,255,127};
ctx.draw_wire_rect(
c->size() * 0.5f,
c->size(),
ctx.selected() ? white_c : gray_c);
if ( ctx.selected() ) {
if ( c->margin() != v2f::zero() ) {
ctx.draw_wire_rect(
c->size() * 0.5f,
c->size() + c->margin() * 2.f,
ctx.selected() ? white_c : gray_c);
}
if ( c->padding() != v2f::zero() ) {
ctx.draw_wire_rect(
c->size() * 0.5f,
c->size() - c->padding() * 2.f,
ctx.selected() ? white_c : gray_c);
}
}
}
}
namespace e2d::widgets
{
gcomponent<widget> mark_dirty(gcomponent<widget> self) {
if ( self ) {
self.component<widget::dirty>().ensure();
}
return self;
}
gcomponent<widget> unmark_dirty(gcomponent<widget> self) {
if ( self ) {
self.component<widget::dirty>().remove();
}
return self;
}
bool is_dirty(const const_gcomponent<widget>& self) noexcept {
return self.component<widget::dirty>().exists();
}
gcomponent<widget> change_size(gcomponent<widget> self, const v2f& value) {
if ( self ) {
self->size(value);
}
return mark_dirty(self);
}
gcomponent<widget> change_margin(gcomponent<widget> self, const v2f& value) {
if ( self ) {
self->margin(value);
}
return mark_dirty(self);
}
gcomponent<widget> change_padding(gcomponent<widget> self, const v2f& value) {
if ( self ) {
self->padding(value);
}
return mark_dirty(self);
}
gcomponent<layout> find_parent_layout(const_gcomponent<widget> self) noexcept {
const_gcomponent<actor> self_actor = self.component<actor>();
return self_actor
? nodes::find_component_from_parents<layout>(self_actor->node())
: gcomponent<layout>();
}
}

View File

@@ -21,9 +21,9 @@ namespace e2d
} }
node_iptr node::create(const t2f& transform) { node_iptr node::create(const t2f& transform) {
node_iptr n = create(); node_iptr child = create();
n->transform(transform); child->transform(transform);
return n; return child;
} }
node_iptr node::create(const node_iptr& parent) { node_iptr node::create(const node_iptr& parent) {
@@ -35,9 +35,9 @@ namespace e2d
} }
node_iptr node::create(const node_iptr& parent, const t2f& transform) { node_iptr node::create(const node_iptr& parent, const t2f& transform) {
node_iptr n = create(parent); node_iptr child = create(parent);
n->transform(transform); child->transform(transform);
return n; return child;
} }
node_iptr node::create(gobject owner) { node_iptr node::create(gobject owner) {
@@ -45,9 +45,9 @@ namespace e2d
} }
node_iptr node::create(gobject owner, const t2f& transform) { node_iptr node::create(gobject owner, const t2f& transform) {
node_iptr n = create(owner); node_iptr child = create(std::move(owner));
n->transform(transform); child->transform(transform);
return n; return child;
} }
node_iptr node::create(gobject owner, const node_iptr& parent) { node_iptr node::create(gobject owner, const node_iptr& parent) {
@@ -59,9 +59,9 @@ namespace e2d
} }
node_iptr node::create(gobject owner, const node_iptr& parent, const t2f& transform) { node_iptr node::create(gobject owner, const node_iptr& parent, const t2f& transform) {
node_iptr n = create(owner, parent); node_iptr child = create(std::move(owner), parent);
n->transform(transform); child->transform(transform);
return n; return child;
} }
void node::owner(gobject owner) noexcept { void node::owner(gobject owner) noexcept {

View File

@@ -30,6 +30,7 @@
#include <enduro2d/high/components/spine_player.hpp> #include <enduro2d/high/components/spine_player.hpp>
#include <enduro2d/high/components/sprite_renderer.hpp> #include <enduro2d/high/components/sprite_renderer.hpp>
#include <enduro2d/high/components/touchable.hpp> #include <enduro2d/high/components/touchable.hpp>
#include <enduro2d/high/components/widget.hpp>
#include <enduro2d/high/systems/camera_system.hpp> #include <enduro2d/high/systems/camera_system.hpp>
#include <enduro2d/high/systems/flipbook_system.hpp> #include <enduro2d/high/systems/flipbook_system.hpp>
@@ -41,6 +42,7 @@
#include <enduro2d/high/systems/script_system.hpp> #include <enduro2d/high/systems/script_system.hpp>
#include <enduro2d/high/systems/spine_system.hpp> #include <enduro2d/high/systems/spine_system.hpp>
#include <enduro2d/high/systems/touch_system.hpp> #include <enduro2d/high/systems/touch_system.hpp>
#include <enduro2d/high/systems/widget_system.hpp>
#include <enduro2d/high/systems/world_system.hpp> #include <enduro2d/high/systems/world_system.hpp>
namespace namespace
@@ -81,6 +83,8 @@ namespace
.add_system<spine_system>()) .add_system<spine_system>())
.feature<struct touch_feature>(ecs::feature() .feature<struct touch_feature>(ecs::feature()
.add_system<touch_system>()) .add_system<touch_system>())
.feature<struct widget_feature>(ecs::feature()
.add_system<widget_system>())
.feature<struct world_feature>(ecs::feature() .feature<struct world_feature>(ecs::feature()
.add_system<world_system>()); .add_system<world_system>());
return !application_ || application_->initialize(); return !application_ || application_->initialize();
@@ -209,6 +213,8 @@ namespace e2d
.register_component<sprite_renderer>("sprite_renderer") .register_component<sprite_renderer>("sprite_renderer")
.register_component<touchable>("touchable") .register_component<touchable>("touchable")
.register_component<events<touchable_events::event>>("touchable.events") .register_component<events<touchable_events::event>>("touchable.events")
.register_component<widget>("widget")
.register_component<widget::dirty>("widget.dirty")
; ;
safe_module_initialize<inspector>() safe_module_initialize<inspector>()
@@ -235,6 +241,8 @@ namespace e2d
.register_component<sprite_renderer>("sprite_renderer") .register_component<sprite_renderer>("sprite_renderer")
.register_component<touchable>("touchable") .register_component<touchable>("touchable")
//.register_component<events<touchable_events::event>>("touchable.events") //.register_component<events<touchable_events::event>>("touchable.events")
.register_component<widget>("widget")
//.register_component<widget::dirty>("widget.dirty")
; ;
safe_module_initialize<luasol>(); safe_module_initialize<luasol>();

View File

@@ -9,6 +9,7 @@
#include <enduro2d/high/components/actor.hpp> #include <enduro2d/high/components/actor.hpp>
#include <enduro2d/high/components/disabled.hpp> #include <enduro2d/high/components/disabled.hpp>
#include <enduro2d/high/components/layout.hpp> #include <enduro2d/high/components/layout.hpp>
#include <enduro2d/high/components/widget.hpp>
#include <3rdparty/yoga/Yoga.h> #include <3rdparty/yoga/Yoga.h>
@@ -21,153 +22,119 @@ namespace
node_ptr as_item{YGNodeNew(), YGNodeFree}; node_ptr as_item{YGNodeNew(), YGNodeFree};
node_ptr as_root{YGNodeNew(), YGNodeFree}; node_ptr as_root{YGNodeNew(), YGNodeFree};
}; };
}
namespace YGDirection convert_to_yogo_direction(layout::directions direction) noexcept {
{ switch ( direction ) {
using namespace e2d; case layout::directions::ltr:
return YGDirectionLTR;
void update_yogo_node(const yogo_node& yn, const layout& l, const actor& a) { case layout::directions::rtl:
switch ( l.direction() ) { return YGDirectionRTL;
case layout::directions::row:
YGNodeStyleSetFlexDirection(yn.as_root.get(), YGFlexDirectionRow);
break;
case layout::directions::row_reversed:
YGNodeStyleSetFlexDirection(yn.as_root.get(), YGFlexDirectionRowReverse);
break;
case layout::directions::column:
YGNodeStyleSetFlexDirection(yn.as_root.get(), YGFlexDirectionColumn);
break;
case layout::directions::column_reversed:
YGNodeStyleSetFlexDirection(yn.as_root.get(), YGFlexDirectionColumnReverse);
break;
default: default:
E2D_ASSERT_MSG(false, "unexpected layout direction"); E2D_ASSERT_MSG(false, "unexpected layout direction");
break; return YGDirectionLTR;
} }
}
switch ( l.direction() ) { YGAlign convert_to_yogo_align(layout::align_modes align_mode) noexcept {
case layout::directions::row: switch ( align_mode ) {
case layout::directions::row_reversed: case layout::align_modes::flex_start:
switch ( l.halign() ) { return YGAlignFlexStart;
case layout::haligns::left: case layout::align_modes::center:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyFlexStart); return YGAlignCenter;
break; case layout::align_modes::flex_end:
case layout::haligns::center: return YGAlignFlexEnd;
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyCenter); case layout::align_modes::space_between:
break; return YGAlignSpaceBetween;
case layout::haligns::right: case layout::align_modes::space_around:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyFlexEnd); return YGAlignSpaceAround;
break;
case layout::haligns::space_around:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifySpaceAround);
break;
case layout::haligns::space_evenly:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifySpaceEvenly);
break;
case layout::haligns::space_between:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifySpaceBetween);
break;
default:
E2D_ASSERT_MSG(false, "unexpected layout halign");
break;
}
switch ( l.valign() ) {
case layout::valigns::top:
case layout::valigns::space_between:
YGNodeStyleSetAlignItems(yn.as_root.get(), YGAlignFlexEnd);
break;
case layout::valigns::center:
case layout::valigns::space_around:
case layout::valigns::space_evenly:
YGNodeStyleSetAlignItems(yn.as_root.get(), YGAlignCenter);
break;
case layout::valigns::bottom:
YGNodeStyleSetAlignItems(yn.as_root.get(), YGAlignFlexStart);
break;
default:
E2D_ASSERT_MSG(false, "unexpected layout valign");
break;
}
break;
case layout::directions::column:
case layout::directions::column_reversed:
switch ( l.valign() ) {
case layout::valigns::top:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyFlexEnd);
break;
case layout::valigns::center:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyCenter);
break;
case layout::valigns::bottom:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyFlexStart);
break;
case layout::valigns::space_around:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifySpaceAround);
break;
case layout::valigns::space_evenly:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifySpaceEvenly);
break;
case layout::valigns::space_between:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifySpaceBetween);
break;
default:
E2D_ASSERT_MSG(false, "unexpected layout valign");
break;
}
switch ( l.halign() ) {
case layout::haligns::left:
case layout::haligns::space_between:
YGNodeStyleSetAlignItems(yn.as_root.get(), YGAlignFlexStart);
break;
case layout::haligns::center:
case layout::haligns::space_around:
case layout::haligns::space_evenly:
YGNodeStyleSetAlignItems(yn.as_root.get(), YGAlignCenter);
break;
case layout::haligns::right:
YGNodeStyleSetAlignItems(yn.as_root.get(), YGAlignFlexEnd);
break;
default:
E2D_ASSERT_MSG(false, "unexpected layout halign");
break;
}
break;
default: default:
E2D_ASSERT_MSG(false, "unexpected layout mode"); E2D_ASSERT_MSG(false, "unexpected layout align mode");
break; return YGAlignFlexStart;
} }
}
{ YGJustify convert_to_yogo_justify(layout::justify_modes justify_mode) noexcept {
YGNodeStyleSetWidth(yn.as_root.get(), l.size().x); switch ( justify_mode ) {
YGNodeStyleSetHeight(yn.as_root.get(), l.size().y); case layout::justify_modes::flex_start:
return YGJustifyFlexStart;
YGNodeStyleSetPadding(yn.as_root.get(), YGEdgeHorizontal, l.padding().x); case layout::justify_modes::center:
YGNodeStyleSetPadding(yn.as_root.get(), YGEdgeVertical, l.padding().y); return YGJustifyCenter;
case layout::justify_modes::flex_end:
return YGJustifyFlexEnd;
case layout::justify_modes::space_between:
return YGJustifySpaceBetween;
case layout::justify_modes::space_around:
return YGJustifySpaceAround;
case layout::justify_modes::space_evenly:
return YGJustifySpaceEvenly;
default:
E2D_ASSERT_MSG(false, "unexpected layout justify mode");
return YGJustifyFlexStart;
} }
}
{ YGWrap convert_to_yogo_flex_wrap(layout::flex_wraps flex_wrap) noexcept {
const v2f& scale = a.node() switch ( flex_wrap ) {
? a.node()->scale() case layout::flex_wraps::no_wrap:
: v2f::unit(); return YGWrapNoWrap;
case layout::flex_wraps::wrap:
YGNodeStyleSetWidth(yn.as_item.get(), l.size().x * scale.x); return YGWrapWrap;
YGNodeStyleSetHeight(yn.as_item.get(), l.size().y * scale.y); case layout::flex_wraps::wrap_reversed:
return YGWrapWrapReverse;
YGNodeStyleSetMargin(yn.as_item.get(), YGEdgeHorizontal, l.margin().x * scale.x); default:
YGNodeStyleSetMargin(yn.as_item.get(), YGEdgeVertical, l.margin().y * scale.y); E2D_ASSERT_MSG(false, "unexpected layout flex wrap");
return YGWrapNoWrap;
} }
} }
YGFlexDirection convert_to_yogo_flex_direction(layout::flex_directions flex_direction) noexcept {
switch ( flex_direction ) {
case layout::flex_directions::row:
return YGFlexDirectionRow;
case layout::flex_directions::row_reversed:
return YGFlexDirectionRowReverse;
case layout::flex_directions::column:
return YGFlexDirectionColumn;
case layout::flex_directions::column_reversed:
return YGFlexDirectionColumnReverse;
default:
E2D_ASSERT_MSG(false, "unexpected layout flex direction");
return YGFlexDirectionRow;
}
}
void update_yogo_layout(const yogo_node& yn, const layout& l, const widget& w) {
YGNodeStyleSetWidth(yn.as_root.get(), w.size().x);
YGNodeStyleSetHeight(yn.as_root.get(), w.size().y);
YGNodeStyleSetPadding(yn.as_root.get(), YGEdgeHorizontal, w.padding().x);
YGNodeStyleSetPadding(yn.as_root.get(), YGEdgeVertical, w.padding().y);
YGNodeStyleSetAlignItems(yn.as_root.get(), convert_to_yogo_align(l.align_items()));
YGNodeStyleSetAlignContent(yn.as_root.get(), convert_to_yogo_align(l.align_content()));
YGNodeStyleSetJustifyContent(yn.as_root.get(), convert_to_yogo_justify(l.justify_content()));
YGNodeStyleSetFlexWrap(yn.as_root.get(), convert_to_yogo_flex_wrap(l.flex_wrap()));
YGNodeStyleSetFlexDirection(yn.as_root.get(), convert_to_yogo_flex_direction(l.flex_direction()));
}
void update_yogo_widget(const yogo_node& yn, const widget& w, const actor& a) {
const v2f& scale = a.node()
? a.node()->scale()
: v2f::unit();
YGNodeStyleSetWidth(yn.as_item.get(), w.size().x * scale.x);
YGNodeStyleSetHeight(yn.as_item.get(), w.size().y * scale.y);
YGNodeStyleSetMargin(yn.as_item.get(), YGEdgeHorizontal, w.margin().x * scale.x);
YGNodeStyleSetMargin(yn.as_item.get(), YGEdgeVertical, w.margin().y * scale.y);
}
} }
namespace namespace
{ {
using namespace e2d; using namespace e2d;
void process_yogo_nodes(ecs::registry& owner) { void update_yogo_nodes(ecs::registry& owner) {
ecsex::remove_all_components_with_disposer<yogo_node>( ecsex::remove_all_components_with_disposer<yogo_node>(
owner, owner,
[](ecs::entity e, const yogo_node&){ [](ecs::entity e, const yogo_node&){
@@ -175,65 +142,65 @@ namespace
a && a->node() && a->node()->owner() ) a && a->node() && a->node()->owner() )
{ {
gcomponent<layout> l{a->node()->owner()}; gcomponent<layout> l{a->node()->owner()};
gcomponent<widget> w{a->node()->owner()};
layouts::mark_dirty(l); layouts::mark_dirty(l);
layouts::mark_dirty(layouts::find_parent_layout(l)); layouts::mark_dirty(widgets::find_parent_layout(w));
} }
}, }, !ecs::exists_all<
!ecs::exists_all<
actor, actor,
layout>() || widget>()
ecs::exists_any< || ecs::exists_any<
disabled<actor>, disabled<actor>,
disabled<layout>>()); disabled<widget>>());
owner.for_joined_components<layout, actor>([]( owner.for_joined_components<widget, actor>([](
ecs::entity e, ecs::entity e,
const layout&, const widget&,
const actor& a) const actor& a)
{ {
e.ensure_component<yogo_node>(); e.ensure_component<yogo_node>();
if ( a.node() && a.node()->owner() ) { if ( a.node() && a.node()->owner() ) {
gcomponent<layout> l{a.node()->owner()}; gcomponent<layout> l{a.node()->owner()};
gcomponent<widget> w{a.node()->owner()};
layouts::mark_dirty(l); layouts::mark_dirty(l);
layouts::mark_dirty(layouts::find_parent_layout(l)); layouts::mark_dirty(widgets::find_parent_layout(w));
} }
}, }, !ecs::exists_any<
!ecs::exists_any<
yogo_node, yogo_node,
disabled<actor>, disabled<actor>,
disabled<layout>>()); disabled<widget>>());
} }
void process_dirty_layouts(ecs::registry& owner) { void update_dirty_layouts(ecs::registry& owner) {
owner.for_joined_components<layout::dirty, yogo_node, layout, actor>([]( owner.for_joined_components<layout::dirty, yogo_node, layout, widget, actor>([](
const ecs::const_entity&, const ecs::const_entity&,
const layout::dirty&, const layout::dirty&,
const yogo_node& root_yn, const yogo_node& root_yn,
const layout& root_l, const layout& root_l,
const widget& root_w,
const actor& root_a) const actor& root_a)
{ {
update_yogo_node(root_yn, root_l, root_a); static thread_local vector<gcomponent<widget>> item_ws;
}); E2D_DEFER([](){ item_ws.clear(); });
owner.for_joined_components<layout::dirty, yogo_node, actor>([]( nodes::extract_components_from_children<widget>(
const ecs::const_entity&,
const layout::dirty&,
const yogo_node& root_yn,
const actor& root_a)
{
static thread_local vector<gcomponent<layout>> items;
E2D_DEFER([](){ items.clear(); });
nodes::extract_components_from_children<layout>(
root_a.node(), root_a.node(),
std::back_inserter(items)); std::back_inserter(item_ws));
E2D_DEFER([&root_yn](){ E2D_DEFER([&root_yn](){
YGNodeRemoveAllChildren(root_yn.as_root.get()); YGNodeRemoveAllChildren(root_yn.as_root.get());
}); });
for ( const auto& item : items ) { update_yogo_layout(root_yn, root_l, root_w);
if ( const auto& item_yn = item.owner().component<yogo_node>() ) {
for ( const auto& item_w : item_ws ) {
const_gcomponent<actor> item_a{item_w.owner()};
const_gcomponent<yogo_node> item_yn{item_w.owner()};
if ( item_a && item_yn ) {
update_yogo_widget(
*item_yn,
*item_w,
*item_a);
YGNodeInsertChild( YGNodeInsertChild(
root_yn.as_root.get(), root_yn.as_root.get(),
item_yn->as_item.get(), item_yn->as_item.get(),
@@ -245,11 +212,11 @@ namespace
root_yn.as_root.get(), root_yn.as_root.get(),
YGUndefined, YGUndefined,
YGUndefined, YGUndefined,
YGDirectionLTR); convert_to_yogo_direction(root_l.direction()));
for ( const auto& item : items ) { for ( const auto& item_w : item_ws ) {
gcomponent<actor> item_a = item.owner().component<actor>(); gcomponent<actor> item_a{item_w.owner()};
const_gcomponent<yogo_node> item_yn = item.owner().component<yogo_node>(); const_gcomponent<yogo_node> item_yn{item_w.owner()};
if ( item_a && item_a->node() && item_yn && item_yn->as_item ) { if ( item_a && item_a->node() && item_yn && item_yn->as_item ) {
item_a->node()->translation(v2f( item_a->node()->translation(v2f(
YGNodeLayoutGetLeft(item_yn->as_item.get()), YGNodeLayoutGetLeft(item_yn->as_item.get()),
@@ -274,8 +241,8 @@ namespace e2d
~internal_state() noexcept = default; ~internal_state() noexcept = default;
void process_update(ecs::registry& owner) { void process_update(ecs::registry& owner) {
process_yogo_nodes(owner); update_yogo_nodes(owner);
process_dirty_layouts(owner); update_dirty_layouts(owner);
} }
}; };

View File

@@ -61,7 +61,7 @@ namespace
// parents // parents
// //
static thread_local std::vector<const_gcomponent<touchable>> parents; static thread_local std::vector<gcomponent<touchable>> parents;
E2D_DEFER([](){ parents.clear(); }); E2D_DEFER([](){ parents.clear(); });
nodes::extract_components_from_parents<touchable>( nodes::extract_components_from_parents<touchable>(
@@ -102,7 +102,7 @@ namespace
disabled<touchable> disabled<touchable>
>()(iter->owner().raw_entity()); >()(iter->owner().raw_entity());
if ( !parent_disabled ) { if ( !parent_disabled ) {
iter->owner().component<events<touchable_events::event>>().ensure().add(event); iter->component<events<touchable_events::event>>().ensure().add(event);
if ( !(*iter)->bubbling() ) { if ( !(*iter)->bubbling() ) {
return; return;
} }

View File

@@ -0,0 +1,71 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <enduro2d/high/systems/widget_system.hpp>
#include <enduro2d/high/components/actor.hpp>
#include <enduro2d/high/components/disabled.hpp>
#include <enduro2d/high/components/layout.hpp>
#include <enduro2d/high/components/widget.hpp>
namespace
{
using namespace e2d;
void update_dirty_widgets(ecs::registry& owner) {
owner.for_joined_components<widget::dirty, widget, actor>([](
const ecs::const_entity&,
const widget::dirty&,
const widget&,
const actor& a)
{
if ( a.node() && a.node()->owner() ) {
gcomponent<layout> l{a.node()->owner()};
gcomponent<widget> w{a.node()->owner()};
layouts::mark_dirty(l);
layouts::mark_dirty(widgets::find_parent_layout(w));
}
}, !ecs::exists_any<
disabled<actor>,
disabled<widget>>());
owner.remove_all_components<widget::dirty>();
}
}
namespace e2d
{
//
// widget_system::internal_state
//
class widget_system::internal_state final : private noncopyable {
public:
internal_state() = default;
~internal_state() noexcept = default;
void process_update(ecs::registry& owner) {
update_dirty_widgets(owner);
}
};
//
// widget_system
//
widget_system::widget_system()
: state_(new internal_state()) {}
widget_system::~widget_system() noexcept = default;
void widget_system::process(
ecs::registry& owner,
const ecs::after<systems::update_event>& trigger)
{
E2D_UNUSED(trigger);
E2D_PROFILER_SCOPE("widget_system.process_update");
state_->process_update(owner);
}
}

View File

@@ -72,7 +72,7 @@ namespace
if ( inst_n ) { if ( inst_n ) {
inst_n->remove_from_parent(); inst_n->remove_from_parent();
while ( node_iptr child = inst_n->first_child() ) { while ( const node_iptr& child = inst_n->first_child() ) {
delete_instance(child->owner()); delete_instance(child->owner());
} }
} }
@@ -85,60 +85,49 @@ namespace
} }
} }
gobject new_instance(world& world, const prefab& prefab) { gobject new_instance(world& world, const prefab& root_prefab) {
gobject inst; ecs::entity ent = world.registry().create_entity(root_prefab.prototype());
ecs::entity ent = world.registry().create_entity(prefab.prototype()); auto ent_defer = make_error_defer([&ent](){
try {
inst = gobject{make_intrusive<gobject_state>(world, ent)};
} catch (...) {
ent.destroy(); ent.destroy();
throw; });
}
try { gobject root_i(make_intrusive<gobject_state>(world, ent));
auto n = node::create(inst); E2D_ERROR_DEFER([&root_i](){
gcomponent<actor> inst_a{inst}; delete_instance(root_i);
if ( inst_a && inst_a->node() ) { });
n->transform(inst_a->node()->transform());
ent_defer.dismiss();
{
gcomponent<actor> root_a{root_i};
node_iptr new_root_node = node::create(root_i);
if ( root_a && root_a->node() ) {
new_root_node->transform(root_a->node()->transform());
} }
inst_a.assign(std::move(n)); root_a.ensure().node(new_root_node);
} catch (...) {
delete_instance(inst);
throw;
} }
try { {
gcomponent<behaviour> inst_b{inst}; gcomponent<behaviour> root_b{root_i};
if ( inst_b && inst_b->script() ) { if ( root_b && root_b->script() ) {
const behaviours::fill_result r = behaviours::fill_meta_table(*inst_b); const behaviours::fill_result r = behaviours::fill_meta_table(*root_b);
if ( r == behaviours::fill_result::failed ) { if ( r == behaviours::fill_result::failed ) {
inst.component<disabled<behaviour>>().ensure(); root_i.component<disabled<behaviour>>().ensure();
} }
} }
} catch (...) {
delete_instance(inst);
throw;
} }
try { for ( const prefab& child_prefab : root_prefab.children() ) {
for ( const auto& child_prefab : prefab.children() ) { gobject child_i = new_instance(world, child_prefab);
auto child = new_instance(world, child_prefab); E2D_ERROR_DEFER([&child_i](){
try { delete_instance(child_i);
gcomponent<actor> inst_a{inst}; });
gcomponent<actor> child_a{child}; gcomponent<actor> root_a{root_i};
inst_a->node()->add_child(child_a->node()); gcomponent<actor> child_a{child_i};
} catch (...) { root_a->node()->add_child(child_a->node());
delete_instance(child);
throw;
}
}
} catch (...) {
delete_instance(inst);
throw;
} }
return inst; return root_i;
} }
void shutdown_instance(gobject& inst) noexcept { void shutdown_instance(gobject& inst) noexcept {
@@ -188,57 +177,64 @@ namespace e2d
} }
gobject world::instantiate() { gobject world::instantiate() {
return instantiate(nullptr); return instantiate(prefab(), nullptr);
} }
gobject world::instantiate(const prefab& prefab) { gobject world::instantiate(const t2f& transform) {
return instantiate(prefab, nullptr); return instantiate(prefab(), nullptr, transform);
} }
gobject world::instantiate(const node_iptr& parent) { gobject world::instantiate(const node_iptr& parent) {
return instantiate(prefab(), parent); return instantiate(prefab(), parent);
} }
gobject world::instantiate(const node_iptr& parent, const t2f& transform) {
return instantiate(prefab(), parent, transform);
}
gobject world::instantiate(const prefab& prefab) {
return instantiate(prefab, nullptr);
}
gobject world::instantiate(const prefab& prefab, const t2f& transform) {
return instantiate(prefab, nullptr, transform);
}
gobject world::instantiate(const prefab& prefab, const node_iptr& parent) { gobject world::instantiate(const prefab& prefab, const node_iptr& parent) {
E2D_PROFILER_SCOPE("world.instantiate"); E2D_PROFILER_SCOPE("world.instantiate");
gobject inst = new_instance(*this, prefab); gobject inst = new_instance(*this, prefab);
E2D_ERROR_DEFER([inst](){
if ( parent ) {
parent->add_child(inst.component<actor>()->node());
}
try {
start_instance(inst);
} catch (...) {
delete_instance(inst); delete_instance(inst);
throw; });
if ( const node_iptr& node = inst.component<actor>()->node() ) {
if ( parent ) {
parent->add_child(node);
}
} }
start_instance(inst);
return inst; return inst;
} }
gobject world::instantiate(const node_iptr& parent, const t2f& transform) {
return instantiate(prefab(), parent, transform);
}
gobject world::instantiate(const prefab& prefab, const node_iptr& parent, const t2f& transform) { gobject world::instantiate(const prefab& prefab, const node_iptr& parent, const t2f& transform) {
E2D_PROFILER_SCOPE("world.instantiate"); E2D_PROFILER_SCOPE("world.instantiate");
gobject inst = new_instance(*this, prefab); gobject inst = new_instance(*this, prefab);
inst.component<actor>()->node()->transform(transform); E2D_ERROR_DEFER([inst](){
if ( parent ) {
parent->add_child(inst.component<actor>()->node());
}
try {
start_instance(inst);
} catch (...) {
delete_instance(inst); delete_instance(inst);
throw; });
if ( const node_iptr& node = inst.component<actor>()->node() ) {
node->transform(transform);
if ( parent ) {
parent->add_child(node);
}
} }
start_instance(inst);
return inst; return inst;
} }