Merge pull request #116 from enduro2d/feature/gui_layouts

Feature/gui layouts
This commit is contained in:
2020-02-15 00:06:36 +07:00
committed by GitHub
78 changed files with 9766 additions and 74 deletions

3
.gitmodules vendored
View File

@@ -55,3 +55,6 @@
[submodule "modules/IconFontCppHeaders"]
path = modules/IconFontCppHeaders
url = https://github.com/juliettef/IconFontCppHeaders
[submodule "modules/yoga"]
path = modules/yoga
url = https://github.com/facebook/yoga

View File

@@ -37,6 +37,7 @@
#include "components/events.hpp"
#include "components/flipbook_player.hpp"
#include "components/label.hpp"
#include "components/layout.hpp"
#include "components/model_renderer.hpp"
#include "components/named.hpp"
#include "components/renderer.hpp"
@@ -50,6 +51,7 @@
#include "systems/frame_system.hpp"
#include "systems/gizmos_system.hpp"
#include "systems/label_system.hpp"
#include "systems/layout_system.hpp"
#include "systems/render_system.hpp"
#include "systems/script_system.hpp"
#include "systems/spine_system.hpp"

View File

@@ -57,6 +57,7 @@ namespace e2d
class events;
class flipbook_player;
class label;
class layout;
class model_renderer;
class named;
class renderer;
@@ -70,6 +71,7 @@ namespace e2d
class frame_system;
class gizmos_system;
class label_system;
class layout_system;
class render_system;
class script_system;
class spine_system;
@@ -128,8 +130,12 @@ namespace sol
namespace e2d::ecsex
{
template < typename T, typename... Opts >
void remove_all_components(ecs::registry& owner, Opts&&... opts) {
template < typename T, typename Disposer, typename... Opts >
void remove_all_components_with_disposer(
ecs::registry& owner,
Disposer&& disposer,
Opts&&... opts)
{
static thread_local vector<ecs::entity> to_remove_components;
E2D_DEFER([](){ to_remove_components.clear(); });
@@ -138,9 +144,18 @@ namespace e2d::ecsex
}, std::forward<Opts>(opts)...);
for ( ecs::entity& e : to_remove_components ) {
std::invoke(disposer, e, e.get_component<T>());
e.remove_component<T>();
}
}
template < typename T, typename... Opts >
void remove_all_components(ecs::registry& owner, Opts&&... opts) {
remove_all_components_with_disposer<T>(
owner,
null_disposer(),
std::forward<Opts>(opts)...);
}
}
namespace e2d::ecsex

View File

@@ -119,6 +119,7 @@ namespace e2d
static const char* title;
void operator()(gcomponent<label>& c) const;
void operator()(gcomponent<label>& c, gizmos_context& ctx) const;
};
}
@@ -226,3 +227,22 @@ namespace e2d
return outline_color_;
}
}
namespace e2d::labels
{
gcomponent<label> mark_dirty(gcomponent<label> self);
gcomponent<label> unmark_dirty(gcomponent<label> self);
bool is_dirty(const const_gcomponent<label>& self) noexcept;
gcomponent<label> change_text(gcomponent<label> self, str value);
gcomponent<label> change_font(gcomponent<label> self, const font_asset::ptr& value);
gcomponent<label> change_tint(gcomponent<label> self, const color32& value);
gcomponent<label> change_halign(gcomponent<label> self, label::haligns value);
gcomponent<label> change_valign(gcomponent<label> self, label::valigns value);
gcomponent<label> change_leading(gcomponent<label> self, f32 value);
gcomponent<label> change_tracking(gcomponent<label> self, f32 value);
gcomponent<label> change_text_width(gcomponent<label> self, f32 value);
gcomponent<label> change_glyph_dilate(gcomponent<label> self, f32 value);
gcomponent<label> change_outline_width(gcomponent<label> self, f32 value);
gcomponent<label> change_outline_color(gcomponent<label> self, const color32& value);
}

View File

@@ -0,0 +1,188 @@
/*******************************************************************************
* 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 layout final {
public:
class dirty final {};
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,
(row)
(row_reversed)
(column)
(column_reversed))
public:
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;
[[nodiscard]] directions direction() const noexcept;
public:
layout& size(const v2f& value) noexcept;
[[nodiscard]] const v2f& size() const noexcept;
layout& margin(const v2f& value) noexcept;
[[nodiscard]] const v2f& margin() const noexcept;
layout& padding(const v2f& value) noexcept;
[[nodiscard]] const v2f& padding() const noexcept;
private:
haligns halign_ = haligns::center;
valigns valign_ = valigns::center;
directions direction_ = directions::row;
private:
v2f size_ = v2f::zero();
v2f margin_ = v2f::zero();
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)
namespace e2d
{
template <>
class factory_loader<layout> final : factory_loader<> {
public:
static const char* schema_source;
bool operator()(
layout& component,
const fill_context& ctx) const;
bool operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const;
};
template <>
class factory_loader<layout::dirty> final : factory_loader<> {
public:
static const char* schema_source;
bool operator()(
layout::dirty& component,
const fill_context& ctx) const;
bool operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const;
};
}
namespace e2d
{
template <>
class component_inspector<layout> final : component_inspector<> {
public:
static const char* title;
void operator()(gcomponent<layout>& c) const;
void operator()(gcomponent<layout>& c, gizmos_context& ctx) const;
};
}
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 {
direction_ = value;
return *this;
}
inline layout::directions layout::direction() const noexcept {
return direction_;
}
inline layout& layout::size(const v2f& value) noexcept {
size_ = value;
return *this;
}
inline const v2f& layout::size() const noexcept {
return size_;
}
inline layout& layout::margin(const v2f& value) noexcept {
margin_ = value;
return *this;
}
inline const v2f& layout::margin() const noexcept {
return margin_;
}
inline layout& layout::padding(const v2f& value) noexcept {
padding_ = value;
return *this;
}
inline const v2f& layout::padding() const noexcept {
return padding_;
}
}
namespace e2d::layouts
{
gcomponent<layout> mark_dirty(gcomponent<layout> self);
gcomponent<layout> unmark_dirty(gcomponent<layout> self);
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_size(gcomponent<layout> self, const v2f& value);
gcomponent<layout> change_margin(gcomponent<layout> self, const v2f& value);
gcomponent<layout> change_padding(gcomponent<layout> self, const v2f& value);
gcomponent<layout> find_parent_layout(const_gcomponent<layout> self) noexcept;
}

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 layout_system final
: public ecs::system<ecs::after<systems::update_event>> {
public:
layout_system();
~layout_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

@@ -179,9 +179,16 @@ namespace e2d
}
//
// (-) mat2
// (+,-) mat2
//
template < typename T >
mat2<T> operator+(const mat2<T>& m) noexcept {
return {
+m.rows[0],
+m.rows[1]};
}
template < typename T >
mat2<T> operator-(const mat2<T>& m) noexcept {
return {

View File

@@ -193,9 +193,17 @@ namespace e2d
}
//
// (-) mat3
// (+,-) mat3
//
template < typename T >
mat3<T> operator+(const mat3<T>& m) noexcept {
return {
+m.rows[0],
+m.rows[1],
+m.rows[2]};
}
template < typename T >
mat3<T> operator-(const mat3<T>& m) noexcept {
return {

View File

@@ -210,9 +210,18 @@ namespace e2d
}
//
// (-) mat4
// (+,-) mat4
//
template < typename T >
mat4<T> operator+(const mat4<T>& m) noexcept {
return {
+m.rows[0],
+m.rows[1],
+m.rows[2],
+m.rows[3]};
}
template < typename T >
mat4<T> operator-(const mat4<T>& m) noexcept {
return {

View File

@@ -167,9 +167,16 @@ namespace e2d
}
//
// (-) unit
// (+,-) unit
//
template < typename T, typename Tag >
unit<T, Tag> operator+(const unit<T, Tag>& u) noexcept {
return {
+u.value,
Tag{}};
}
template < typename T, typename Tag >
unit<T, Tag> operator-(const unit<T, Tag>& u) noexcept {
return {

View File

@@ -260,9 +260,16 @@ namespace e2d
}
//
// (-) vec2
// (+,-) vec2
//
template < typename T >
vec2<T> operator+(const vec2<T>& v) noexcept {
return {
+v.x,
+v.y};
}
template < typename T >
vec2<T> operator-(const vec2<T>& v) noexcept {
return {

View File

@@ -283,9 +283,17 @@ namespace e2d
}
//
// (-) vec3
// (+,-) vec3
//
template < typename T >
vec3<T> operator+(const vec3<T>& v) noexcept {
return {
+v.x,
+v.y,
+v.z};
}
template < typename T >
vec3<T> operator-(const vec3<T>& v) noexcept {
return {

View File

@@ -306,9 +306,18 @@ namespace e2d
}
//
// (-) vec4
// (+,-) vec4
//
template < typename T >
vec4<T> operator+(const vec4<T>& v) noexcept {
return {
+v.x,
+v.y,
+v.z,
+v.w};
}
template < typename T >
vec4<T> operator-(const vec4<T>& v) noexcept {
return {

View File

@@ -18,19 +18,72 @@ namespace e2d
explicit defer_impl(F f)
: f_(std::move(f)) {}
~defer_impl() noexcept(std::is_nothrow_invocable_v<F>) {
~defer_impl() noexcept {
f_();
}
private:
F f_;
};
template < typename F >
class error_defer_impl final : noncopyable {
public:
explicit error_defer_impl(F f)
: f_(std::move(f))
, exceptions_(std::uncaught_exceptions()) {}
~error_defer_impl() noexcept {
if ( exceptions_ != std::uncaught_exceptions() ) {
f_();
}
}
private:
F f_{};
int exceptions_{};
};
template < typename F >
class return_defer_impl final : noncopyable {
public:
explicit return_defer_impl(F f)
: f_(std::move(f))
, exceptions_(std::uncaught_exceptions()) {}
~return_defer_impl() noexcept {
if ( exceptions_ == std::uncaught_exceptions() ) {
f_();
}
}
private:
F f_{};
int exceptions_{};
};
}
template < typename F >
impl::defer_impl<std::decay_t<F>> make_defer(F&& f) {
return impl::defer_impl<std::decay_t<F>>(std::forward<F>(f));
}
template < typename F >
impl::error_defer_impl<std::decay_t<F>> make_error_defer(F&& f) {
return impl::error_defer_impl<std::decay_t<F>>(std::forward<F>(f));
}
template < typename F >
impl::return_defer_impl<std::decay_t<F>> make_return_defer(F&& f) {
return impl::return_defer_impl<std::decay_t<F>>(std::forward<F>(f));
}
}
#define E2D_DEFER(lambda)\
auto E2D_PP_CAT(e2d_generated_defer_, __LINE__) = ::e2d::make_defer(lambda)
auto E2D_PP_CAT(e2d_generated_defer_, __LINE__) =\
::e2d::make_defer(lambda)
#define E2D_ERROR_DEFER(lambda)\
auto E2D_PP_CAT(e2d_generated_error_defer_, __LINE__) =\
::e2d::make_error_defer(lambda)
#define E2D_RETURN_DEFER(lambda)\
auto E2D_PP_CAT(e2d_generated_return_defer_, __LINE__) =\
::e2d::make_return_defer(lambda)

1
modules/yoga Submodule

Submodule modules/yoga added at 0be0e9fc01

View File

@@ -47,3 +47,4 @@ add_e2d_sample(05)
add_e2d_sample(06)
add_e2d_sample(07)
add_e2d_sample(08)
add_e2d_sample(09)

View File

@@ -1,5 +1,9 @@
{
"components" : {},
"components" : {
"named" : {
"name" : "background"
}
},
"children" : [{
"prototype" : "sprite_prefab.json",
"components" : {

View File

@@ -4,7 +4,8 @@
"name" : "camera"
},
"camera" : {
"background" : [1.0, 0.4, 0.0, 1.0]
"background" : [1.0, 0.4, 0.0, 1.0],
"mode" : "fixed_crop"
},
"camera.input" : {},
"camera.gizmos" : {}

View File

@@ -1,6 +1,9 @@
{
"prototype" : "spine_prefab.json",
"components" : {
"named" : {
"name" : "coin"
},
"spine_player" : {
"spine" : "../spines/coin_spine.json"
},

View File

@@ -1,6 +1,9 @@
{
"prototype" : "spine_prefab.json",
"components" : {
"named" : {
"name" : "dragon"
},
"spine_player" : {
"spine" : "../spines/dragon_spine.json"
},

View File

@@ -1,6 +1,9 @@
{
"prototype" : "model_prefab.json",
"components" : {
"named" : {
"name" : "gnome"
},
"renderer" : {
"materials" : [
"../models/gnome/gnome_material.json"

View File

@@ -1,5 +1,8 @@
{
"components" : {
"named" : {
"name" : "label"
},
"renderer" : {
"materials" : [
"../materials/font_bm_material.json"

View File

@@ -1,5 +1,8 @@
{
"components" : {
"named" : {
"name" : "label"
},
"renderer" : {
"materials" : [
"../materials/font_sdf_material.json"

View File

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

View File

@@ -1,5 +1,8 @@
{
"components" : {
"named" : {
"name" : "model"
},
"renderer" : {},
"model_renderer" : {}
}

View File

@@ -1,6 +1,9 @@
{
"prototype" : "spine_prefab.json",
"components" : {
"named" : {
"name" : "raptor"
},
"spine_player" : {
"spine" : "../spines/raptor_spine.json"
},

View File

@@ -0,0 +1,8 @@
{
"components" : {
"named" : {
"name" : "scene"
},
"scene" : {}
}
}

View File

@@ -1,6 +1,9 @@
{
"prototype" : "sprite_prefab.json",
"components" : {
"named" : {
"name" : "ship"
},
"sprite_renderer" : {
"sprite" : "../sprites/ship_sprite.json"
}

View File

@@ -1,5 +1,8 @@
{
"components" : {
"named" : {
"name" : "spine"
},
"renderer" : {},
"spine_player" : {
"materials" : {

View File

@@ -1,5 +1,8 @@
{
"components" : {
"named" : {
"name" : "sprite"
},
"renderer" : {},
"sprite_renderer" : {
"materials" : {

View File

@@ -1,7 +1,5 @@
{
"components" : {
"scene" : {}
},
"prototype" : "../prefabs/scene_prefab.json",
"children" : [{
"prototype" : "../prefabs/camera_prefab.json",
"components" : {

View File

@@ -1,7 +1,5 @@
{
"components" : {
"scene" : {}
},
"prototype" : "../prefabs/scene_prefab.json",
"children" : [{
"prototype" : "../prefabs/camera_prefab.json"
},{

View File

@@ -1,6 +1,6 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"components" : {
"scene" : {},
"behaviour" : {
"script" : "../scripts/sample_07/sample_07.lua"
}

View File

@@ -1,9 +1,6 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"components" : {
"named" : {
"name" : "scene"
},
"scene" : {},
"behaviour" : {
"script" : "../scripts/sample_08/sample_08.lua"
}

View File

@@ -0,0 +1,65 @@
{
"prototype" : "../prefabs/scene_prefab.json",
"children" : [{
"prototype" : "../prefabs/background_prefab.json"
},{
"prototype" : "../prefabs/camera_prefab.json"
},{
"prototype" : "../prefabs/layout_prefab.json",
"components" : {
"actor" : {
"translation" : [-250,0]
},
"layout" : {
"size" : [500,200],
"halign" : "space_evenly"
}
},
"children" : [{
"prototype" : "../prefabs/layout_prefab.json",
"components" : {
"layout" : {
"size" : [66,113]
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"components" : {
"actor" : {
"translation" : [33,56.5]
}
}
}]
},{
"prototype" : "../prefabs/layout_prefab.json",
"components" : {
"layout" : {
"size" : [66,113]
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"components" : {
"actor" : {
"translation" : [33,56.5]
}
}
}]
},{
"prototype" : "../prefabs/layout_prefab.json",
"components" : {
"layout" : {
"size" : [66,113]
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"components" : {
"actor" : {
"translation" : [33,56.5]
}
}
}]
}]
}]
}

View File

@@ -1,5 +1,8 @@
---@class label
local label = {
---@type boolean
dirty = false,
---@type string
text = "",

View File

@@ -0,0 +1,68 @@
---@class layout
local layout = {
---@type boolean
enabled = true,
---@type boolean
disabled = false,
---@type boolean
dirty = false,
---@type layout_haligns
halign = layout.haligns.center,
---@type layout_valigns
valign = layout.valigns.center,
---@type layout_directions
direction = layout.directions.row,
---@type v2f
size = v2f.zero(),
---@type v2f
margin = v2f.zero(),
---@type v2f
padding = v2f.zero()
}
---@class layout_haligns
layout.haligns = {
left = "left",
center = "center",
right = "right",
space_around = "space_around",
space_evenly = "space_evenly",
space_between = "space_between"
}
---@class layout_valigns
layout.valigns = {
top = "top",
center = "center",
bottom = "bottom",
space_around = "space_around",
space_evenly = "space_evenly",
space_between = "space_between"
}
---@class layout_directions
layout.directions = {
row = "row",
row_reversed = "row_reversed",
column = "column",
column_reversed = "column_reversed"
}
---@overload fun(self: layout)
---@param self layout
function layout.enable(self) end
---@overload fun(self: layout)
---@param self layout
function layout.disable(self) end
---@type layout
_G.layout = _G.layout or layout

View File

@@ -30,6 +30,9 @@ local gobject = {
---@type label
label = nil,
---@type layout
layout = nil,
---@type model_renderer
model_renderer = nil,

View File

@@ -0,0 +1,69 @@
/*******************************************************************************
* 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 "../common.hpp"
using namespace e2d;
namespace
{
class game_system final : public systems::update_system {
public:
void process(
ecs::registry& owner,
const systems::update_event& event) override
{
E2D_UNUSED(owner, event);
const keyboard& k = the<input>().keyboard();
if ( k.is_key_just_released(keyboard_key::f12) ) {
the<dbgui>().toggle_visible(!the<dbgui>().visible());
}
if ( k.is_key_just_released(keyboard_key::escape) ) {
the<window>().set_should_close(true);
}
if ( k.is_key_pressed(keyboard_key::lsuper) && k.is_key_just_released(keyboard_key::enter) ) {
the<window>().toggle_fullscreen(!the<window>().fullscreen());
}
}
};
class game final : public starter::application {
public:
bool initialize() final {
return create_scene()
&& create_systems();
}
private:
bool create_scene() {
auto scene_prefab_res = the<library>().load_asset<prefab_asset>("scenes/sample_09.json");
auto scene_go = scene_prefab_res
? the<world>().instantiate(scene_prefab_res->content())
: gobject();
return scene_go.valid();
}
bool create_systems() {
ecs::registry_filler(the<world>().registry())
.feature<struct game_feature>(ecs::feature()
.add_system<game_system>());
return true;
}
};
}
int e2d_main(int argc, char *argv[]) {
const auto starter_params = starter::parameters(
engine::parameters("sample_09", "enduro2d")
.window_params(engine::window_parameters()
.size({1024, 512}))
.timer_params(engine::timer_parameters()
.maximal_framerate(100)));
modules::initialize<starter>(argc, argv, starter_params).start<game>();
modules::shutdown<starter>();
return 0;
}

View File

@@ -123,3 +123,6 @@ cp -fv $MODULES_DIR/stb/stb_truetype.h $SOURCES_RDPARTY_DIR/stb/stb_truetype.h
mkdir -p $SOURCES_RDPARTY_DIR/utfcpp
cp -rfv $MODULES_DIR/utfcpp/source/. $SOURCES_RDPARTY_DIR/utfcpp/
mkdir -p $SOURCES_RDPARTY_DIR/yoga
cp -rfv $MODULES_DIR/yoga/yoga/. $SOURCES_RDPARTY_DIR/yoga/

145
sources/3rdparty/yoga/Bitfield.h vendored Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cstddef>
#include <limits>
#include <type_traits>
#include <yoga/YGEnums.h>
namespace facebook {
namespace yoga {
namespace detail {
constexpr size_t log2ceil(size_t n) {
return n < 1 ? 0 : (1 + log2ceil(n / 2));
}
// The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL
template <typename Enum>
constexpr size_t bitWidth() {
static_assert(
enums::count<Enum>() > 0, "Enums must have at least one entries");
return log2ceil(enums::count<Enum>() - 1);
}
// Number of bits needed for a boolean
template <>
constexpr size_t bitWidth<bool>() {
return 1;
}
template <typename U, typename... Ts>
struct BitTraits {};
template <typename U>
struct BitTraits<U> {
// Base cases
static constexpr size_t width(size_t) { return 0; }
static constexpr size_t shift(size_t) { return 0; }
};
template <typename U, typename T, typename... Ts>
struct BitTraits<U, T, Ts...> {
using Rest = BitTraits<U, Ts...>;
static constexpr size_t width(size_t idx) {
return idx == 0 ? bitWidth<T>() : Rest::width(idx - 1);
}
static constexpr size_t shift(size_t idx) {
return idx == 0 ? Rest::width(0) + Rest::shift(0) : Rest::shift(idx - 1);
}
static constexpr U mask(size_t idx) {
return ((U{1} << width(idx)) - 1) << shift(idx);
}
};
template <size_t Idx, typename T, typename... Ts>
struct IndexedType {
using Type = typename IndexedType<Idx - 1, Ts...>::Type;
};
template <typename T, typename... Ts>
struct IndexedType<0, T, Ts...> {
using Type = T;
};
} // namespace detail
template <typename Storage, typename... Fields>
class Bitfield {
static_assert(
std::is_integral<Storage>::value,
"Bitfield needs an integral storage type");
static_assert(
std::is_unsigned<Storage>::value,
"Bitfield needs an unsigned storage type");
static_assert(sizeof...(Fields) > 0, "Bitfield needs at least one member");
using BitTraits = detail::BitTraits<Storage, Fields...>;
#if !defined(_MSC_VER) || _MSC_VER > 1914
static_assert(
BitTraits::shift(0) + BitTraits::width(0) <=
std::numeric_limits<Storage>::digits,
"Specified storage type is too narrow to hold all types");
#endif
template <size_t Idx>
using TypeAt = typename detail::IndexedType<Idx, Fields...>::Type;
template <size_t Idx, typename Value, typename... Values>
static constexpr Storage initStorage(Value value, Values... values) {
return ((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx)) |
initStorage<Idx + 1, Values...>(values...);
}
template <size_t Idx>
static constexpr Storage initStorage() {
return Storage{0};
}
Storage storage_ = 0;
public:
template <size_t Idx>
class Ref {
Bitfield& bitfield_;
public:
Ref(Bitfield& bitfield) : bitfield_(bitfield) {}
Ref& operator=(TypeAt<Idx> value) {
bitfield_.storage_ = (bitfield_.storage_ & ~BitTraits::mask(Idx)) |
((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx));
return *this;
}
operator TypeAt<Idx>() const {
return const_cast<const Bitfield&>(bitfield_).at<Idx>();
}
};
constexpr Bitfield() = default;
constexpr Bitfield(Fields... values) : storage_{initStorage<0>(values...)} {}
template <size_t Idx>
constexpr TypeAt<Idx> at() const {
return static_cast<TypeAt<Idx>>(
(storage_ & BitTraits::mask(Idx)) >> BitTraits::shift(Idx));
}
template <size_t Idx>
Ref<Idx> at() {
return {*this};
}
};
} // namespace yoga
} // namespace facebook

184
sources/3rdparty/yoga/CompactValue.h vendored Normal file
View File

@@ -0,0 +1,184 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "YGValue.h"
#include "YGMacros.h"
#include <cmath>
#include <cstdint>
#include <limits>
static_assert(
std::numeric_limits<float>::is_iec559,
"facebook::yoga::detail::CompactValue only works with IEEE754 floats");
#ifdef YOGA_COMPACT_VALUE_TEST
#define VISIBLE_FOR_TESTING public:
#else
#define VISIBLE_FOR_TESTING private:
#endif
namespace facebook {
namespace yoga {
namespace detail {
// This class stores YGValue in 32 bits.
// - The value does not matter for Undefined and Auto. NaNs are used for their
// representation.
// - To differentiate between Point and Percent, one exponent bit is used.
// Supported the range [0x40, 0xbf] (0xbf is inclusive for point, but
// exclusive for percent).
// - Value ranges:
// points: 1.08420217e-19f to 36893485948395847680
// 0x00000000 0x3fffffff
// percent: 1.08420217e-19f to 18446742974197923840
// 0x40000000 0x7f7fffff
// - Zero is supported, negative zero is not
// - values outside of the representable range are clamped
class YOGA_EXPORT CompactValue {
friend constexpr bool operator==(CompactValue, CompactValue) noexcept;
public:
static constexpr auto LOWER_BOUND = 1.08420217e-19f;
static constexpr auto UPPER_BOUND_POINT = 36893485948395847680.0f;
static constexpr auto UPPER_BOUND_PERCENT = 18446742974197923840.0f;
template <YGUnit Unit>
static CompactValue of(float value) noexcept {
if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) {
constexpr auto zero =
Unit == YGUnitPercent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT;
return {Payload{zero}};
}
constexpr auto upperBound =
Unit == YGUnitPercent ? UPPER_BOUND_PERCENT : UPPER_BOUND_POINT;
if (value > upperBound || value < -upperBound) {
value = copysignf(upperBound, value);
}
uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0;
auto data = Payload{value};
data.repr -= BIAS;
data.repr |= unitBit;
return {data};
}
template <YGUnit Unit>
static CompactValue ofMaybe(float value) noexcept {
return std::isnan(value) || std::isinf(value) ? ofUndefined()
: of<Unit>(value);
}
static constexpr CompactValue ofZero() noexcept {
return CompactValue{Payload{ZERO_BITS_POINT}};
}
static constexpr CompactValue ofUndefined() noexcept {
return CompactValue{};
}
static constexpr CompactValue ofAuto() noexcept {
return CompactValue{Payload{AUTO_BITS}};
}
constexpr CompactValue() noexcept
: payload_(std::numeric_limits<float>::quiet_NaN()) {}
CompactValue(const YGValue& x) noexcept : payload_(uint32_t{0}) {
switch (x.unit) {
case YGUnitUndefined:
*this = ofUndefined();
break;
case YGUnitAuto:
*this = ofAuto();
break;
case YGUnitPoint:
*this = of<YGUnitPoint>(x.value);
break;
case YGUnitPercent:
*this = of<YGUnitPercent>(x.value);
break;
}
}
operator YGValue() const noexcept {
switch (payload_.repr) {
case AUTO_BITS:
return YGValueAuto;
case ZERO_BITS_POINT:
return YGValue{0.0f, YGUnitPoint};
case ZERO_BITS_PERCENT:
return YGValue{0.0f, YGUnitPercent};
}
if (std::isnan(payload_.value)) {
return YGValueUndefined;
}
auto data = payload_;
data.repr &= ~PERCENT_BIT;
data.repr += BIAS;
return YGValue{data.value,
payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint};
}
bool isUndefined() const noexcept {
return (
payload_.repr != AUTO_BITS && payload_.repr != ZERO_BITS_POINT &&
payload_.repr != ZERO_BITS_PERCENT && std::isnan(payload_.value));
}
bool isAuto() const noexcept { return payload_.repr == AUTO_BITS; }
private:
union Payload {
float value;
uint32_t repr;
Payload() = delete;
constexpr Payload(uint32_t r) : repr(r) {}
constexpr Payload(float v) : value(v) {}
};
static constexpr uint32_t BIAS = 0x20000000;
static constexpr uint32_t PERCENT_BIT = 0x40000000;
// these are signaling NaNs with specific bit pattern as payload they will be
// silenced whenever going through an FPU operation on ARM + x86
static constexpr uint32_t AUTO_BITS = 0x7faaaaaa;
static constexpr uint32_t ZERO_BITS_POINT = 0x7f8f0f0f;
static constexpr uint32_t ZERO_BITS_PERCENT = 0x7f80f0f0;
constexpr CompactValue(Payload data) noexcept : payload_(data) {}
Payload payload_;
VISIBLE_FOR_TESTING uint32_t repr() { return payload_.repr; }
};
template <>
CompactValue CompactValue::of<YGUnitUndefined>(float) noexcept = delete;
template <>
CompactValue CompactValue::of<YGUnitAuto>(float) noexcept = delete;
template <>
CompactValue CompactValue::ofMaybe<YGUnitUndefined>(float) noexcept = delete;
template <>
CompactValue CompactValue::ofMaybe<YGUnitAuto>(float) noexcept = delete;
constexpr bool operator==(CompactValue a, CompactValue b) noexcept {
return a.payload_.repr == b.payload_.repr;
}
constexpr bool operator!=(CompactValue a, CompactValue b) noexcept {
return !(a == b);
}
} // namespace detail
} // namespace yoga
} // namespace facebook

67
sources/3rdparty/yoga/Utils.cpp vendored Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "Utils.h"
using namespace facebook;
YGFlexDirection YGFlexDirectionCross(
const YGFlexDirection flexDirection,
const YGDirection direction) {
return YGFlexDirectionIsColumn(flexDirection)
? YGResolveFlexDirection(YGFlexDirectionRow, direction)
: YGFlexDirectionColumn;
}
float YGFloatMax(const float a, const float b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fmaxf(a, b);
}
return yoga::isUndefined(a) ? b : a;
}
float YGFloatMin(const float a, const float b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fminf(a, b);
}
return yoga::isUndefined(a) ? b : a;
}
bool YGValueEqual(const YGValue& a, const YGValue& b) {
if (a.unit != b.unit) {
return false;
}
if (a.unit == YGUnitUndefined ||
(yoga::isUndefined(a.value) && yoga::isUndefined(b.value))) {
return true;
}
return fabs(a.value - b.value) < 0.0001f;
}
bool YGFloatsEqual(const float a, const float b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fabs(a - b) < 0.0001f;
}
return yoga::isUndefined(a) && yoga::isUndefined(b);
}
float YGFloatSanitize(const float val) {
return yoga::isUndefined(val) ? 0 : val;
}
YGFloatOptional YGFloatOptionalMax(YGFloatOptional op1, YGFloatOptional op2) {
if (op1 >= op2) {
return op1;
}
if (op2 > op1) {
return op2;
}
return op1.isUndefined() ? op2 : op1;
}

143
sources/3rdparty/yoga/Utils.h vendored Normal file
View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "YGNode.h"
#include "Yoga-internal.h"
#include "CompactValue.h"
// This struct is an helper model to hold the data for step 4 of flexbox algo,
// which is collecting the flex items in a line.
//
// - itemsOnLine: Number of items which can fit in a line considering the
// available Inner dimension, the flex items computed flexbasis and their
// margin. It may be different than the difference between start and end
// indicates because we skip over absolute-positioned items.
//
// - sizeConsumedOnCurrentLine: It is accumulation of the dimensions and margin
// of all the children on the current line. This will be used in order to
// either set the dimensions of the node if none already exist or to compute
// the remaining space left for the flexible children.
//
// - totalFlexGrowFactors: total flex grow factors of flex items which are to be
// layed in the current line
//
// - totalFlexShrinkFactors: total flex shrink factors of flex items which are
// to be layed in the current line
//
// - endOfLineIndex: Its the end index of the last flex item which was examined
// and it may or may not be part of the current line(as it may be absolutely
// positioned or including it may have caused to overshoot availableInnerDim)
//
// - relativeChildren: Maintain a vector of the child nodes that can shrink
// and/or grow.
struct YGCollectFlexItemsRowValues {
uint32_t itemsOnLine;
float sizeConsumedOnCurrentLine;
float totalFlexGrowFactors;
float totalFlexShrinkScaledFactors;
uint32_t endOfLineIndex;
std::vector<YGNodeRef> relativeChildren;
float remainingFreeSpace;
// The size of the mainDim for the row after considering size, padding, margin
// and border of flex items. This is used to calculate maxLineDim after going
// through all the rows to decide on the main axis size of owner.
float mainDim;
// The size of the crossDim for the row after considering size, padding,
// margin and border of flex items. Used for calculating containers crossSize.
float crossDim;
};
bool YGValueEqual(const YGValue& a, const YGValue& b);
inline bool YGValueEqual(
facebook::yoga::detail::CompactValue a,
facebook::yoga::detail::CompactValue b) {
return YGValueEqual((YGValue) a, (YGValue) b);
}
// This custom float equality function returns true if either absolute
// difference between two floats is less than 0.0001f or both are undefined.
bool YGFloatsEqual(const float a, const float b);
float YGFloatMax(const float a, const float b);
YGFloatOptional YGFloatOptionalMax(
const YGFloatOptional op1,
const YGFloatOptional op2);
float YGFloatMin(const float a, const float b);
// This custom float comparison function compares the array of float with
// YGFloatsEqual, as the default float comparison operator will not work(Look
// at the comments of YGFloatsEqual function).
template <std::size_t size>
bool YGFloatArrayEqual(
const std::array<float, size>& val1,
const std::array<float, size>& val2) {
bool areEqual = true;
for (std::size_t i = 0; i < size && areEqual; ++i) {
areEqual = YGFloatsEqual(val1[i], val2[i]);
}
return areEqual;
}
// This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise
float YGFloatSanitize(const float val);
YGFlexDirection YGFlexDirectionCross(
const YGFlexDirection flexDirection,
const YGDirection direction);
inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) {
return flexDirection == YGFlexDirectionRow ||
flexDirection == YGFlexDirectionRowReverse;
}
inline YGFloatOptional YGResolveValue(
const YGValue value,
const float ownerSize) {
switch (value.unit) {
case YGUnitPoint:
return YGFloatOptional{value.value};
case YGUnitPercent:
return YGFloatOptional{value.value * ownerSize * 0.01f};
default:
return YGFloatOptional{};
}
}
inline YGFloatOptional YGResolveValue(
yoga::detail::CompactValue value,
float ownerSize) {
return YGResolveValue((YGValue) value, ownerSize);
}
inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) {
return flexDirection == YGFlexDirectionColumn ||
flexDirection == YGFlexDirectionColumnReverse;
}
inline YGFlexDirection YGResolveFlexDirection(
const YGFlexDirection flexDirection,
const YGDirection direction) {
if (direction == YGDirectionRTL) {
if (flexDirection == YGFlexDirectionRow) {
return YGFlexDirectionRowReverse;
} else if (flexDirection == YGFlexDirectionRowReverse) {
return YGFlexDirectionRow;
}
}
return flexDirection;
}
inline YGFloatOptional YGResolveValueMargin(
yoga::detail::CompactValue value,
const float ownerSize) {
return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize);
}

44
sources/3rdparty/yoga/YGConfig.cpp vendored Normal file
View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGConfig.h"
YGConfig::YGConfig(YGLogger logger) : cloneNodeCallback_{nullptr} {
logger_.noContext = logger;
loggerUsesContext_ = false;
}
void YGConfig::log(
YGConfig* config,
YGNode* node,
YGLogLevel logLevel,
void* logContext,
const char* format,
va_list args) {
if (loggerUsesContext_) {
logger_.withContext(config, node, logLevel, logContext, format, args);
} else {
logger_.noContext(config, node, logLevel, format, args);
}
}
YGNodeRef YGConfig::cloneNode(
YGNodeRef node,
YGNodeRef owner,
int childIndex,
void* cloneContext) {
YGNodeRef clone = nullptr;
if (cloneNodeCallback_.noContext != nullptr) {
clone = cloneNodeUsesContext_
? cloneNodeCallback_.withContext(node, owner, childIndex, cloneContext)
: cloneNodeCallback_.noContext(node, owner, childIndex);
}
if (clone == nullptr) {
clone = YGNodeClone(node);
}
return clone;
}

76
sources/3rdparty/yoga/YGConfig.h vendored Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "Yoga-internal.h"
#include "Yoga.h"
struct YOGA_EXPORT YGConfig {
using LogWithContextFn = int (*)(
YGConfigRef config,
YGNodeRef node,
YGLogLevel level,
void* context,
const char* format,
va_list args);
using CloneWithContextFn = YGNodeRef (*)(
YGNodeRef node,
YGNodeRef owner,
int childIndex,
void* cloneContext);
private:
union {
CloneWithContextFn withContext;
YGCloneNodeFunc noContext;
} cloneNodeCallback_;
union {
LogWithContextFn withContext;
YGLogger noContext;
} logger_;
bool cloneNodeUsesContext_;
bool loggerUsesContext_;
public:
bool useWebDefaults = false;
bool useLegacyStretchBehaviour = false;
bool shouldDiffLayoutWithoutLegacyStretchBehaviour = false;
bool printTree = false;
float pointScaleFactor = 1.0f;
std::array<bool, facebook::yoga::enums::count<YGExperimentalFeature>()>
experimentalFeatures = {};
void* context = nullptr;
YGConfig(YGLogger logger);
void log(YGConfig*, YGNode*, YGLogLevel, void*, const char*, va_list);
void setLogger(YGLogger logger) {
logger_.noContext = logger;
loggerUsesContext_ = false;
}
void setLogger(LogWithContextFn logger) {
logger_.withContext = logger;
loggerUsesContext_ = true;
}
void setLogger(std::nullptr_t) { setLogger(YGLogger{nullptr}); }
YGNodeRef cloneNode(
YGNodeRef node,
YGNodeRef owner,
int childIndex,
void* cloneContext);
void setCloneNodeCallback(YGCloneNodeFunc cloneNode) {
cloneNodeCallback_.noContext = cloneNode;
cloneNodeUsesContext_ = false;
}
void setCloneNodeCallback(CloneWithContextFn cloneNode) {
cloneNodeCallback_.withContext = cloneNode;
cloneNodeUsesContext_ = true;
}
void setCloneNodeCallback(std::nullptr_t) {
setCloneNodeCallback(YGCloneNodeFunc{nullptr});
}
};

226
sources/3rdparty/yoga/YGEnums.cpp vendored Normal file
View File

@@ -0,0 +1,226 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGEnums.h"
const char* YGAlignToString(const YGAlign value) {
switch (value) {
case YGAlignAuto:
return "auto";
case YGAlignFlexStart:
return "flex-start";
case YGAlignCenter:
return "center";
case YGAlignFlexEnd:
return "flex-end";
case YGAlignStretch:
return "stretch";
case YGAlignBaseline:
return "baseline";
case YGAlignSpaceBetween:
return "space-between";
case YGAlignSpaceAround:
return "space-around";
}
return "unknown";
}
const char* YGDimensionToString(const YGDimension value) {
switch (value) {
case YGDimensionWidth:
return "width";
case YGDimensionHeight:
return "height";
}
return "unknown";
}
const char* YGDirectionToString(const YGDirection value) {
switch (value) {
case YGDirectionInherit:
return "inherit";
case YGDirectionLTR:
return "ltr";
case YGDirectionRTL:
return "rtl";
}
return "unknown";
}
const char* YGDisplayToString(const YGDisplay value) {
switch (value) {
case YGDisplayFlex:
return "flex";
case YGDisplayNone:
return "none";
}
return "unknown";
}
const char* YGEdgeToString(const YGEdge value) {
switch (value) {
case YGEdgeLeft:
return "left";
case YGEdgeTop:
return "top";
case YGEdgeRight:
return "right";
case YGEdgeBottom:
return "bottom";
case YGEdgeStart:
return "start";
case YGEdgeEnd:
return "end";
case YGEdgeHorizontal:
return "horizontal";
case YGEdgeVertical:
return "vertical";
case YGEdgeAll:
return "all";
}
return "unknown";
}
const char* YGExperimentalFeatureToString(const YGExperimentalFeature value) {
switch (value) {
case YGExperimentalFeatureWebFlexBasis:
return "web-flex-basis";
}
return "unknown";
}
const char* YGFlexDirectionToString(const YGFlexDirection value) {
switch (value) {
case YGFlexDirectionColumn:
return "column";
case YGFlexDirectionColumnReverse:
return "column-reverse";
case YGFlexDirectionRow:
return "row";
case YGFlexDirectionRowReverse:
return "row-reverse";
}
return "unknown";
}
const char* YGJustifyToString(const YGJustify value) {
switch (value) {
case YGJustifyFlexStart:
return "flex-start";
case YGJustifyCenter:
return "center";
case YGJustifyFlexEnd:
return "flex-end";
case YGJustifySpaceBetween:
return "space-between";
case YGJustifySpaceAround:
return "space-around";
case YGJustifySpaceEvenly:
return "space-evenly";
}
return "unknown";
}
const char* YGLogLevelToString(const YGLogLevel value) {
switch (value) {
case YGLogLevelError:
return "error";
case YGLogLevelWarn:
return "warn";
case YGLogLevelInfo:
return "info";
case YGLogLevelDebug:
return "debug";
case YGLogLevelVerbose:
return "verbose";
case YGLogLevelFatal:
return "fatal";
}
return "unknown";
}
const char* YGMeasureModeToString(const YGMeasureMode value) {
switch (value) {
case YGMeasureModeUndefined:
return "undefined";
case YGMeasureModeExactly:
return "exactly";
case YGMeasureModeAtMost:
return "at-most";
}
return "unknown";
}
const char* YGNodeTypeToString(const YGNodeType value) {
switch (value) {
case YGNodeTypeDefault:
return "default";
case YGNodeTypeText:
return "text";
}
return "unknown";
}
const char* YGOverflowToString(const YGOverflow value) {
switch (value) {
case YGOverflowVisible:
return "visible";
case YGOverflowHidden:
return "hidden";
case YGOverflowScroll:
return "scroll";
}
return "unknown";
}
const char* YGPositionTypeToString(const YGPositionType value) {
switch (value) {
case YGPositionTypeRelative:
return "relative";
case YGPositionTypeAbsolute:
return "absolute";
}
return "unknown";
}
const char* YGPrintOptionsToString(const YGPrintOptions value) {
switch (value) {
case YGPrintOptionsLayout:
return "layout";
case YGPrintOptionsStyle:
return "style";
case YGPrintOptionsChildren:
return "children";
}
return "unknown";
}
const char* YGUnitToString(const YGUnit value) {
switch (value) {
case YGUnitUndefined:
return "undefined";
case YGUnitPoint:
return "point";
case YGUnitPercent:
return "percent";
case YGUnitAuto:
return "auto";
}
return "unknown";
}
const char* YGWrapToString(const YGWrap value) {
switch (value) {
case YGWrapNoWrap:
return "no-wrap";
case YGWrapWrap:
return "wrap";
case YGWrapWrapReverse:
return "wrap-reverse";
}
return "unknown";
}

151
sources/3rdparty/yoga/YGEnums.h vendored Normal file
View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "YGMacros.h"
#ifdef __cplusplus
namespace facebook {
namespace yoga {
namespace enums {
template <typename T>
constexpr int count(); // can't use `= delete` due to a defect in clang < 3.9
namespace detail {
template <int... xs>
constexpr int n() {
return sizeof...(xs);
}
} // namespace detail
} // namespace enums
} // namespace yoga
} // namespace facebook
#endif
#define YG_ENUM_DECL(NAME, ...) \
typedef YG_ENUM_BEGIN(NAME){__VA_ARGS__} YG_ENUM_END(NAME); \
WIN_EXPORT const char* NAME##ToString(NAME);
#ifdef __cplusplus
#define YG_ENUM_SEQ_DECL(NAME, ...) \
YG_ENUM_DECL(NAME, __VA_ARGS__) \
YG_EXTERN_C_END \
namespace facebook { \
namespace yoga { \
namespace enums { \
template <> \
constexpr int count<NAME>() { \
return detail::n<__VA_ARGS__>(); \
} \
} \
} \
} \
YG_EXTERN_C_BEGIN
#else
#define YG_ENUM_SEQ_DECL YG_ENUM_DECL
#endif
YG_EXTERN_C_BEGIN
YG_ENUM_SEQ_DECL(
YGAlign,
YGAlignAuto,
YGAlignFlexStart,
YGAlignCenter,
YGAlignFlexEnd,
YGAlignStretch,
YGAlignBaseline,
YGAlignSpaceBetween,
YGAlignSpaceAround);
YG_ENUM_SEQ_DECL(YGDimension, YGDimensionWidth, YGDimensionHeight)
YG_ENUM_SEQ_DECL(
YGDirection,
YGDirectionInherit,
YGDirectionLTR,
YGDirectionRTL)
YG_ENUM_SEQ_DECL(YGDisplay, YGDisplayFlex, YGDisplayNone)
YG_ENUM_SEQ_DECL(
YGEdge,
YGEdgeLeft,
YGEdgeTop,
YGEdgeRight,
YGEdgeBottom,
YGEdgeStart,
YGEdgeEnd,
YGEdgeHorizontal,
YGEdgeVertical,
YGEdgeAll)
YG_ENUM_SEQ_DECL(YGExperimentalFeature, YGExperimentalFeatureWebFlexBasis)
YG_ENUM_SEQ_DECL(
YGFlexDirection,
YGFlexDirectionColumn,
YGFlexDirectionColumnReverse,
YGFlexDirectionRow,
YGFlexDirectionRowReverse)
YG_ENUM_SEQ_DECL(
YGJustify,
YGJustifyFlexStart,
YGJustifyCenter,
YGJustifyFlexEnd,
YGJustifySpaceBetween,
YGJustifySpaceAround,
YGJustifySpaceEvenly)
YG_ENUM_SEQ_DECL(
YGLogLevel,
YGLogLevelError,
YGLogLevelWarn,
YGLogLevelInfo,
YGLogLevelDebug,
YGLogLevelVerbose,
YGLogLevelFatal)
YG_ENUM_SEQ_DECL(
YGMeasureMode,
YGMeasureModeUndefined,
YGMeasureModeExactly,
YGMeasureModeAtMost)
YG_ENUM_SEQ_DECL(YGNodeType, YGNodeTypeDefault, YGNodeTypeText)
YG_ENUM_SEQ_DECL(
YGOverflow,
YGOverflowVisible,
YGOverflowHidden,
YGOverflowScroll)
YG_ENUM_SEQ_DECL(YGPositionType, YGPositionTypeRelative, YGPositionTypeAbsolute)
YG_ENUM_DECL(
YGPrintOptions,
YGPrintOptionsLayout = 1,
YGPrintOptionsStyle = 2,
YGPrintOptionsChildren = 4)
YG_ENUM_SEQ_DECL(
YGUnit,
YGUnitUndefined,
YGUnitPoint,
YGUnitPercent,
YGUnitAuto)
YG_ENUM_SEQ_DECL(YGWrap, YGWrapNoWrap, YGWrapWrap, YGWrapWrapReverse)
YG_EXTERN_C_END
#undef YG_ENUM_DECL
#undef YG_ENUM_SEQ_DECL

70
sources/3rdparty/yoga/YGFloatOptional.h vendored Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cmath>
#include <limits>
#include "Yoga-internal.h"
struct YGFloatOptional {
private:
float value_ = std::numeric_limits<float>::quiet_NaN();
public:
explicit constexpr YGFloatOptional(float value) : value_(value) {}
constexpr YGFloatOptional() = default;
// returns the wrapped value, or a value x with YGIsUndefined(x) == true
constexpr float unwrap() const { return value_; }
bool isUndefined() const { return std::isnan(value_); }
};
// operators take YGFloatOptional by value, as it is a 32bit value
inline bool operator==(YGFloatOptional lhs, YGFloatOptional rhs) {
return lhs.unwrap() == rhs.unwrap() ||
(lhs.isUndefined() && rhs.isUndefined());
}
inline bool operator!=(YGFloatOptional lhs, YGFloatOptional rhs) {
return !(lhs == rhs);
}
inline bool operator==(YGFloatOptional lhs, float rhs) {
return lhs == YGFloatOptional{rhs};
}
inline bool operator!=(YGFloatOptional lhs, float rhs) {
return !(lhs == rhs);
}
inline bool operator==(float lhs, YGFloatOptional rhs) {
return rhs == lhs;
}
inline bool operator!=(float lhs, YGFloatOptional rhs) {
return !(lhs == rhs);
}
inline YGFloatOptional operator+(YGFloatOptional lhs, YGFloatOptional rhs) {
return YGFloatOptional{lhs.unwrap() + rhs.unwrap()};
}
inline bool operator>(YGFloatOptional lhs, YGFloatOptional rhs) {
return lhs.unwrap() > rhs.unwrap();
}
inline bool operator<(YGFloatOptional lhs, YGFloatOptional rhs) {
return lhs.unwrap() < rhs.unwrap();
}
inline bool operator>=(YGFloatOptional lhs, YGFloatOptional rhs) {
return lhs > rhs || lhs == rhs;
}
inline bool operator<=(YGFloatOptional lhs, YGFloatOptional rhs) {
return lhs < rhs || lhs == rhs;
}

42
sources/3rdparty/yoga/YGLayout.cpp vendored Normal file
View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGLayout.h"
#include "Utils.h"
using namespace facebook;
bool YGLayout::operator==(YGLayout layout) const {
bool isEqual = YGFloatArrayEqual(position, layout.position) &&
YGFloatArrayEqual(dimensions, layout.dimensions) &&
YGFloatArrayEqual(margin, layout.margin) &&
YGFloatArrayEqual(border, layout.border) &&
YGFloatArrayEqual(padding, layout.padding) &&
direction() == layout.direction() &&
hadOverflow() == layout.hadOverflow() &&
lastOwnerDirection == layout.lastOwnerDirection &&
nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&
cachedLayout == layout.cachedLayout &&
computedFlexBasis == layout.computedFlexBasis;
for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) {
isEqual = isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i];
}
if (!yoga::isUndefined(measuredDimensions[0]) ||
!yoga::isUndefined(layout.measuredDimensions[0])) {
isEqual =
isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]);
}
if (!yoga::isUndefined(measuredDimensions[1]) ||
!yoga::isUndefined(layout.measuredDimensions[1])) {
isEqual =
isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]);
}
return isEqual;
}

69
sources/3rdparty/yoga/YGLayout.h vendored Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "Bitfield.h"
#include "YGFloatOptional.h"
#include "Yoga-internal.h"
struct YGLayout {
std::array<float, 4> position = {};
std::array<float, 2> dimensions = {{YGUndefined, YGUndefined}};
std::array<float, 4> margin = {};
std::array<float, 4> border = {};
std::array<float, 4> padding = {};
private:
static constexpr size_t directionIdx = 0;
static constexpr size_t didUseLegacyFlagIdx = 1;
static constexpr size_t doesLegacyStretchFlagAffectsLayoutIdx = 2;
static constexpr size_t hadOverflowIdx = 3;
facebook::yoga::Bitfield<uint8_t, YGDirection, bool, bool, bool> flags_ =
{YGDirectionInherit, false, false, false};
public:
uint32_t computedFlexBasisGeneration = 0;
YGFloatOptional computedFlexBasis = {};
// Instead of recomputing the entire layout every single time, we cache some
// information to break early when nothing changed
uint32_t generationCount = 0;
YGDirection lastOwnerDirection = (YGDirection) -1;
uint32_t nextCachedMeasurementsIndex = 0;
std::array<YGCachedMeasurement, YG_MAX_CACHED_RESULT_COUNT>
cachedMeasurements = {};
std::array<float, 2> measuredDimensions = {{YGUndefined, YGUndefined}};
YGCachedMeasurement cachedLayout = YGCachedMeasurement();
YGDirection direction() const { return flags_.at<directionIdx>(); }
decltype(flags_)::Ref<directionIdx> direction() {
return flags_.at<directionIdx>();
}
bool didUseLegacyFlag() const { return flags_.at<didUseLegacyFlagIdx>(); }
decltype(flags_)::Ref<didUseLegacyFlagIdx> didUseLegacyFlag() {
return flags_.at<didUseLegacyFlagIdx>();
}
bool doesLegacyStretchFlagAffectsLayout() const {
return flags_.at<doesLegacyStretchFlagAffectsLayoutIdx>();
}
decltype(flags_)::Ref<doesLegacyStretchFlagAffectsLayoutIdx>
doesLegacyStretchFlagAffectsLayout() {
return flags_.at<doesLegacyStretchFlagAffectsLayoutIdx>();
}
bool hadOverflow() const { return flags_.at<hadOverflowIdx>(); }
decltype(flags_)::Ref<hadOverflowIdx> hadOverflow() {
return flags_.at<hadOverflowIdx>();
}
bool operator==(YGLayout layout) const;
bool operator!=(YGLayout layout) const { return !(*this == layout); }
};

53
sources/3rdparty/yoga/YGMacros.h vendored Normal file
View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#ifdef __cplusplus
#define YG_EXTERN_C_BEGIN extern "C" {
#define YG_EXTERN_C_END }
#else
#define YG_EXTERN_C_BEGIN
#define YG_EXTERN_C_END
#endif
#ifdef _WINDLL
#define WIN_EXPORT __declspec(dllexport)
#else
#define WIN_EXPORT
#endif
#ifndef YOGA_EXPORT
#ifdef _MSC_VER
#define YOGA_EXPORT
#else
#define YOGA_EXPORT __attribute__((visibility("default")))
#endif
#endif
#ifdef NS_ENUM
// Cannot use NSInteger as NSInteger has a different size than int (which is the
// default type of a enum). Therefor when linking the Yoga C library into obj-c
// the header is a missmatch for the Yoga ABI.
#define YG_ENUM_BEGIN(name) NS_ENUM(int, name)
#define YG_ENUM_END(name)
#else
#define YG_ENUM_BEGIN(name) enum name
#define YG_ENUM_END(name) name
#endif
#ifdef __GNUC__
#define YG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define YG_DEPRECATED __declspec(deprecated)
#elif __cplusplus >= 201402L
#if defined(__has_cpp_attribute)
#if __has_cpp_attribute(deprecated)
#define YG_DEPRECATED [[deprecated]]
#endif
#endif
#endif

585
sources/3rdparty/yoga/YGNode.cpp vendored Normal file
View File

@@ -0,0 +1,585 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGNode.h"
#include <algorithm>
#include <iostream>
#include "CompactValue.h"
#include "Utils.h"
using namespace facebook;
using facebook::yoga::detail::CompactValue;
YGNode::YGNode(YGNode&& node) {
context_ = node.context_;
flags_ = node.flags_;
measure_ = node.measure_;
baseline_ = node.baseline_;
print_ = node.print_;
dirtied_ = node.dirtied_;
style_ = node.style_;
layout_ = node.layout_;
lineIndex_ = node.lineIndex_;
owner_ = node.owner_;
children_ = std::move(node.children_);
config_ = node.config_;
resolvedDimensions_ = node.resolvedDimensions_;
for (auto c : children_) {
c->setOwner(c);
}
}
YGNode::YGNode(const YGNode& node, YGConfigRef config) : YGNode{node} {
config_ = config;
if (config->useWebDefaults) {
useWebDefaults();
}
}
void YGNode::print(void* printContext) {
if (print_.noContext != nullptr) {
if (flags_.at<printUsesContext_>()) {
print_.withContext(this, printContext);
} else {
print_.noContext(this);
}
}
}
YGFloatOptional YGNode::getLeadingPosition(
const YGFlexDirection axis,
const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) {
auto leadingPosition = YGComputedEdgeValue(
style_.position(), YGEdgeStart, CompactValue::ofUndefined());
if (!leadingPosition.isUndefined()) {
return YGResolveValue(leadingPosition, axisSize);
}
}
auto leadingPosition = YGComputedEdgeValue(
style_.position(), leading[axis], CompactValue::ofUndefined());
return leadingPosition.isUndefined()
? YGFloatOptional{0}
: YGResolveValue(leadingPosition, axisSize);
}
YGFloatOptional YGNode::getTrailingPosition(
const YGFlexDirection axis,
const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) {
auto trailingPosition = YGComputedEdgeValue(
style_.position(), YGEdgeEnd, CompactValue::ofUndefined());
if (!trailingPosition.isUndefined()) {
return YGResolveValue(trailingPosition, axisSize);
}
}
auto trailingPosition = YGComputedEdgeValue(
style_.position(), trailing[axis], CompactValue::ofUndefined());
return trailingPosition.isUndefined()
? YGFloatOptional{0}
: YGResolveValue(trailingPosition, axisSize);
}
bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) &&
!YGComputedEdgeValue(
style_.position(), YGEdgeStart, CompactValue::ofUndefined())
.isUndefined()) ||
!YGComputedEdgeValue(
style_.position(), leading[axis], CompactValue::ofUndefined())
.isUndefined();
}
bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) &&
!YGComputedEdgeValue(
style_.position(), YGEdgeEnd, CompactValue::ofUndefined())
.isUndefined()) ||
!YGComputedEdgeValue(
style_.position(), trailing[axis], CompactValue::ofUndefined())
.isUndefined();
}
YGFloatOptional YGNode::getLeadingMargin(
const YGFlexDirection axis,
const float widthSize) const {
if (YGFlexDirectionIsRow(axis) &&
!style_.margin()[YGEdgeStart].isUndefined()) {
return YGResolveValueMargin(style_.margin()[YGEdgeStart], widthSize);
}
return YGResolveValueMargin(
YGComputedEdgeValue(
style_.margin(), leading[axis], CompactValue::ofZero()),
widthSize);
}
YGFloatOptional YGNode::getTrailingMargin(
const YGFlexDirection axis,
const float widthSize) const {
if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) {
return YGResolveValueMargin(style_.margin()[YGEdgeEnd], widthSize);
}
return YGResolveValueMargin(
YGComputedEdgeValue(
style_.margin(), trailing[axis], CompactValue::ofZero()),
widthSize);
}
YGFloatOptional YGNode::getMarginForAxis(
const YGFlexDirection axis,
const float widthSize) const {
return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
}
YGSize YGNode::measure(
float width,
YGMeasureMode widthMode,
float height,
YGMeasureMode heightMode,
void* layoutContext) {
return flags_.at<measureUsesContext_>()
? measure_.withContext(
this, width, widthMode, height, heightMode, layoutContext)
: measure_.noContext(this, width, widthMode, height, heightMode);
}
float YGNode::baseline(float width, float height, void* layoutContext) {
return flags_.at<baselineUsesContext_>()
? baseline_.withContext(this, width, height, layoutContext)
: baseline_.noContext(this, width, height);
}
// Setters
void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) {
if (measureFunc.noContext == nullptr) {
// TODO: t18095186 Move nodeType to opt-in function and mark appropriate
// places in Litho
flags_.at<nodeType_>() = YGNodeTypeDefault;
} else {
YGAssertWithNode(
this,
children_.size() == 0,
"Cannot set measure function: Nodes with measure functions cannot have "
"children.");
// TODO: t18095186 Move nodeType to opt-in function and mark appropriate
// places in Litho
setNodeType(YGNodeTypeText);
}
measure_ = measureFunc;
}
void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
flags_.at<measureUsesContext_>() = false;
decltype(YGNode::measure_) m;
m.noContext = measureFunc;
setMeasureFunc(m);
}
YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) {
flags_.at<measureUsesContext_>() = true;
decltype(YGNode::measure_) m;
m.withContext = measureFunc;
setMeasureFunc(m);
}
void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
children_[index] = child;
}
void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
std::replace(children_.begin(), children_.end(), oldChild, newChild);
}
void YGNode::insertChild(YGNodeRef child, uint32_t index) {
children_.insert(children_.begin() + index, child);
}
void YGNode::setDirty(bool isDirty) {
if (isDirty == flags_.at<isDirty_>()) {
return;
}
flags_.at<isDirty_>() = isDirty;
if (isDirty && dirtied_) {
dirtied_(this);
}
}
bool YGNode::removeChild(YGNodeRef child) {
std::vector<YGNodeRef>::iterator p =
std::find(children_.begin(), children_.end(), child);
if (p != children_.end()) {
children_.erase(p);
return true;
}
return false;
}
void YGNode::removeChild(uint32_t index) {
children_.erase(children_.begin() + index);
}
void YGNode::setLayoutDirection(YGDirection direction) {
layout_.direction() = direction;
}
void YGNode::setLayoutMargin(float margin, int index) {
layout_.margin[index] = margin;
}
void YGNode::setLayoutBorder(float border, int index) {
layout_.border[index] = border;
}
void YGNode::setLayoutPadding(float padding, int index) {
layout_.padding[index] = padding;
}
void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
layout_.lastOwnerDirection = direction;
}
void YGNode::setLayoutComputedFlexBasis(
const YGFloatOptional computedFlexBasis) {
layout_.computedFlexBasis = computedFlexBasis;
}
void YGNode::setLayoutPosition(float position, int index) {
layout_.position[index] = position;
}
void YGNode::setLayoutComputedFlexBasisGeneration(
uint32_t computedFlexBasisGeneration) {
layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
}
void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
layout_.measuredDimensions[index] = measuredDimension;
}
void YGNode::setLayoutHadOverflow(bool hadOverflow) {
layout_.hadOverflow() = hadOverflow;
}
void YGNode::setLayoutDimension(float dimension, int index) {
layout_.dimensions[index] = dimension;
}
// If both left and right are defined, then use left. Otherwise return +left or
// -right depending on which is defined.
YGFloatOptional YGNode::relativePosition(
const YGFlexDirection axis,
const float axisSize) const {
if (isLeadingPositionDefined(axis)) {
return getLeadingPosition(axis, axisSize);
}
YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
if (!trailingPosition.isUndefined()) {
trailingPosition = YGFloatOptional{-1 * trailingPosition.unwrap()};
}
return trailingPosition;
}
void YGNode::setPosition(
const YGDirection direction,
const float mainSize,
const float crossSize,
const float ownerWidth) {
/* Root nodes should be always layouted as LTR, so we don't return negative
* values. */
const YGDirection directionRespectingRoot =
owner_ != nullptr ? direction : YGDirectionLTR;
const YGFlexDirection mainAxis =
YGResolveFlexDirection(style_.flexDirection(), directionRespectingRoot);
const YGFlexDirection crossAxis =
YGFlexDirectionCross(mainAxis, directionRespectingRoot);
const YGFloatOptional relativePositionMain =
relativePosition(mainAxis, mainSize);
const YGFloatOptional relativePositionCross =
relativePosition(crossAxis, crossSize);
setLayoutPosition(
(getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(),
leading[mainAxis]);
setLayoutPosition(
(getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(),
trailing[mainAxis]);
setLayoutPosition(
(getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross)
.unwrap(),
leading[crossAxis]);
setLayoutPosition(
(getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross)
.unwrap(),
trailing[crossAxis]);
}
YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
if (YGFlexDirectionIsRow(axis) &&
!style_.margin()[YGEdgeStart].isUndefined()) {
return style_.margin()[YGEdgeStart];
} else {
return style_.margin()[leading[axis]];
}
}
YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) {
return style_.margin()[YGEdgeEnd];
} else {
return style_.margin()[trailing[axis]];
}
}
YGValue YGNode::resolveFlexBasisPtr() const {
YGValue flexBasis = style_.flexBasis();
if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
return flexBasis;
}
if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) {
return flags_.at<useWebDefaults_>() ? YGValueAuto : YGValueZero;
}
return YGValueAuto;
}
void YGNode::resolveDimension() {
using namespace yoga;
const YGStyle& style = getStyle();
for (auto dim : {YGDimensionWidth, YGDimensionHeight}) {
if (!style.maxDimensions()[dim].isUndefined() &&
YGValueEqual(style.maxDimensions()[dim], style.minDimensions()[dim])) {
resolvedDimensions_[dim] = style.maxDimensions()[dim];
} else {
resolvedDimensions_[dim] = style.dimensions()[dim];
}
}
}
YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
if (style_.direction() == YGDirectionInherit) {
return ownerDirection > YGDirectionInherit ? ownerDirection
: YGDirectionLTR;
} else {
return style_.direction();
}
}
YOGA_EXPORT void YGNode::clearChildren() {
children_.clear();
children_.shrink_to_fit();
}
// Other Methods
void YGNode::cloneChildrenIfNeeded(void* cloneContext) {
iterChildrenAfterCloningIfNeeded([](YGNodeRef, void*) {}, cloneContext);
}
void YGNode::markDirtyAndPropogate() {
if (!flags_.at<isDirty_>()) {
setDirty(true);
setLayoutComputedFlexBasis(YGFloatOptional());
if (owner_) {
owner_->markDirtyAndPropogate();
}
}
}
void YGNode::markDirtyAndPropogateDownwards() {
flags_.at<isDirty_>() = true;
for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
childNode->markDirtyAndPropogateDownwards();
});
}
float YGNode::resolveFlexGrow() const {
// Root nodes flexGrow should always be 0
if (owner_ == nullptr) {
return 0.0;
}
if (!style_.flexGrow().isUndefined()) {
return style_.flexGrow().unwrap();
}
if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) {
return style_.flex().unwrap();
}
return kDefaultFlexGrow;
}
float YGNode::resolveFlexShrink() const {
if (owner_ == nullptr) {
return 0.0;
}
if (!style_.flexShrink().isUndefined()) {
return style_.flexShrink().unwrap();
}
if (!flags_.at<useWebDefaults_>() && !style_.flex().isUndefined() &&
style_.flex().unwrap() < 0.0f) {
return -style_.flex().unwrap();
}
return flags_.at<useWebDefaults_>() ? kWebDefaultFlexShrink
: kDefaultFlexShrink;
}
bool YGNode::isNodeFlexible() {
return (
(style_.positionType() == YGPositionTypeRelative) &&
(resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
}
float YGNode::getLeadingBorder(const YGFlexDirection axis) const {
YGValue leadingBorder;
if (YGFlexDirectionIsRow(axis) &&
!style_.border()[YGEdgeStart].isUndefined()) {
leadingBorder = style_.border()[YGEdgeStart];
if (leadingBorder.value >= 0) {
return leadingBorder.value;
}
}
leadingBorder = YGComputedEdgeValue(
style_.border(), leading[axis], CompactValue::ofZero());
return YGFloatMax(leadingBorder.value, 0.0f);
}
float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const {
YGValue trailingBorder;
if (YGFlexDirectionIsRow(flexDirection) &&
!style_.border()[YGEdgeEnd].isUndefined()) {
trailingBorder = style_.border()[YGEdgeEnd];
if (trailingBorder.value >= 0.0f) {
return trailingBorder.value;
}
}
trailingBorder = YGComputedEdgeValue(
style_.border(), trailing[flexDirection], CompactValue::ofZero());
return YGFloatMax(trailingBorder.value, 0.0f);
}
YGFloatOptional YGNode::getLeadingPadding(
const YGFlexDirection axis,
const float widthSize) const {
const YGFloatOptional paddingEdgeStart =
YGResolveValue(style_.padding()[YGEdgeStart], widthSize);
if (YGFlexDirectionIsRow(axis) &&
!style_.padding()[YGEdgeStart].isUndefined() &&
!paddingEdgeStart.isUndefined() && paddingEdgeStart.unwrap() >= 0.0f) {
return paddingEdgeStart;
}
YGFloatOptional resolvedValue = YGResolveValue(
YGComputedEdgeValue(
style_.padding(), leading[axis], CompactValue::ofZero()),
widthSize);
return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
}
YGFloatOptional YGNode::getTrailingPadding(
const YGFlexDirection axis,
const float widthSize) const {
const YGFloatOptional paddingEdgeEnd =
YGResolveValue(style_.padding()[YGEdgeEnd], widthSize);
if (YGFlexDirectionIsRow(axis) && paddingEdgeEnd >= YGFloatOptional{0.0f}) {
return paddingEdgeEnd;
}
YGFloatOptional resolvedValue = YGResolveValue(
YGComputedEdgeValue(
style_.padding(), trailing[axis], CompactValue::ofZero()),
widthSize);
return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
}
YGFloatOptional YGNode::getLeadingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const {
return getLeadingPadding(axis, widthSize) +
YGFloatOptional(getLeadingBorder(axis));
}
YGFloatOptional YGNode::getTrailingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const {
return getTrailingPadding(axis, widthSize) +
YGFloatOptional(getTrailingBorder(axis));
}
bool YGNode::didUseLegacyFlag() {
bool didUseLegacyFlag = layout_.didUseLegacyFlag();
if (didUseLegacyFlag) {
return true;
}
for (const auto& child : children_) {
if (child->layout_.didUseLegacyFlag()) {
didUseLegacyFlag = true;
break;
}
}
return didUseLegacyFlag;
}
void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
bool doesLegacyFlagAffectsLayout) {
layout_.doesLegacyStretchFlagAffectsLayout() = doesLegacyFlagAffectsLayout;
}
void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
layout_.didUseLegacyFlag() = didUseLegacyFlag;
}
bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
if (children_.size() != node.children_.size()) {
return false;
}
if (layout_ != node.layout_) {
return false;
}
if (children_.size() == 0) {
return true;
}
bool isLayoutTreeEqual = true;
YGNodeRef otherNodeChildren = nullptr;
for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
otherNodeChildren = node.children_[i];
isLayoutTreeEqual =
children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
if (!isLayoutTreeEqual) {
return false;
}
}
return isLayoutTreeEqual;
}
void YGNode::reset() {
YGAssertWithNode(
this,
children_.size() == 0,
"Cannot reset a node which still has children attached");
YGAssertWithNode(
this, owner_ == nullptr, "Cannot reset a node still attached to a owner");
clearChildren();
auto webDefaults = flags_.at<useWebDefaults_>();
*this = YGNode{getConfig()};
if (webDefaults) {
useWebDefaults();
}
}

323
sources/3rdparty/yoga/YGNode.h vendored Normal file
View File

@@ -0,0 +1,323 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cstdint>
#include <stdio.h>
#include "Bitfield.h"
#include "CompactValue.h"
#include "YGConfig.h"
#include "YGLayout.h"
#include "YGStyle.h"
#include "YGMacros.h"
#include "Yoga-internal.h"
YGConfigRef YGConfigGetDefault();
struct YOGA_EXPORT YGNode {
using MeasureWithContextFn =
YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*);
using BaselineWithContextFn = float (*)(YGNode*, float, float, void*);
using PrintWithContextFn = void (*)(YGNode*, void*);
private:
static constexpr size_t hasNewLayout_ = 0;
static constexpr size_t isReferenceBaseline_ = 1;
static constexpr size_t isDirty_ = 2;
static constexpr size_t nodeType_ = 3;
static constexpr size_t measureUsesContext_ = 4;
static constexpr size_t baselineUsesContext_ = 5;
static constexpr size_t printUsesContext_ = 6;
static constexpr size_t useWebDefaults_ = 7;
void* context_ = nullptr;
using Flags = facebook::yoga::
Bitfield<uint8_t, bool, bool, bool, YGNodeType, bool, bool, bool, bool>;
Flags flags_ =
{true, false, false, YGNodeTypeDefault, false, false, false, false};
uint8_t reserved_ = 0;
union {
YGMeasureFunc noContext;
MeasureWithContextFn withContext;
} measure_ = {nullptr};
union {
YGBaselineFunc noContext;
BaselineWithContextFn withContext;
} baseline_ = {nullptr};
union {
YGPrintFunc noContext;
PrintWithContextFn withContext;
} print_ = {nullptr};
YGDirtiedFunc dirtied_ = nullptr;
YGStyle style_ = {};
YGLayout layout_ = {};
uint32_t lineIndex_ = 0;
YGNodeRef owner_ = nullptr;
YGVector children_ = {};
YGConfigRef config_;
std::array<YGValue, 2> resolvedDimensions_ = {
{YGValueUndefined, YGValueUndefined}};
YGFloatOptional relativePosition(
const YGFlexDirection axis,
const float axisSize) const;
void setMeasureFunc(decltype(measure_));
void setBaselineFunc(decltype(baseline_));
void useWebDefaults() {
flags_.at<useWebDefaults_>() = true;
style_.flexDirection() = YGFlexDirectionRow;
style_.alignContent() = YGAlignStretch;
}
// DANGER DANGER DANGER!
// If the the node assigned to has children, we'd either have to deallocate
// them (potentially incorrect) or ignore them (danger of leaks). Only ever
// use this after checking that there are no children.
// DO NOT CHANGE THE VISIBILITY OF THIS METHOD!
YGNode& operator=(YGNode&&) = default;
using CompactValue = facebook::yoga::detail::CompactValue;
public:
YGNode() : YGNode{YGConfigGetDefault()} {}
explicit YGNode(const YGConfigRef config) : config_{config} {
if (config->useWebDefaults) {
useWebDefaults();
}
};
~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree
YGNode(YGNode&&);
// Does not expose true value semantics, as children are not cloned eagerly.
// Should we remove this?
YGNode(const YGNode& node) = default;
// for RB fabric
YGNode(const YGNode& node, YGConfigRef config);
// assignment means potential leaks of existing children, or alternatively
// freeing unowned memory, double free, or freeing stack memory.
YGNode& operator=(const YGNode&) = delete;
// Getters
void* getContext() const { return context_; }
uint8_t& reserved() { return reserved_; }
uint8_t reserved() const { return reserved_; }
void print(void*);
bool getHasNewLayout() const { return flags_.at<hasNewLayout_>(); }
YGNodeType getNodeType() const { return flags_.at<nodeType_>(); }
bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; }
YGSize measure(float, YGMeasureMode, float, YGMeasureMode, void*);
bool hasBaselineFunc() const noexcept {
return baseline_.noContext != nullptr;
}
float baseline(float width, float height, void* layoutContext);
YGDirtiedFunc getDirtied() const { return dirtied_; }
// For Performance reasons passing as reference.
YGStyle& getStyle() { return style_; }
const YGStyle& getStyle() const { return style_; }
// For Performance reasons passing as reference.
YGLayout& getLayout() { return layout_; }
const YGLayout& getLayout() const { return layout_; }
uint32_t getLineIndex() const { return lineIndex_; }
bool isReferenceBaseline() { return flags_.at<isReferenceBaseline_>(); }
// returns the YGNodeRef that owns this YGNode. An owner is used to identify
// the YogaTree that a YGNode belongs to. This method will return the parent
// of the YGNode when a YGNode only belongs to one YogaTree or nullptr when
// the YGNode is shared between two or more YogaTrees.
YGNodeRef getOwner() const { return owner_; }
// Deprecated, use getOwner() instead.
YGNodeRef getParent() const { return getOwner(); }
const YGVector& getChildren() const { return children_; }
// Applies a callback to all children, after cloning them if they are not
// owned.
template <typename T>
void iterChildrenAfterCloningIfNeeded(T callback, void* cloneContext) {
int i = 0;
for (YGNodeRef& child : children_) {
if (child->getOwner() != this) {
child = config_->cloneNode(child, this, i, cloneContext);
child->setOwner(this);
}
i += 1;
callback(child, cloneContext);
}
}
YGNodeRef getChild(uint32_t index) const { return children_.at(index); }
YGConfigRef getConfig() const { return config_; }
bool isDirty() const { return flags_.at<isDirty_>(); }
std::array<YGValue, 2> getResolvedDimensions() const {
return resolvedDimensions_;
}
YGValue getResolvedDimension(int index) const {
return resolvedDimensions_[index];
}
// Methods related to positions, margin, padding and border
YGFloatOptional getLeadingPosition(
const YGFlexDirection axis,
const float axisSize) const;
bool isLeadingPositionDefined(const YGFlexDirection axis) const;
bool isTrailingPosDefined(const YGFlexDirection axis) const;
YGFloatOptional getTrailingPosition(
const YGFlexDirection axis,
const float axisSize) const;
YGFloatOptional getLeadingMargin(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingMargin(
const YGFlexDirection axis,
const float widthSize) const;
float getLeadingBorder(const YGFlexDirection flexDirection) const;
float getTrailingBorder(const YGFlexDirection flexDirection) const;
YGFloatOptional getLeadingPadding(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingPadding(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getLeadingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getMarginForAxis(
const YGFlexDirection axis,
const float widthSize) const;
// Setters
void setContext(void* context) { context_ = context; }
void setPrintFunc(YGPrintFunc printFunc) {
print_.noContext = printFunc;
flags_.at<printUsesContext_>() = false;
}
void setPrintFunc(PrintWithContextFn printFunc) {
print_.withContext = printFunc;
flags_.at<printUsesContext_>() = true;
}
void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); }
void setHasNewLayout(bool hasNewLayout) {
flags_.at<hasNewLayout_>() = hasNewLayout;
}
void setNodeType(YGNodeType nodeType) { flags_.at<nodeType_>() = nodeType; }
void setMeasureFunc(YGMeasureFunc measureFunc);
void setMeasureFunc(MeasureWithContextFn);
void setMeasureFunc(std::nullptr_t) {
return setMeasureFunc(YGMeasureFunc{nullptr});
}
void setBaselineFunc(YGBaselineFunc baseLineFunc) {
flags_.at<baselineUsesContext_>() = false;
baseline_.noContext = baseLineFunc;
}
void setBaselineFunc(BaselineWithContextFn baseLineFunc) {
flags_.at<baselineUsesContext_>() = true;
baseline_.withContext = baseLineFunc;
}
void setBaselineFunc(std::nullptr_t) {
return setBaselineFunc(YGBaselineFunc{nullptr});
}
void setDirtiedFunc(YGDirtiedFunc dirtiedFunc) { dirtied_ = dirtiedFunc; }
void setStyle(const YGStyle& style) { style_ = style; }
void setLayout(const YGLayout& layout) { layout_ = layout; }
void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; }
void setIsReferenceBaseline(bool isReferenceBaseline) {
flags_.at<isReferenceBaseline_>() = isReferenceBaseline;
}
void setOwner(YGNodeRef owner) { owner_ = owner; }
void setChildren(const YGVector& children) { children_ = children; }
// TODO: rvalue override for setChildren
YG_DEPRECATED void setConfig(YGConfigRef config) { config_ = config; }
void setDirty(bool isDirty);
void setLayoutLastOwnerDirection(YGDirection direction);
void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis);
void setLayoutComputedFlexBasisGeneration(
uint32_t computedFlexBasisGeneration);
void setLayoutMeasuredDimension(float measuredDimension, int index);
void setLayoutHadOverflow(bool hadOverflow);
void setLayoutDimension(float dimension, int index);
void setLayoutDirection(YGDirection direction);
void setLayoutMargin(float margin, int index);
void setLayoutBorder(float border, int index);
void setLayoutPadding(float padding, int index);
void setLayoutPosition(float position, int index);
void setPosition(
const YGDirection direction,
const float mainSize,
const float crossSize,
const float ownerWidth);
void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout);
void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag);
void markDirtyAndPropogateDownwards();
// Other methods
YGValue marginLeadingValue(const YGFlexDirection axis) const;
YGValue marginTrailingValue(const YGFlexDirection axis) const;
YGValue resolveFlexBasisPtr() const;
void resolveDimension();
YGDirection resolveDirection(const YGDirection ownerDirection);
void clearChildren();
/// Replaces the occurrences of oldChild with newChild
void replaceChild(YGNodeRef oldChild, YGNodeRef newChild);
void replaceChild(YGNodeRef child, uint32_t index);
void insertChild(YGNodeRef child, uint32_t index);
/// Removes the first occurrence of child
bool removeChild(YGNodeRef child);
void removeChild(uint32_t index);
void cloneChildrenIfNeeded(void*);
void markDirtyAndPropogate();
float resolveFlexGrow() const;
float resolveFlexShrink() const;
bool isNodeFlexible();
bool didUseLegacyFlag();
bool isLayoutTreeEqualToNode(const YGNode& node) const;
void reset();
};

225
sources/3rdparty/yoga/YGNodePrint.cpp vendored Normal file
View File

@@ -0,0 +1,225 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#ifdef DEBUG
#include "YGNodePrint.h"
#include <stdarg.h>
#include "YGEnums.h"
#include "YGNode.h"
#include "Yoga-internal.h"
#include "Utils.h"
namespace facebook {
namespace yoga {
typedef std::string string;
static void indent(string& base, uint32_t level) {
for (uint32_t i = 0; i < level; ++i) {
base.append(" ");
}
}
static bool areFourValuesEqual(const YGStyle::Edges& four) {
return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) &&
YGValueEqual(four[0], four[3]);
}
static void appendFormatedString(string& str, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
va_list argsCopy;
va_copy(argsCopy, args);
std::vector<char> buf(1 + vsnprintf(NULL, 0, fmt, args));
va_end(args);
vsnprintf(buf.data(), buf.size(), fmt, argsCopy);
va_end(argsCopy);
string result = string(buf.begin(), buf.end() - 1);
str.append(result);
}
static void appendFloatOptionalIfDefined(
string& base,
const string key,
const YGFloatOptional num) {
if (!num.isUndefined()) {
appendFormatedString(base, "%s: %g; ", key.c_str(), num.unwrap());
}
}
static void appendNumberIfNotUndefined(
string& base,
const string key,
const YGValue number) {
if (number.unit != YGUnitUndefined) {
if (number.unit == YGUnitAuto) {
base.append(key + ": auto; ");
} else {
string unit = number.unit == YGUnitPoint ? "px" : "%%";
appendFormatedString(
base, "%s: %g%s; ", key.c_str(), number.value, unit.c_str());
}
}
}
static void appendNumberIfNotAuto(
string& base,
const string& key,
const YGValue number) {
if (number.unit != YGUnitAuto) {
appendNumberIfNotUndefined(base, key, number);
}
}
static void appendNumberIfNotZero(
string& base,
const string& str,
const YGValue number) {
if (number.unit == YGUnitAuto) {
base.append(str + ": auto; ");
} else if (!YGFloatsEqual(number.value, 0)) {
appendNumberIfNotUndefined(base, str, number);
}
}
static void appendEdges(
string& base,
const string& key,
const YGStyle::Edges& edges) {
if (areFourValuesEqual(edges)) {
appendNumberIfNotZero(base, key, edges[YGEdgeLeft]);
} else {
for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) {
string str = key + "-" + YGEdgeToString(static_cast<YGEdge>(edge));
appendNumberIfNotZero(base, str, edges[edge]);
}
}
}
static void appendEdgeIfNotUndefined(
string& base,
const string& str,
const YGStyle::Edges& edges,
const YGEdge edge) {
appendNumberIfNotUndefined(
base,
str,
YGComputedEdgeValue(edges, edge, detail::CompactValue::ofUndefined()));
}
void YGNodeToString(
std::string& str,
YGNodeRef node,
YGPrintOptions options,
uint32_t level) {
indent(str, level);
appendFormatedString(str, "<div ");
if (options & YGPrintOptionsLayout) {
appendFormatedString(str, "layout=\"");
appendFormatedString(
str, "width: %g; ", node->getLayout().dimensions[YGDimensionWidth]);
appendFormatedString(
str, "height: %g; ", node->getLayout().dimensions[YGDimensionHeight]);
appendFormatedString(
str, "top: %g; ", node->getLayout().position[YGEdgeTop]);
appendFormatedString(
str, "left: %g;", node->getLayout().position[YGEdgeLeft]);
appendFormatedString(str, "\" ");
}
if (options & YGPrintOptionsStyle) {
appendFormatedString(str, "style=\"");
const auto& style = node->getStyle();
if (style.flexDirection() != YGNode().getStyle().flexDirection()) {
appendFormatedString(
str,
"flex-direction: %s; ",
YGFlexDirectionToString(style.flexDirection()));
}
if (style.justifyContent() != YGNode().getStyle().justifyContent()) {
appendFormatedString(
str,
"justify-content: %s; ",
YGJustifyToString(style.justifyContent()));
}
if (style.alignItems() != YGNode().getStyle().alignItems()) {
appendFormatedString(
str, "align-items: %s; ", YGAlignToString(style.alignItems()));
}
if (style.alignContent() != YGNode().getStyle().alignContent()) {
appendFormatedString(
str, "align-content: %s; ", YGAlignToString(style.alignContent()));
}
if (style.alignSelf() != YGNode().getStyle().alignSelf()) {
appendFormatedString(
str, "align-self: %s; ", YGAlignToString(style.alignSelf()));
}
appendFloatOptionalIfDefined(str, "flex-grow", style.flexGrow());
appendFloatOptionalIfDefined(str, "flex-shrink", style.flexShrink());
appendNumberIfNotAuto(str, "flex-basis", style.flexBasis());
appendFloatOptionalIfDefined(str, "flex", style.flex());
if (style.flexWrap() != YGNode().getStyle().flexWrap()) {
appendFormatedString(
str, "flex-wrap: %s; ", YGWrapToString(style.flexWrap()));
}
if (style.overflow() != YGNode().getStyle().overflow()) {
appendFormatedString(
str, "overflow: %s; ", YGOverflowToString(style.overflow()));
}
if (style.display() != YGNode().getStyle().display()) {
appendFormatedString(
str, "display: %s; ", YGDisplayToString(style.display()));
}
appendEdges(str, "margin", style.margin());
appendEdges(str, "padding", style.padding());
appendEdges(str, "border", style.border());
appendNumberIfNotAuto(str, "width", style.dimensions()[YGDimensionWidth]);
appendNumberIfNotAuto(str, "height", style.dimensions()[YGDimensionHeight]);
appendNumberIfNotAuto(
str, "max-width", style.maxDimensions()[YGDimensionWidth]);
appendNumberIfNotAuto(
str, "max-height", style.maxDimensions()[YGDimensionHeight]);
appendNumberIfNotAuto(
str, "min-width", style.minDimensions()[YGDimensionWidth]);
appendNumberIfNotAuto(
str, "min-height", style.minDimensions()[YGDimensionHeight]);
if (style.positionType() != YGNode().getStyle().positionType()) {
appendFormatedString(
str, "position: %s; ", YGPositionTypeToString(style.positionType()));
}
appendEdgeIfNotUndefined(str, "left", style.position(), YGEdgeLeft);
appendEdgeIfNotUndefined(str, "right", style.position(), YGEdgeRight);
appendEdgeIfNotUndefined(str, "top", style.position(), YGEdgeTop);
appendEdgeIfNotUndefined(str, "bottom", style.position(), YGEdgeBottom);
appendFormatedString(str, "\" ");
if (node->hasMeasureFunc()) {
appendFormatedString(str, "has-custom-measure=\"true\"");
}
}
appendFormatedString(str, ">");
const uint32_t childCount = static_cast<uint32_t>(node->getChildren().size());
if (options & YGPrintOptionsChildren && childCount > 0) {
for (uint32_t i = 0; i < childCount; i++) {
appendFormatedString(str, "\n");
YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1);
}
appendFormatedString(str, "\n");
indent(str, level);
}
appendFormatedString(str, "</div>");
}
} // namespace yoga
} // namespace facebook
#endif

25
sources/3rdparty/yoga/YGNodePrint.h vendored Normal file
View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#ifdef DEBUG
#pragma once
#include <string>
#include "Yoga.h"
namespace facebook {
namespace yoga {
void YGNodeToString(
std::string& str,
YGNodeRef node,
YGPrintOptions options,
uint32_t level);
} // namespace yoga
} // namespace facebook
#endif

56
sources/3rdparty/yoga/YGStyle.cpp vendored Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGStyle.h"
#include "Utils.h"
// Yoga specific properties, not compatible with flexbox specification
bool operator==(const YGStyle& lhs, const YGStyle& rhs) {
bool areNonFloatValuesEqual = lhs.direction() == rhs.direction() &&
lhs.flexDirection() == rhs.flexDirection() &&
lhs.justifyContent() == rhs.justifyContent() &&
lhs.alignContent() == rhs.alignContent() &&
lhs.alignItems() == rhs.alignItems() &&
lhs.alignSelf() == rhs.alignSelf() &&
lhs.positionType() == rhs.positionType() &&
lhs.flexWrap() == rhs.flexWrap() && lhs.overflow() == rhs.overflow() &&
lhs.display() == rhs.display() &&
YGValueEqual(lhs.flexBasis(), rhs.flexBasis()) &&
lhs.margin() == rhs.margin() && lhs.position() == rhs.position() &&
lhs.padding() == rhs.padding() && lhs.border() == rhs.border() &&
lhs.dimensions() == rhs.dimensions() &&
lhs.minDimensions() == rhs.minDimensions() &&
lhs.maxDimensions() == rhs.maxDimensions();
areNonFloatValuesEqual = areNonFloatValuesEqual &&
lhs.flex().isUndefined() == rhs.flex().isUndefined();
if (areNonFloatValuesEqual && !lhs.flex().isUndefined() &&
!rhs.flex().isUndefined()) {
areNonFloatValuesEqual = areNonFloatValuesEqual && lhs.flex() == rhs.flex();
}
areNonFloatValuesEqual = areNonFloatValuesEqual &&
lhs.flexGrow().isUndefined() == rhs.flexGrow().isUndefined();
if (areNonFloatValuesEqual && !lhs.flexGrow().isUndefined()) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && lhs.flexGrow() == rhs.flexGrow();
}
areNonFloatValuesEqual = areNonFloatValuesEqual &&
lhs.flexShrink().isUndefined() == rhs.flexShrink().isUndefined();
if (areNonFloatValuesEqual && !rhs.flexShrink().isUndefined()) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && lhs.flexShrink() == rhs.flexShrink();
}
if (!(lhs.aspectRatio().isUndefined() && rhs.aspectRatio().isUndefined())) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && lhs.aspectRatio() == rhs.aspectRatio();
}
return areNonFloatValuesEqual;
}

203
sources/3rdparty/yoga/YGStyle.h vendored Normal file
View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <algorithm>
#include <array>
#include <cstdint>
#include <type_traits>
#include "Bitfield.h"
#include "CompactValue.h"
#include "YGEnums.h"
#include "YGFloatOptional.h"
#include "Yoga-internal.h"
#include "Yoga.h"
class YOGA_EXPORT YGStyle {
template <typename Enum>
using Values =
facebook::yoga::detail::Values<facebook::yoga::enums::count<Enum>()>;
using CompactValue = facebook::yoga::detail::CompactValue;
public:
using Dimensions = Values<YGDimension>;
using Edges = Values<YGEdge>;
template <typename T, T YGStyle::*Prop>
struct Ref {
YGStyle& style;
operator T() const { return style.*Prop; }
Ref<T, Prop>& operator=(T value) {
style.*Prop = value;
return *this;
}
};
template <typename Idx, Values<Idx> YGStyle::*Prop>
struct IdxRef {
struct Ref {
YGStyle& style;
Idx idx;
operator CompactValue() const { return (style.*Prop)[idx]; }
operator YGValue() const { return (style.*Prop)[idx]; }
Ref& operator=(CompactValue value) {
(style.*Prop)[idx] = value;
return *this;
}
};
YGStyle& style;
IdxRef<Idx, Prop>& operator=(const Values<Idx>& values) {
style.*Prop = values;
return *this;
}
operator const Values<Idx>&() const { return style.*Prop; }
Ref operator[](Idx idx) { return {style, idx}; }
CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; }
};
YGStyle() = default;
~YGStyle() = default;
private:
static constexpr size_t directionIdx = 0;
static constexpr size_t flexDirectionIdx = 1;
static constexpr size_t justifyContentIdx = 2;
static constexpr size_t alignContentIdx = 3;
static constexpr size_t alignItemsIdx = 4;
static constexpr size_t alignSelfIdx = 5;
static constexpr size_t positionTypeIdx = 6;
static constexpr size_t flexWrapIdx = 7;
static constexpr size_t overflowIdx = 8;
static constexpr size_t displayIdx = 9;
using Flags = facebook::yoga::Bitfield<
uint32_t,
YGDirection,
YGFlexDirection,
YGJustify,
YGAlign,
YGAlign,
YGAlign,
YGPositionType,
YGWrap,
YGOverflow,
YGDisplay>;
Flags flags_ = {YGDirectionInherit,
YGFlexDirectionColumn,
YGJustifyFlexStart,
YGAlignFlexStart,
YGAlignStretch,
YGAlignAuto,
YGPositionTypeRelative,
YGWrapNoWrap,
YGOverflowVisible,
YGDisplayFlex};
YGFloatOptional flex_ = {};
YGFloatOptional flexGrow_ = {};
YGFloatOptional flexShrink_ = {};
CompactValue flexBasis_ = CompactValue::ofAuto();
Edges margin_ = {};
Edges position_ = {};
Edges padding_ = {};
Edges border_ = {};
Dimensions dimensions_{CompactValue::ofAuto()};
Dimensions minDimensions_ = {};
Dimensions maxDimensions_ = {};
// Yoga specific properties, not compatible with flexbox specification
YGFloatOptional aspectRatio_ = {};
public:
// for library users needing a type
using ValueRepr = std::remove_reference<decltype(margin_[0])>::type;
YGDirection direction() const { return flags_.at<directionIdx>(); }
Flags::Ref<directionIdx> direction() { return flags_.at<directionIdx>(); }
YGFlexDirection flexDirection() const {
return flags_.at<flexDirectionIdx>();
}
Flags::Ref<flexDirectionIdx> flexDirection() {
return flags_.at<flexDirectionIdx>();
}
YGJustify justifyContent() const { return flags_.at<justifyContentIdx>(); }
Flags::Ref<justifyContentIdx> justifyContent() {
return flags_.at<justifyContentIdx>();
}
YGAlign alignContent() const { return flags_.at<alignContentIdx>(); }
Flags::Ref<alignContentIdx> alignContent() {
return flags_.at<alignContentIdx>();
}
YGAlign alignItems() const { return flags_.at<alignItemsIdx>(); }
Flags::Ref<alignItemsIdx> alignItems() { return flags_.at<alignItemsIdx>(); }
YGAlign alignSelf() const { return flags_.at<alignSelfIdx>(); }
Flags::Ref<alignSelfIdx> alignSelf() { return flags_.at<alignSelfIdx>(); }
YGPositionType positionType() const { return flags_.at<positionTypeIdx>(); }
Flags::Ref<positionTypeIdx> positionType() {
return flags_.at<positionTypeIdx>();
}
YGWrap flexWrap() const { return flags_.at<flexWrapIdx>(); }
Flags::Ref<flexWrapIdx> flexWrap() { return flags_.at<flexWrapIdx>(); }
YGOverflow overflow() const { return flags_.at<overflowIdx>(); }
Flags::Ref<overflowIdx> overflow() { return flags_.at<overflowIdx>(); }
YGDisplay display() const { return flags_.at<displayIdx>(); }
Flags::Ref<displayIdx> display() { return flags_.at<displayIdx>(); }
YGFloatOptional flex() const { return flex_; }
Ref<YGFloatOptional, &YGStyle::flex_> flex() { return {*this}; }
YGFloatOptional flexGrow() const { return flexGrow_; }
Ref<YGFloatOptional, &YGStyle::flexGrow_> flexGrow() { return {*this}; }
YGFloatOptional flexShrink() const { return flexShrink_; }
Ref<YGFloatOptional, &YGStyle::flexShrink_> flexShrink() { return {*this}; }
CompactValue flexBasis() const { return flexBasis_; }
Ref<CompactValue, &YGStyle::flexBasis_> flexBasis() { return {*this}; }
const Edges& margin() const { return margin_; }
IdxRef<YGEdge, &YGStyle::margin_> margin() { return {*this}; }
const Edges& position() const { return position_; }
IdxRef<YGEdge, &YGStyle::position_> position() { return {*this}; }
const Edges& padding() const { return padding_; }
IdxRef<YGEdge, &YGStyle::padding_> padding() { return {*this}; }
const Edges& border() const { return border_; }
IdxRef<YGEdge, &YGStyle::border_> border() { return {*this}; }
const Dimensions& dimensions() const { return dimensions_; }
IdxRef<YGDimension, &YGStyle::dimensions_> dimensions() { return {*this}; }
const Dimensions& minDimensions() const { return minDimensions_; }
IdxRef<YGDimension, &YGStyle::minDimensions_> minDimensions() {
return {*this};
}
const Dimensions& maxDimensions() const { return maxDimensions_; }
IdxRef<YGDimension, &YGStyle::maxDimensions_> maxDimensions() {
return {*this};
}
// Yoga specific properties, not compatible with flexbox specification
YGFloatOptional aspectRatio() const { return aspectRatio_; }
Ref<YGFloatOptional, &YGStyle::aspectRatio_> aspectRatio() { return {*this}; }
};
YOGA_EXPORT bool operator==(const YGStyle& lhs, const YGStyle& rhs);
YOGA_EXPORT inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) {
return !(lhs == rhs);
}

12
sources/3rdparty/yoga/YGValue.cpp vendored Normal file
View File

@@ -0,0 +1,12 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGValue.h"
const YGValue YGValueZero = {0, YGUnitPoint};
const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};

84
sources/3rdparty/yoga/YGValue.h vendored Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <math.h>
#include "YGEnums.h"
#include "YGMacros.h"
YG_EXTERN_C_BEGIN
// Not defined in MSVC++
#ifndef NAN
static const uint32_t __nan = 0x7fc00000;
#define NAN (*(const float*) __nan)
#endif
#define YGUndefined NAN
typedef struct YGValue {
float value;
YGUnit unit;
} YGValue;
YOGA_EXPORT extern const YGValue YGValueAuto;
YOGA_EXPORT extern const YGValue YGValueUndefined;
YOGA_EXPORT extern const YGValue YGValueZero;
YG_EXTERN_C_END
#ifdef __cplusplus
inline bool operator==(const YGValue& lhs, const YGValue& rhs) {
if (lhs.unit != rhs.unit) {
return false;
}
switch (lhs.unit) {
case YGUnitUndefined:
case YGUnitAuto:
return true;
case YGUnitPoint:
case YGUnitPercent:
return lhs.value == rhs.value;
}
return false;
}
inline bool operator!=(const YGValue& lhs, const YGValue& rhs) {
return !(lhs == rhs);
}
inline YGValue operator-(const YGValue& value) {
return {-value.value, value.unit};
}
namespace facebook {
namespace yoga {
namespace literals {
inline YGValue operator"" _pt(long double value) {
return YGValue{static_cast<float>(value), YGUnitPoint};
}
inline YGValue operator"" _pt(unsigned long long value) {
return operator"" _pt(static_cast<long double>(value));
}
inline YGValue operator"" _percent(long double value) {
return YGValue{static_cast<float>(value), YGUnitPercent};
}
inline YGValue operator"" _percent(unsigned long long value) {
return operator"" _percent(static_cast<long double>(value));
}
} // namespace literals
} // namespace yoga
} // namespace facebook
#endif

151
sources/3rdparty/yoga/Yoga-internal.h vendored Normal file
View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <algorithm>
#include <array>
#include <cmath>
#include <vector>
#include "CompactValue.h"
#include "Yoga.h"
using YGVector = std::vector<YGNodeRef>;
YG_EXTERN_C_BEGIN
void YGNodeCalculateLayoutWithContext(
YGNodeRef node,
float availableWidth,
float availableHeight,
YGDirection ownerDirection,
void* layoutContext);
YG_EXTERN_C_END
namespace facebook {
namespace yoga {
inline bool isUndefined(float value) {
return std::isnan(value);
}
} // namespace yoga
} // namespace facebook
using namespace facebook;
extern const std::array<YGEdge, 4> trailing;
extern const std::array<YGEdge, 4> leading;
extern const YGValue YGValueUndefined;
extern const YGValue YGValueAuto;
extern const YGValue YGValueZero;
struct YGCachedMeasurement {
float availableWidth;
float availableHeight;
YGMeasureMode widthMeasureMode;
YGMeasureMode heightMeasureMode;
float computedWidth;
float computedHeight;
YGCachedMeasurement()
: availableWidth(0),
availableHeight(0),
widthMeasureMode((YGMeasureMode) -1),
heightMeasureMode((YGMeasureMode) -1),
computedWidth(-1),
computedHeight(-1) {}
bool operator==(YGCachedMeasurement measurement) const {
bool isEqual = widthMeasureMode == measurement.widthMeasureMode &&
heightMeasureMode == measurement.heightMeasureMode;
if (!yoga::isUndefined(availableWidth) ||
!yoga::isUndefined(measurement.availableWidth)) {
isEqual = isEqual && availableWidth == measurement.availableWidth;
}
if (!yoga::isUndefined(availableHeight) ||
!yoga::isUndefined(measurement.availableHeight)) {
isEqual = isEqual && availableHeight == measurement.availableHeight;
}
if (!yoga::isUndefined(computedWidth) ||
!yoga::isUndefined(measurement.computedWidth)) {
isEqual = isEqual && computedWidth == measurement.computedWidth;
}
if (!yoga::isUndefined(computedHeight) ||
!yoga::isUndefined(measurement.computedHeight)) {
isEqual = isEqual && computedHeight == measurement.computedHeight;
}
return isEqual;
}
};
// This value was chosen based on empirical data:
// 98% of analyzed layouts require less than 8 entries.
#define YG_MAX_CACHED_RESULT_COUNT 8
namespace facebook {
namespace yoga {
namespace detail {
template <size_t Size>
class Values {
private:
std::array<CompactValue, Size> values_;
public:
Values() = default;
explicit Values(const YGValue& defaultValue) noexcept {
values_.fill(defaultValue);
}
const CompactValue& operator[](size_t i) const noexcept { return values_[i]; }
CompactValue& operator[](size_t i) noexcept { return values_[i]; }
template <size_t I>
YGValue get() const noexcept {
return std::get<I>(values_);
}
template <size_t I>
void set(YGValue& value) noexcept {
std::get<I>(values_) = value;
}
template <size_t I>
void set(YGValue&& value) noexcept {
set<I>(value);
}
bool operator==(const Values& other) const noexcept {
for (size_t i = 0; i < Size; ++i) {
if (values_[i] != other.values_[i]) {
return false;
}
}
return true;
}
Values& operator=(const Values& other) = default;
};
} // namespace detail
} // namespace yoga
} // namespace facebook
static const float kDefaultFlexGrow = 0.0f;
static const float kDefaultFlexShrink = 0.0f;
static const float kWebDefaultFlexShrink = 1.0f;
extern bool YGFloatsEqual(const float a, const float b);
extern facebook::yoga::detail::CompactValue YGComputedEdgeValue(
const facebook::yoga::detail::Values<
facebook::yoga::enums::count<YGEdge>()>& edges,
YGEdge edge,
facebook::yoga::detail::CompactValue defaultValue);

4405
sources/3rdparty/yoga/Yoga.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

369
sources/3rdparty/yoga/Yoga.h vendored Normal file
View File

@@ -0,0 +1,369 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <assert.h>
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include "YGEnums.h"
#include "YGMacros.h"
#include "YGValue.h"
YG_EXTERN_C_BEGIN
typedef struct YGSize {
float width;
float height;
} YGSize;
typedef struct YGConfig* YGConfigRef;
typedef struct YGNode* YGNodeRef;
typedef const struct YGNode* YGNodeConstRef;
typedef YGSize (*YGMeasureFunc)(
YGNodeRef node,
float width,
YGMeasureMode widthMode,
float height,
YGMeasureMode heightMode);
typedef float (*YGBaselineFunc)(YGNodeRef node, float width, float height);
typedef void (*YGDirtiedFunc)(YGNodeRef node);
typedef void (*YGPrintFunc)(YGNodeRef node);
typedef void (*YGNodeCleanupFunc)(YGNodeRef node);
typedef int (*YGLogger)(
YGConfigRef config,
YGNodeRef node,
YGLogLevel level,
const char* format,
va_list args);
typedef YGNodeRef (
*YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex);
// YGNode
WIN_EXPORT YGNodeRef YGNodeNew(void);
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigRef config);
WIN_EXPORT YGNodeRef YGNodeClone(YGNodeRef node);
WIN_EXPORT void YGNodeFree(YGNodeRef node);
WIN_EXPORT void YGNodeFreeRecursiveWithCleanupFunc(
YGNodeRef node,
YGNodeCleanupFunc cleanup);
WIN_EXPORT void YGNodeFreeRecursive(YGNodeRef node);
WIN_EXPORT void YGNodeReset(YGNodeRef node);
WIN_EXPORT void YGNodeInsertChild(
YGNodeRef node,
YGNodeRef child,
uint32_t index);
WIN_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child);
WIN_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node);
WIN_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, uint32_t index);
WIN_EXPORT YGNodeRef YGNodeGetOwner(YGNodeRef node);
WIN_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node);
WIN_EXPORT uint32_t YGNodeGetChildCount(YGNodeRef node);
WIN_EXPORT void YGNodeSetChildren(
YGNodeRef owner,
const YGNodeRef children[],
uint32_t count);
WIN_EXPORT void YGNodeSetIsReferenceBaseline(
YGNodeRef node,
bool isReferenceBaseline);
WIN_EXPORT bool YGNodeIsReferenceBaseline(YGNodeRef node);
WIN_EXPORT void YGNodeCalculateLayout(
YGNodeRef node,
float availableWidth,
float availableHeight,
YGDirection ownerDirection);
// Mark a node as dirty. Only valid for nodes with a custom measure function
// set.
//
// Yoga knows when to mark all other nodes as dirty but because nodes with
// measure functions depend on information not known to Yoga they must perform
// this dirty marking manually.
WIN_EXPORT void YGNodeMarkDirty(YGNodeRef node);
// Marks the current node and all its descendants as dirty.
//
// Intended to be used for Uoga benchmarks. Don't use in production, as calling
// `YGCalculateLayout` will cause the recalculation of each and every node.
WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(YGNodeRef node);
WIN_EXPORT void YGNodePrint(YGNodeRef node, YGPrintOptions options);
WIN_EXPORT bool YGFloatIsUndefined(float value);
WIN_EXPORT bool YGNodeCanUseCachedMeasurement(
YGMeasureMode widthMode,
float width,
YGMeasureMode heightMode,
float height,
YGMeasureMode lastWidthMode,
float lastWidth,
YGMeasureMode lastHeightMode,
float lastHeight,
float lastComputedWidth,
float lastComputedHeight,
float marginRow,
float marginColumn,
YGConfigRef config);
WIN_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeRef srcNode);
WIN_EXPORT void* YGNodeGetContext(YGNodeRef node);
WIN_EXPORT void YGNodeSetContext(YGNodeRef node, void* context);
void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled);
bool YGNodeHasMeasureFunc(YGNodeRef node);
WIN_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc);
bool YGNodeHasBaselineFunc(YGNodeRef node);
void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc);
YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node);
void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc);
void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc);
WIN_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node);
WIN_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
YGNodeType YGNodeGetNodeType(YGNodeRef node);
void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType);
WIN_EXPORT bool YGNodeIsDirty(YGNodeRef node);
bool YGNodeLayoutGetDidUseLegacyFlag(YGNodeRef node);
WIN_EXPORT void YGNodeStyleSetDirection(YGNodeRef node, YGDirection direction);
WIN_EXPORT YGDirection YGNodeStyleGetDirection(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetFlexDirection(
YGNodeRef node,
YGFlexDirection flexDirection);
WIN_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetJustifyContent(
YGNodeRef node,
YGJustify justifyContent);
WIN_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetAlignContent(
YGNodeRef node,
YGAlign alignContent);
WIN_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetAlignItems(YGNodeRef node, YGAlign alignItems);
WIN_EXPORT YGAlign YGNodeStyleGetAlignItems(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetAlignSelf(YGNodeRef node, YGAlign alignSelf);
WIN_EXPORT YGAlign YGNodeStyleGetAlignSelf(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetPositionType(
YGNodeRef node,
YGPositionType positionType);
WIN_EXPORT YGPositionType YGNodeStyleGetPositionType(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetFlexWrap(YGNodeRef node, YGWrap flexWrap);
WIN_EXPORT YGWrap YGNodeStyleGetFlexWrap(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow);
WIN_EXPORT YGOverflow YGNodeStyleGetOverflow(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetDisplay(YGNodeRef node, YGDisplay display);
WIN_EXPORT YGDisplay YGNodeStyleGetDisplay(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetFlex(YGNodeRef node, float flex);
WIN_EXPORT float YGNodeStyleGetFlex(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetFlexGrow(YGNodeRef node, float flexGrow);
WIN_EXPORT float YGNodeStyleGetFlexGrow(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetFlexShrink(YGNodeRef node, float flexShrink);
WIN_EXPORT float YGNodeStyleGetFlexShrink(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetFlexBasis(YGNodeRef node, float flexBasis);
WIN_EXPORT void YGNodeStyleSetFlexBasisPercent(YGNodeRef node, float flexBasis);
WIN_EXPORT void YGNodeStyleSetFlexBasisAuto(YGNodeRef node);
WIN_EXPORT YGValue YGNodeStyleGetFlexBasis(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetPosition(
YGNodeRef node,
YGEdge edge,
float position);
WIN_EXPORT void YGNodeStyleSetPositionPercent(
YGNodeRef node,
YGEdge edge,
float position);
WIN_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge);
WIN_EXPORT void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float margin);
WIN_EXPORT void YGNodeStyleSetMarginPercent(
YGNodeRef node,
YGEdge edge,
float margin);
WIN_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge);
WIN_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge);
WIN_EXPORT void YGNodeStyleSetPadding(
YGNodeRef node,
YGEdge edge,
float padding);
WIN_EXPORT void YGNodeStyleSetPaddingPercent(
YGNodeRef node,
YGEdge edge,
float padding);
WIN_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge);
WIN_EXPORT void YGNodeStyleSetBorder(YGNodeRef node, YGEdge edge, float border);
WIN_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge);
WIN_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width);
WIN_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float width);
WIN_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node);
WIN_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float height);
WIN_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float height);
WIN_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node);
WIN_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetMinWidth(YGNodeRef node, float minWidth);
WIN_EXPORT void YGNodeStyleSetMinWidthPercent(YGNodeRef node, float minWidth);
WIN_EXPORT YGValue YGNodeStyleGetMinWidth(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetMinHeight(YGNodeRef node, float minHeight);
WIN_EXPORT void YGNodeStyleSetMinHeightPercent(YGNodeRef node, float minHeight);
WIN_EXPORT YGValue YGNodeStyleGetMinHeight(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetMaxWidth(YGNodeRef node, float maxWidth);
WIN_EXPORT void YGNodeStyleSetMaxWidthPercent(YGNodeRef node, float maxWidth);
WIN_EXPORT YGValue YGNodeStyleGetMaxWidth(YGNodeConstRef node);
WIN_EXPORT void YGNodeStyleSetMaxHeight(YGNodeRef node, float maxHeight);
WIN_EXPORT void YGNodeStyleSetMaxHeightPercent(YGNodeRef node, float maxHeight);
WIN_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef node);
// Yoga specific properties, not compatible with flexbox specification Aspect
// ratio control the size of the undefined dimension of a node. Aspect ratio is
// encoded as a floating point value width/height. e.g. A value of 2 leads to a
// node with a width twice the size of its height while a value of 0.5 gives the
// opposite effect.
//
// - On a node with a set width/height aspect ratio control the size of the
// unset dimension
// - On a node with a set flex basis aspect ratio controls the size of the node
// in the cross axis if unset
// - On a node with a measure function aspect ratio works as though the measure
// function measures the flex basis
// - On a node with flex grow/shrink aspect ratio controls the size of the node
// in the cross axis if unset
// - Aspect ratio takes min/max dimensions into account
WIN_EXPORT void YGNodeStyleSetAspectRatio(YGNodeRef node, float aspectRatio);
WIN_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node);
WIN_EXPORT float YGNodeLayoutGetLeft(YGNodeRef node);
WIN_EXPORT float YGNodeLayoutGetTop(YGNodeRef node);
WIN_EXPORT float YGNodeLayoutGetRight(YGNodeRef node);
WIN_EXPORT float YGNodeLayoutGetBottom(YGNodeRef node);
WIN_EXPORT float YGNodeLayoutGetWidth(YGNodeRef node);
WIN_EXPORT float YGNodeLayoutGetHeight(YGNodeRef node);
WIN_EXPORT YGDirection YGNodeLayoutGetDirection(YGNodeRef node);
WIN_EXPORT bool YGNodeLayoutGetHadOverflow(YGNodeRef node);
bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(YGNodeRef node);
// Get the computed values for these nodes after performing layout. If they were
// set using point values then the returned value will be the same as
// YGNodeStyleGetXXX. However if they were set using a percentage value then the
// returned value is the computed value used during layout.
WIN_EXPORT float YGNodeLayoutGetMargin(YGNodeRef node, YGEdge edge);
WIN_EXPORT float YGNodeLayoutGetBorder(YGNodeRef node, YGEdge edge);
WIN_EXPORT float YGNodeLayoutGetPadding(YGNodeRef node, YGEdge edge);
WIN_EXPORT void YGConfigSetLogger(YGConfigRef config, YGLogger logger);
WIN_EXPORT void YGAssert(bool condition, const char* message);
WIN_EXPORT void YGAssertWithNode(
YGNodeRef node,
bool condition,
const char* message);
WIN_EXPORT void YGAssertWithConfig(
YGConfigRef config,
bool condition,
const char* message);
// Set this to number of pixels in 1 point to round calculation results If you
// want to avoid rounding - set PointScaleFactor to 0
WIN_EXPORT void YGConfigSetPointScaleFactor(
YGConfigRef config,
float pixelsInPoint);
void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
YGConfigRef config,
bool shouldDiffLayout);
// Yoga previously had an error where containers would take the maximum space
// possible instead of the minimum like they are supposed to. In practice this
// resulted in implicit behaviour similar to align-self: stretch; Because this
// was such a long-standing bug we must allow legacy users to switch back to
// this behaviour.
WIN_EXPORT void YGConfigSetUseLegacyStretchBehaviour(
YGConfigRef config,
bool useLegacyStretchBehaviour);
// YGConfig
WIN_EXPORT YGConfigRef YGConfigNew(void);
WIN_EXPORT void YGConfigFree(YGConfigRef config);
WIN_EXPORT void YGConfigCopy(YGConfigRef dest, YGConfigRef src);
WIN_EXPORT int32_t YGConfigGetInstanceCount(void);
WIN_EXPORT void YGConfigSetExperimentalFeatureEnabled(
YGConfigRef config,
YGExperimentalFeature feature,
bool enabled);
WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(
YGConfigRef config,
YGExperimentalFeature feature);
// Using the web defaults is the preferred configuration for new projects. Usage
// of non web defaults should be considered as legacy.
WIN_EXPORT void YGConfigSetUseWebDefaults(YGConfigRef config, bool enabled);
WIN_EXPORT bool YGConfigGetUseWebDefaults(YGConfigRef config);
WIN_EXPORT void YGConfigSetCloneNodeFunc(
YGConfigRef config,
YGCloneNodeFunc callback);
// Export only for C#
WIN_EXPORT YGConfigRef YGConfigGetDefault(void);
WIN_EXPORT void YGConfigSetContext(YGConfigRef config, void* context);
WIN_EXPORT void* YGConfigGetContext(YGConfigRef config);
WIN_EXPORT float YGRoundValueToPixelGrid(
float value,
float pointScaleFactor,
bool forceCeil,
bool forceFloor);
YG_EXTERN_C_END
#ifdef __cplusplus
#include <functional>
#include <vector>
// Calls f on each node in the tree including the given node argument.
void YGTraversePreOrder(
YGNodeRef node,
std::function<void(YGNodeRef node)>&& f);
void YGNodeSetChildren(YGNodeRef owner, const std::vector<YGNodeRef>& children);
#endif

87
sources/3rdparty/yoga/event/event.cpp vendored Normal file
View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "event.h"
#include <atomic>
#include <memory>
#include <stdexcept>
namespace facebook {
namespace yoga {
const char* LayoutPassReasonToString(const LayoutPassReason value) {
switch (value) {
case LayoutPassReason::kInitial:
return "initial";
case LayoutPassReason::kAbsLayout:
return "abs_layout";
case LayoutPassReason::kStretch:
return "stretch";
case LayoutPassReason::kMultilineStretch:
return "multiline_stretch";
case LayoutPassReason::kFlexLayout:
return "flex_layout";
case LayoutPassReason::kMeasureChild:
return "measure";
case LayoutPassReason::kAbsMeasureChild:
return "abs_measure";
case LayoutPassReason::kFlexMeasure:
return "flex_measure";
default:
return "unknown";
}
}
namespace {
struct Node {
std::function<Event::Subscriber> subscriber = nullptr;
Node* next = nullptr;
Node(std::function<Event::Subscriber>&& subscriber)
: subscriber{std::move(subscriber)} {}
};
std::atomic<Node*> subscribers{nullptr};
Node* push(Node* newHead) {
Node* oldHead;
do {
oldHead = subscribers.load(std::memory_order_relaxed);
if (newHead != nullptr) {
newHead->next = oldHead;
}
} while (!subscribers.compare_exchange_weak(
oldHead, newHead, std::memory_order_release, std::memory_order_relaxed));
return oldHead;
}
} // namespace
void Event::reset() {
auto head = push(nullptr);
while (head != nullptr) {
auto current = head;
head = head->next;
delete current;
}
}
void Event::subscribe(std::function<Subscriber>&& subscriber) {
push(new Node{std::move(subscriber)});
}
void Event::publish(const YGNode& node, Type eventType, const Data& eventData) {
for (auto subscriber = subscribers.load(std::memory_order_relaxed);
subscriber != nullptr;
subscriber = subscriber->next) {
subscriber->subscriber(node, eventType, eventData);
}
}
} // namespace yoga
} // namespace facebook

145
sources/3rdparty/yoga/event/event.h vendored Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <functional>
#include <vector>
#include <array>
#include <yoga/YGEnums.h>
struct YGConfig;
struct YGNode;
namespace facebook {
namespace yoga {
enum struct LayoutType : int {
kLayout = 0,
kMeasure = 1,
kCachedLayout = 2,
kCachedMeasure = 3
};
enum struct LayoutPassReason : int {
kInitial = 0,
kAbsLayout = 1,
kStretch = 2,
kMultilineStretch = 3,
kFlexLayout = 4,
kMeasureChild = 5,
kAbsMeasureChild = 6,
kFlexMeasure = 7,
COUNT
};
struct LayoutData {
int layouts;
int measures;
int maxMeasureCache;
int cachedLayouts;
int cachedMeasures;
int measureCallbacks;
std::array<int, static_cast<uint8_t>(LayoutPassReason::COUNT)>
measureCallbackReasonsCount;
};
const char* LayoutPassReasonToString(const LayoutPassReason value);
struct YOGA_EXPORT Event {
enum Type {
NodeAllocation,
NodeDeallocation,
NodeLayout,
LayoutPassStart,
LayoutPassEnd,
MeasureCallbackStart,
MeasureCallbackEnd,
NodeBaselineStart,
NodeBaselineEnd,
};
class Data;
using Subscriber = void(const YGNode&, Type, Data);
using Subscribers = std::vector<std::function<Subscriber>>;
template <Type E>
struct TypedData {};
class Data {
const void* data_;
public:
template <Type E>
Data(const TypedData<E>& data) : data_{&data} {}
template <Type E>
const TypedData<E>& get() const {
return *static_cast<const TypedData<E>*>(data_);
};
};
static void reset();
static void subscribe(std::function<Subscriber>&& subscriber);
template <Type E>
static void publish(const YGNode& node, const TypedData<E>& eventData = {}) {
#ifdef YG_ENABLE_EVENTS
publish(node, E, Data{eventData});
#endif
}
template <Type E>
static void publish(const YGNode* node, const TypedData<E>& eventData = {}) {
publish<E>(*node, eventData);
}
private:
static void publish(const YGNode&, Type, const Data&);
};
template <>
struct Event::TypedData<Event::NodeAllocation> {
YGConfig* config;
};
template <>
struct Event::TypedData<Event::NodeDeallocation> {
YGConfig* config;
};
template <>
struct Event::TypedData<Event::LayoutPassStart> {
void* layoutContext;
};
template <>
struct Event::TypedData<Event::LayoutPassEnd> {
void* layoutContext;
LayoutData* layoutData;
};
template <>
struct Event::TypedData<Event::MeasureCallbackEnd> {
void* layoutContext;
float width;
YGMeasureMode widthMeasureMode;
float height;
YGMeasureMode heightMeasureMode;
float measuredWidth;
float measuredHeight;
const LayoutPassReason reason;
};
template <>
struct Event::TypedData<Event::NodeLayout> {
LayoutType layoutType;
void* layoutContext;
};
} // namespace yoga
} // namespace facebook

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "experiments.h"
#include <bitset>
namespace facebook {
namespace yoga {
namespace internal {
namespace detail {
extern std::bitset<sizeof(int)> enabledExperiments;
} // namespace detail
inline bool isEnabled(Experiment experiment) {
return detail::enabledExperiments.test(static_cast<size_t>(experiment));
}
inline void disableAllExperiments() {
detail::enabledExperiments = 0;
}
} // namespace internal
} // namespace yoga
} // namespace facebook

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "experiments.h"
#include "experiments-inl.h"
namespace facebook {
namespace yoga {
namespace internal {
namespace detail {
std::bitset<sizeof(int)> enabledExperiments = 0;
} // namespace detail
void enable(Experiment experiment) {
detail::enabledExperiments.set(static_cast<size_t>(experiment));
}
void disable(Experiment experiment) {
detail::enabledExperiments.reset(static_cast<size_t>(experiment));
}
bool toggle(Experiment experiment) {
auto bit = static_cast<size_t>(experiment);
auto previousState = detail::enabledExperiments.test(bit);
detail::enabledExperiments.flip(bit);
return previousState;
}
} // namespace internal
} // namespace yoga
} // namespace facebook

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cstddef>
namespace facebook {
namespace yoga {
namespace internal {
enum struct Experiment : size_t {
kDoubleMeasureCallbacks,
};
void enable(Experiment);
void disable(Experiment);
bool toggle(Experiment);
} // namespace internal
} // namespace yoga
} // namespace facebook

68
sources/3rdparty/yoga/log.cpp vendored Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "log.h"
#include "Yoga.h"
#include "YGConfig.h"
#include "YGNode.h"
namespace facebook {
namespace yoga {
namespace detail {
namespace {
void vlog(
YGConfig* config,
YGNode* node,
YGLogLevel level,
void* context,
const char* format,
va_list args) {
YGConfig* logConfig = config != nullptr ? config : YGConfigGetDefault();
logConfig->log(logConfig, node, level, context, format, args);
if (level == YGLogLevelFatal) {
abort();
}
}
} // namespace
YOGA_EXPORT void Log::log(
YGNode* node,
YGLogLevel level,
void* context,
const char* format,
...) noexcept {
va_list args;
va_start(args, format);
vlog(
node == nullptr ? nullptr : node->getConfig(),
node,
level,
context,
format,
args);
va_end(args);
}
void Log::log(
YGConfig* config,
YGLogLevel level,
void* context,
const char* format,
...) noexcept {
va_list args;
va_start(args, format);
vlog(config, nullptr, level, context, format, args);
va_end(args);
}
} // namespace detail
} // namespace yoga
} // namespace facebook

38
sources/3rdparty/yoga/log.h vendored Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "YGEnums.h"
struct YGNode;
struct YGConfig;
namespace facebook {
namespace yoga {
namespace detail {
struct Log {
static void log(
YGNode* node,
YGLogLevel level,
void*,
const char* message,
...) noexcept;
static void log(
YGConfig* config,
YGLogLevel level,
void*,
const char* format,
...) noexcept;
};
} // namespace detail
} // namespace yoga
} // namespace facebook

View File

@@ -24,6 +24,7 @@ namespace e2d::bindings::high
void bind_colliders(sol::state& l);
void bind_flipbook_player(sol::state& l);
void bind_label(sol::state& l);
void bind_layout(sol::state& l);
void bind_model_renderer(sol::state& l);
void bind_named(sol::state& l);
void bind_renderer(sol::state& l);
@@ -50,6 +51,7 @@ namespace e2d::bindings
high::bind_colliders(l);
high::bind_flipbook_player(l);
high::bind_label(l);
high::bind_layout(l);
high::bind_model_renderer(l);
high::bind_named(l);
high::bind_renderer(l);

View File

@@ -15,13 +15,25 @@ namespace e2d::bindings::high
l.new_usertype<gcomponent<label>>("label",
sol::no_constructor,
"dirty", sol::property(
[](const gcomponent<label>& c) -> bool {
return labels::is_dirty(c);
},
[](gcomponent<label>& c, bool yesno){
if ( yesno ) {
labels::mark_dirty(c);
} else {
labels::unmark_dirty(c);
}
}
),
"text", sol::property(
[](const gcomponent<label>& c) -> str {
return c->text();
},
[](gcomponent<label>& c, str_view v){
c->text(str(v));
c.owner().component<label::dirty>().ensure();
labels::change_text(c, str(v));
}),
"font", sol::property(
@@ -29,8 +41,7 @@ namespace e2d::bindings::high
return c->font();
},
[](gcomponent<label>& c, const font_asset::ptr& v){
c->font(v);
c.owner().component<label::dirty>().ensure();
labels::change_font(c, v);
}),
"tint", sol::property(
@@ -38,8 +49,7 @@ namespace e2d::bindings::high
return c->tint();
},
[](gcomponent<label>& c, const color32& v){
c->tint(v);
c.owner().component<label::dirty>().ensure();
labels::change_tint(c, v);
}),
"halign", sol::property(
@@ -47,8 +57,7 @@ namespace e2d::bindings::high
return c->halign();
},
[](gcomponent<label>& c, label::haligns v){
c->halign(v);
c.owner().component<label::dirty>().ensure();
labels::change_halign(c, v);
}),
"valign", sol::property(
@@ -56,8 +65,7 @@ namespace e2d::bindings::high
return c->valign();
},
[](gcomponent<label>& c, label::valigns v){
c->valign(v);
c.owner().component<label::dirty>().ensure();
labels::change_valign(c, v);
}),
"leading", sol::property(
@@ -65,8 +73,7 @@ namespace e2d::bindings::high
return c->leading();
},
[](gcomponent<label>& c, f32 v){
c->leading(v);
c.owner().component<label::dirty>().ensure();
labels::change_leading(c, v);
}),
"tracking", sol::property(
@@ -74,8 +81,7 @@ namespace e2d::bindings::high
return c->tracking();
},
[](gcomponent<label>& c, f32 v){
c->tracking(v);
c.owner().component<label::dirty>().ensure();
labels::change_tracking(c, v);
}),
"text_width", sol::property(
@@ -83,8 +89,7 @@ namespace e2d::bindings::high
return c->text_width();
},
[](gcomponent<label>& c, f32 v){
c->text_width(v);
c.owner().component<label::dirty>().ensure();
labels::change_text_width(c, v);
}),
"glyph_dilate", sol::property(
@@ -92,8 +97,7 @@ namespace e2d::bindings::high
return c->glyph_dilate();
},
[](gcomponent<label>& c, f32 v){
c->glyph_dilate(v);
c.owner().component<label::dirty>().ensure();
labels::change_glyph_dilate(c, v);
}),
"outline_width", sol::property(
@@ -101,8 +105,7 @@ namespace e2d::bindings::high
return c->outline_width();
},
[](gcomponent<label>& c, f32 v){
c->outline_width(v);
c.owner().component<label::dirty>().ensure();
labels::change_outline_width(c, v);
}),
"outline_color", sol::property(
@@ -110,8 +113,7 @@ namespace e2d::bindings::high
return c->outline_color();
},
[](gcomponent<label>& c, const color32& v){
c->outline_color(v);
c.owner().component<label::dirty>().ensure();
labels::change_outline_color(c, v);
})
);

View File

@@ -0,0 +1,153 @@
/*******************************************************************************
* 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/layout.hpp>
namespace e2d::bindings::high
{
void bind_layout(sol::state& l) {
l.new_usertype<gcomponent<layout>>("layout",
sol::no_constructor,
"enable", [](gcomponent<layout>& c){
c.owner().component<disabled<layout>>().remove();
layouts::mark_dirty(c);
},
"disable", [](gcomponent<layout>& c){
c.owner().component<disabled<layout>>().ensure();
layouts::mark_dirty(c);
},
"enabled", sol::property(
[](const gcomponent<layout>& c) -> bool {
return !c.owner().component<disabled<layout>>().exists();
},
[](gcomponent<layout>& c, bool yesno){
if ( yesno ) {
c.owner().component<disabled<layout>>().remove();
} else {
c.owner().component<disabled<layout>>().ensure();
}
layouts::mark_dirty(c);
}
),
"disabled", sol::property(
[](const gcomponent<layout>& c) -> bool {
return c.owner().component<disabled<layout>>().exists();
},
[](gcomponent<layout>& c, bool yesno){
if ( yesno ) {
c.owner().component<disabled<layout>>().ensure();
} else {
c.owner().component<disabled<layout>>().remove();
}
layouts::mark_dirty(c);
}
),
"dirty", sol::property(
[](const gcomponent<layout>& c) -> bool {
return layouts::is_dirty(c);
},
[](gcomponent<layout>& c, bool yesno){
if ( yesno ) {
layouts::mark_dirty(c);
} else {
layouts::unmark_dirty(c);
}
}
),
"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(
[](const gcomponent<layout>& c) -> layout::directions {
return c->direction();
},
[](gcomponent<layout>& c, layout::directions v){
layouts::change_direction(c, v);
}),
"size", sol::property(
[](const gcomponent<layout>& c) -> v2f {
return c->size();
},
[](gcomponent<layout>& c, const v2f& v){
layouts::change_size(c, v);
}),
"margin", sol::property(
[](const gcomponent<layout>& c) -> v2f {
return c->margin();
},
[](gcomponent<layout>& c, const v2f& v){
layouts::change_margin(c, v);
}),
"padding", sol::property(
[](const gcomponent<layout>& c) -> v2f {
return c->padding();
},
[](gcomponent<layout>& c, const v2f& v){
layouts::change_padding(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},
l["layout"].get_or_create<sol::table>()
.new_enum<layout::directions>("directions", {
LAYOUT_DIRECTION_PAIR(row)
LAYOUT_DIRECTION_PAIR(row_reversed)
LAYOUT_DIRECTION_PAIR(column)
LAYOUT_DIRECTION_PAIR(column_reversed)
});
#undef LAYOUT_DIRECTION_PAIR
}
}

View File

@@ -201,11 +201,22 @@ namespace e2d
const char* component_inspector<label>::title = ICON_FA_PARAGRAPH " label";
void component_inspector<label>::operator()(gcomponent<label>& c) const {
if ( bool dirty = c.owner().component<label::dirty>().exists();
ImGui::Checkbox("dirty", &dirty) )
{
if ( dirty ) {
labels::mark_dirty(c);
} else {
labels::unmark_dirty(c);
}
}
ImGui::Separator();
if ( str text = c->text();
ImGui::InputTextMultiline("text", &text) )
{
c->text(std::move(text));
c.owner().component<label::dirty>().ensure();
labels::change_text(c, std::move(text));
}
///TODO(BlackMat): add 'font' inspector
@@ -213,64 +224,209 @@ namespace e2d
if ( color tint = color(c->tint());
ImGui::ColorEdit4("tint", tint.data()) )
{
c->tint(color32(tint));
c.owner().component<label::dirty>().ensure();
labels::change_tint(c, color32(tint));
}
if ( label::haligns halign = c->halign();
imgui_utils::show_enum_combo_box("halign", &halign) )
{
c->halign(halign);
c.owner().component<label::dirty>().ensure();
labels::change_halign(c, halign);
}
if ( label::valigns valign = c->valign();
imgui_utils::show_enum_combo_box("valign", &valign) )
{
c->valign(valign);
c.owner().component<label::dirty>().ensure();
labels::change_valign(c, valign);
}
if ( f32 leading = c->leading();
ImGui::DragFloat("leading", &leading, 0.01f) )
{
c->leading(leading);
c.owner().component<label::dirty>().ensure();
labels::change_leading(c, leading);
}
if ( f32 tracking = c->tracking();
ImGui::DragFloat("tracking", &tracking, 0.01f) )
{
c->tracking(tracking);
c.owner().component<label::dirty>().ensure();
labels::change_tracking(c, tracking);
}
if ( f32 text_width = c->text_width();
ImGui::DragFloat("text_width", &text_width, 1.f) )
{
c->text_width(text_width);
c.owner().component<label::dirty>().ensure();
labels::change_text_width(c, text_width);
}
if ( f32 glyph_dilate = c->glyph_dilate();
ImGui::SliderFloat("glyph_dilate", &glyph_dilate, -1.f, 1.f) )
{
c->glyph_dilate(glyph_dilate);
c.owner().component<label::dirty>().ensure();
labels::change_glyph_dilate(c, glyph_dilate);
}
if ( f32 outline_width = c->outline_width();
ImGui::SliderFloat("outline_width", &outline_width, 0.f, 1.f) )
{
c->outline_width(outline_width);
c.owner().component<label::dirty>().ensure();
labels::change_outline_width(c, outline_width);
}
if ( color outline_color = color(c->outline_color());
ImGui::ColorEdit4("outline_color", outline_color.data()) )
{
c->outline_color(color32(outline_color));
c.owner().component<label::dirty>().ensure();
labels::change_outline_color(c, color32(outline_color));
}
}
void component_inspector<label>::operator()(
gcomponent<label>& c,
gizmos_context& ctx) const
{
if ( c->font() && c->text_width() > 0.f ) {
const f32 corner_height = 0.2f * c->font()->content().info().line_height;
const color32 line_color = ctx.selected() ? color32(255,255,255) : color32(127,127,127);
const color32 corner_color = ctx.selected() ? color32(0,255,0) : color32(0,127,0);
v2f ox = v2f::zero();
switch ( c->halign() ) {
case label::haligns::left:
ox = +0.5f * v2f::unit_x() * c->text_width();
break;
case label::haligns::center:
ox = v2f::zero();
break;
case label::haligns::right:
ox = -0.5f * v2f::unit_x() * c->text_width();
break;
default:
E2D_ASSERT_MSG(false, "unexpected label halign");
break;
}
v2f oy = v2f::zero();
switch ( c->valign() ) {
case label::valigns::top:
oy = -v2f::unit_y() * corner_height;
break;
case label::valigns::center:
oy = v2f::zero();
break;
case label::valigns::bottom:
oy = +v2f::unit_y() * corner_height;
break;
case label::valigns::baseline:
oy = v2f::zero();
break;
default:
E2D_ASSERT_MSG(false, "unexpected label valign");
break;
}
ctx.draw_line(
ox - 0.5f * v2f::unit_x() * c->text_width(),
ox + 0.5f * v2f::unit_x() * c->text_width(),
line_color);
ctx.draw_line(
oy - v2f::unit_y() * corner_height,
oy + v2f::unit_y() * corner_height,
corner_color);
}
}
}
namespace e2d::labels
{
gcomponent<label> mark_dirty(gcomponent<label> self) {
if ( self ) {
self.owner().component<label::dirty>().ensure();
}
return self;
}
gcomponent<label> unmark_dirty(gcomponent<label> self) {
if ( self ) {
self.owner().component<label::dirty>().remove();
}
return self;
}
bool is_dirty(const const_gcomponent<label>& self) noexcept {
return self.owner().component<label::dirty>().exists();
}
gcomponent<label> change_text(gcomponent<label> self, str value) {
if ( self ) {
self->text(std::move(value));
}
return mark_dirty(self);
}
gcomponent<label> change_font(gcomponent<label> self, const font_asset::ptr& value) {
if ( self ) {
self->font(value);
}
return mark_dirty(self);
}
gcomponent<label> change_tint(gcomponent<label> self, const color32& value) {
if ( self ) {
self->tint(value);
}
return mark_dirty(self);
}
gcomponent<label> change_halign(gcomponent<label> self, label::haligns value) {
if ( self ) {
self->halign(value);
}
return mark_dirty(self);
}
gcomponent<label> change_valign(gcomponent<label> self, label::valigns value) {
if ( self ) {
self->valign(value);
}
return mark_dirty(self);
}
gcomponent<label> change_leading(gcomponent<label> self, f32 value) {
if ( self ) {
self->leading(value);
}
return mark_dirty(self);
}
gcomponent<label> change_tracking(gcomponent<label> self, f32 value) {
if ( self ) {
self->tracking(value);
}
return mark_dirty(self);
}
gcomponent<label> change_text_width(gcomponent<label> self, f32 value) {
if ( self ) {
self->text_width(value);
}
return mark_dirty(self);
}
gcomponent<label> change_glyph_dilate(gcomponent<label> self, f32 value) {
if ( self ) {
self->glyph_dilate(value);
}
return mark_dirty(self);
}
gcomponent<label> change_outline_width(gcomponent<label> self, f32 value) {
if ( self ) {
self->outline_width(value);
}
return mark_dirty(self);
}
gcomponent<label> change_outline_color(gcomponent<label> self, const color32& value) {
if ( self ) {
self->outline_color(value);
}
return mark_dirty(self);
}
}

View File

@@ -0,0 +1,308 @@
/*******************************************************************************
* 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/layout.hpp>
#include <enduro2d/high/components/actor.hpp>
namespace e2d
{
const char* factory_loader<layout>::schema_source = R"json({
"type" : "object",
"required" : [],
"additionalProperties" : false,
"properties" : {
"halign" : { "$ref": "#/definitions/haligns" },
"valign" : { "$ref": "#/definitions/valigns" },
"direction" : { "$ref": "#/definitions/directions" },
"size" : { "$ref": "#/common_definitions/v2" },
"margin" : { "$ref": "#/common_definitions/v2" },
"padding" : { "$ref": "#/common_definitions/v2" }
},
"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" : {
"type" : "string",
"enum" : [
"row",
"row_reversed",
"column",
"column_reversed"
]
}
}
})json";
bool factory_loader<layout>::operator()(
layout& component,
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") ) {
layout::directions direction = component.direction();
if ( !json_utils::try_parse_value(ctx.root["direction"], direction) ) {
the<debug>().error("LAYOUT: Incorrect formatting of 'direction' property");
return false;
}
component.direction(direction);
}
if ( ctx.root.HasMember("size") ) {
v2f size = component.size();
if ( !json_utils::try_parse_value(ctx.root["size"], size) ) {
the<debug>().error("LAYOUT: 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("LAYOUT: 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("LAYOUT: Incorrect formatting of 'padding' property");
return false;
}
component.padding(padding);
}
return true;
}
bool factory_loader<layout>::operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const
{
E2D_UNUSED(dependencies, ctx);
return true;
}
}
namespace e2d
{
const char* factory_loader<layout::dirty>::schema_source = R"json({
"type" : "object",
"required" : [],
"additionalProperties" : false,
"properties" : {}
})json";
bool factory_loader<layout::dirty>::operator()(
layout::dirty& component,
const fill_context& ctx) const
{
E2D_UNUSED(component, ctx);
return true;
}
bool factory_loader<layout::dirty>::operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const
{
E2D_UNUSED(dependencies, ctx);
return true;
}
}
namespace e2d
{
const char* component_inspector<layout>::title = ICON_FA_BARS " layout";
void component_inspector<layout>::operator()(gcomponent<layout>& c) const {
if ( bool dirty = c.owner().component<layout::dirty>().exists();
ImGui::Checkbox("dirty", &dirty) )
{
if ( dirty ) {
layouts::mark_dirty(c);
} else {
layouts::unmark_dirty(c);
}
}
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();
imgui_utils::show_enum_combo_box("direction", &direction) )
{
layouts::change_direction(c, direction);
}
if ( v2f size = c->size();
ImGui::DragFloat2("size", size.data(), 1.f) )
{
layouts::change_size(c, size);
}
if ( v2f margin = c->margin();
ImGui::DragFloat2("margin", margin.data(), 1.f) )
{
layouts::change_margin(c, margin);
}
if ( v2f padding = c->padding();
ImGui::DragFloat2("padding", padding.data(), 1.f) )
{
layouts::change_padding(c, padding);
}
}
void component_inspector<layout>::operator()(
gcomponent<layout>& c,
gizmos_context& ctx) const
{
ctx.draw_wire_rect(
c->size() * 0.5f,
c->size(),
ctx.selected() ? color32(255,255,255) : color32(127,127,127));
if ( ctx.selected() ) {
if ( c->margin() != v2f::zero() ) {
ctx.draw_wire_rect(
c->size() * 0.5f,
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));
}
}
}
}
namespace e2d::layouts
{
gcomponent<layout> mark_dirty(gcomponent<layout> self) {
if ( self ) {
self.owner().component<layout::dirty>().ensure();
}
return self;
}
gcomponent<layout> unmark_dirty(gcomponent<layout> self) {
if ( self ) {
self.owner().component<layout::dirty>().remove();
}
return self;
}
bool is_dirty(const const_gcomponent<layout>& self) noexcept {
return self.owner().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) {
if ( self ) {
self->direction(value);
}
return mark_dirty(self);
}
gcomponent<layout> change_size(gcomponent<layout> self, const v2f& value) {
if ( self ) {
self->size(value);
}
mark_dirty(find_parent_layout(self));
return mark_dirty(self);
}
gcomponent<layout> change_margin(gcomponent<layout> self, const v2f& value) {
if ( self ) {
self->margin(value);
}
mark_dirty(find_parent_layout(self));
return mark_dirty(self);
}
gcomponent<layout> change_padding(gcomponent<layout> self, const v2f& value) {
if ( self ) {
self->padding(value);
}
mark_dirty(find_parent_layout(self));
return mark_dirty(self);
}
gcomponent<layout> find_parent_layout(const_gcomponent<layout> self) noexcept {
const_gcomponent<actor> self_actor = self.owner().component<actor>();
return self_actor
? nodes::find_component_from_parents<layout>(self_actor->node())
: gcomponent<layout>();
}
}

View File

@@ -22,6 +22,7 @@
#include <enduro2d/high/components/events.hpp>
#include <enduro2d/high/components/flipbook_player.hpp>
#include <enduro2d/high/components/label.hpp>
#include <enduro2d/high/components/layout.hpp>
#include <enduro2d/high/components/model_renderer.hpp>
#include <enduro2d/high/components/named.hpp>
#include <enduro2d/high/components/renderer.hpp>
@@ -35,6 +36,7 @@
#include <enduro2d/high/systems/frame_system.hpp>
#include <enduro2d/high/systems/gizmos_system.hpp>
#include <enduro2d/high/systems/label_system.hpp>
#include <enduro2d/high/systems/layout_system.hpp>
#include <enduro2d/high/systems/render_system.hpp>
#include <enduro2d/high/systems/script_system.hpp>
#include <enduro2d/high/systems/spine_system.hpp>
@@ -69,6 +71,8 @@ namespace
.add_system<gizmos_system>())
.feature<struct label_feature>(ecs::feature()
.add_system<label_system>())
.feature<struct layout_feature>(ecs::feature()
.add_system<layout_system>())
.feature<struct render_feature>(ecs::feature()
.add_system<render_system>())
.feature<struct script_feature>(ecs::feature()
@@ -193,6 +197,8 @@ namespace e2d
.register_component<flipbook_player>("flipbook_player")
.register_component<label>("label")
.register_component<label::dirty>("label.dirty")
.register_component<layout>("layout")
.register_component<layout::dirty>("layout.dirty")
.register_component<model_renderer>("model_renderer")
.register_component<named>("named")
.register_component<renderer>("renderer")
@@ -217,6 +223,8 @@ namespace e2d
.register_component<flipbook_player>("flipbook_player")
.register_component<label>("label")
//.register_component<label::dirty>("label.dirty")
.register_component<layout>("layout")
//.register_component<layout::dirty>("layout.dirty")
.register_component<model_renderer>("model_renderer")
.register_component<named>("named")
.register_component<renderer>("renderer")

View File

@@ -0,0 +1,298 @@
/*******************************************************************************
* 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/layout_system.hpp>
#include <enduro2d/high/components/actor.hpp>
#include <enduro2d/high/components/disabled.hpp>
#include <enduro2d/high/components/layout.hpp>
#include <3rdparty/yoga/Yoga.h>
namespace
{
using namespace e2d;
struct yogo_node final {
using node_ptr = std::shared_ptr<YGNode>;
node_ptr as_item{YGNodeNew(), YGNodeFree};
node_ptr as_root{YGNodeNew(), YGNodeFree};
};
}
namespace
{
using namespace e2d;
void update_yogo_node(const yogo_node& yn, const layout& l, const actor& a) {
switch ( l.direction() ) {
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:
E2D_ASSERT_MSG(false, "unexpected layout direction");
break;
}
switch ( l.direction() ) {
case layout::directions::row:
case layout::directions::row_reversed:
switch ( l.halign() ) {
case layout::haligns::left:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyFlexStart);
break;
case layout::haligns::center:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyCenter);
break;
case layout::haligns::right:
YGNodeStyleSetJustifyContent(yn.as_root.get(), YGJustifyFlexEnd);
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:
E2D_ASSERT_MSG(false, "unexpected layout mode");
break;
}
{
YGNodeStyleSetWidth(yn.as_root.get(), l.size().x);
YGNodeStyleSetHeight(yn.as_root.get(), l.size().y);
YGNodeStyleSetPadding(yn.as_root.get(), YGEdgeHorizontal, l.padding().x);
YGNodeStyleSetPadding(yn.as_root.get(), YGEdgeVertical, l.padding().y);
}
{
const v2f& scale = a.node()
? a.node()->scale()
: v2f::unit();
YGNodeStyleSetWidth(yn.as_item.get(), l.size().x * scale.x);
YGNodeStyleSetHeight(yn.as_item.get(), l.size().y * scale.y);
YGNodeStyleSetMargin(yn.as_item.get(), YGEdgeHorizontal, l.margin().x * scale.x);
YGNodeStyleSetMargin(yn.as_item.get(), YGEdgeVertical, l.margin().y * scale.y);
}
}
}
namespace
{
using namespace e2d;
void process_yogo_nodes(ecs::registry& owner) {
ecsex::remove_all_components_with_disposer<yogo_node>(
owner,
[](ecs::entity e, const yogo_node&){
if ( const actor* a = e.find_component<actor>();
a && a->node() && a->node()->owner() )
{
gcomponent<layout> l{a->node()->owner()};
layouts::mark_dirty(l);
layouts::mark_dirty(layouts::find_parent_layout(l));
}
},
!ecs::exists_all<
actor,
layout>() ||
ecs::exists_any<
disabled<actor>,
disabled<layout>>());
owner.for_joined_components<layout, actor>([](
ecs::entity e,
const layout&,
const actor& a)
{
e.ensure_component<yogo_node>();
if ( a.node() && a.node()->owner() ) {
gcomponent<layout> l{a.node()->owner()};
layouts::mark_dirty(l);
layouts::mark_dirty(layouts::find_parent_layout(l));
}
},
!ecs::exists_any<
yogo_node,
disabled<actor>,
disabled<layout>>());
}
void process_dirty_layouts(ecs::registry& owner) {
owner.for_joined_components<layout::dirty, yogo_node, layout, actor>([](
const ecs::const_entity&,
const layout::dirty&,
const yogo_node& root_yn,
const layout& root_l,
const actor& root_a)
{
update_yogo_node(root_yn, root_l, root_a);
});
owner.for_joined_components<layout::dirty, yogo_node, actor>([](
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(),
std::back_inserter(items));
E2D_DEFER([&root_yn](){
YGNodeRemoveAllChildren(root_yn.as_root.get());
});
for ( const auto& item : items ) {
if ( const auto& item_yn = item.owner().component<yogo_node>() ) {
YGNodeInsertChild(
root_yn.as_root.get(),
item_yn->as_item.get(),
YGNodeGetChildCount(root_yn.as_root.get()));
}
}
YGNodeCalculateLayout(
root_yn.as_root.get(),
YGUndefined,
YGUndefined,
YGDirectionLTR);
for ( const auto& item : items ) {
gcomponent<actor> item_a = item.owner().component<actor>();
const_gcomponent<yogo_node> item_yn = item.owner().component<yogo_node>();
if ( item_a && item_a->node() && item_yn && item_yn->as_item ) {
item_a->node()->translation(v2f(
YGNodeLayoutGetLeft(item_yn->as_item.get()),
YGNodeLayoutGetTop(item_yn->as_item.get())));
}
}
});
owner.remove_all_components<layout::dirty>();
}
}
namespace e2d
{
//
// layout_system::internal_state
//
class layout_system::internal_state final : private noncopyable {
public:
internal_state() = default;
~internal_state() noexcept = default;
void process_update(ecs::registry& owner) {
process_yogo_nodes(owner);
process_dirty_layouts(owner);
}
};
//
// layout_system
//
layout_system::layout_system()
: state_(new internal_state()) {}
layout_system::~layout_system() noexcept = default;
void layout_system::process(
ecs::registry& owner,
const ecs::after<systems::update_event>& trigger)
{
E2D_UNUSED(trigger);
E2D_PROFILER_SCOPE("layout_system.process_update");
state_->process_update(owner);
}
}

View File

@@ -109,17 +109,20 @@ namespace
}
}
void show_tree_for_all_scenes(editor& e, input& i, world& w) {
w.registry().for_joined_components<scene, actor>(
[&e, &i, &w](const ecs::const_entity&, const scene&, actor& a){
show_tree_for_node(e, i, w, a.node());
void show_tree_for_all_free_nodes(editor& e, input& i, world& w) {
ecsex::for_extracted_components<actor>(w.registry(), [&e, &i, &w](
const ecs::const_entity&,
actor& a)
{
if ( a.node() && !a.node()->has_parent() ) {
show_tree_for_node(e, i, w, a.node());
}
});
ImGui::Separator();
if ( ImGui::Button("+ Add Scene") ) {
gobject inst = w.instantiate();
inst.component<scene>().ensure();
if ( ImGui::Button("+ Add Node") ) {
w.instantiate();
}
}
@@ -154,7 +157,7 @@ namespace e2d::dbgui_widgets
return false;
}
show_tree_for_all_scenes(
show_tree_for_all_free_nodes(
the<editor>(),
the<input>(),
the<world>());