diff --git a/libs/ui/include/psemek/ui/impl/box_layout_base.hpp b/libs/ui/include/psemek/ui/impl/box_layout_base.hpp index 9f0973cc..ef40d72e 100644 --- a/libs/ui/include/psemek/ui/impl/box_layout_base.hpp +++ b/libs/ui/include/psemek/ui/impl/box_layout_base.hpp @@ -37,7 +37,7 @@ namespace psemek::ui::impl box_layout_base(react::value margin); void reshape(geom::box const & new_shape) override; - react::value size_constraints() const override; + react::value size_constraints() const override; void set_children(std::vector> children) override; std::vector> release_children() override; @@ -47,8 +47,8 @@ namespace psemek::ui::impl private: react::value margin_; react::value>> size_policies_; - react::source>> children_size_constraints_; - react::value size_constraints_; + react::source>> children_size_constraints_; + react::value size_constraints_; }; extern template struct box_layout_base<0>; diff --git a/libs/ui/include/psemek/ui/impl/component.hpp b/libs/ui/include/psemek/ui/impl/component.hpp index 55868c49..f8045f3e 100644 --- a/libs/ui/include/psemek/ui/impl/component.hpp +++ b/libs/ui/include/psemek/ui/impl/component.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include @@ -15,15 +15,12 @@ namespace psemek::ui::impl { static constexpr float infinity = std::numeric_limits::infinity(); - static size_polygon const & default_size_polygon(); - static react::value default_size_constraints(); - virtual util::span const> children() const; virtual geom::box const & shape() const; virtual void reshape(geom::box const & new_shape); - virtual react::value size_constraints() const; + virtual react::value size_constraints() const; virtual ~component() {} diff --git a/libs/ui/include/psemek/ui/impl/single_container.hpp b/libs/ui/include/psemek/ui/impl/single_container.hpp index 7e0c6b67..b049391a 100644 --- a/libs/ui/include/psemek/ui/impl/single_container.hpp +++ b/libs/ui/include/psemek/ui/impl/single_container.hpp @@ -4,8 +4,6 @@ #include #include -#include - namespace psemek::ui::impl { diff --git a/libs/ui/include/psemek/ui/impl/single_container_base.hpp b/libs/ui/include/psemek/ui/impl/single_container_base.hpp index 8f8b2f44..20b397eb 100644 --- a/libs/ui/include/psemek/ui/impl/single_container_base.hpp +++ b/libs/ui/include/psemek/ui/impl/single_container_base.hpp @@ -13,15 +13,15 @@ namespace psemek::ui::impl single_container_base(react::value> margin); void reshape(geom::box const & new_shape) override; - react::value size_constraints() const override; + react::value size_constraints() const override; void set_child(std::unique_ptr child) override; std::unique_ptr release_child() override; private: react::value> margin_; - react::source> child_size_constraints_; - react::value size_constraints_; + react::source> child_size_constraints_; + react::value size_constraints_; }; } diff --git a/libs/ui/include/psemek/ui/impl/size_constraints.hpp b/libs/ui/include/psemek/ui/impl/size_constraints.hpp new file mode 100644 index 00000000..c6d3d21d --- /dev/null +++ b/libs/ui/include/psemek/ui/impl/size_constraints.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace psemek::ui::impl +{ + + struct size_constraints + { + geom::box box; + + static size_constraints max(); + }; + + size_constraints shift(size_constraints const & constraints, geom::vector const & delta); + size_constraints scale(size_constraints const & constraints, float factor, int dimension); + + float min(size_constraints const & constraints, int dimension); + + size_constraints intersect(size_constraints const & constraints1, size_constraints const & constraints2); + + geom::interval range(size_constraints const & constraints, int dimension); + + size_constraints cut(size_constraints const & constraints, int dimension, geom::interval const & range); + + size_constraints sum_along(size_constraints const & constraints1, size_constraints const & constraints2, int dimension); + +} diff --git a/libs/ui/include/psemek/ui/impl/size_polygon.hpp b/libs/ui/include/psemek/ui/impl/size_polygon.hpp deleted file mode 100644 index bbd48976..00000000 --- a/libs/ui/include/psemek/ui/impl/size_polygon.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#include - -namespace psemek::ui::impl -{ - - constexpr float max_size = 16384.f; - - // Convex, in CCW order - using size_polygon = std::vector>; - -} diff --git a/libs/ui/include/psemek/ui/impl/size_polygon_utils.hpp b/libs/ui/include/psemek/ui/impl/size_polygon_utils.hpp deleted file mode 100644 index e9cdb60f..00000000 --- a/libs/ui/include/psemek/ui/impl/size_polygon_utils.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -namespace psemek::ui::impl -{ - - size_polygon shift(size_polygon polygon, geom::vector const & delta); - - size_polygon min(size_polygon const & polygon, int dimension); - - size_polygon intersect(size_polygon const & polygon1, size_polygon const & polygon2); - - geom::interval range(size_polygon const & polygon, int dimension); - size_polygon cut(size_polygon const & polygon, int dimension, geom::interval const & range); - size_polygon sum_along(size_polygon const & polygon1, size_polygon const & polygon2, int dimension); - -} diff --git a/libs/ui/include/psemek/ui/impl/stack_layout_base.hpp b/libs/ui/include/psemek/ui/impl/stack_layout_base.hpp index e5e0ca43..fc994816 100644 --- a/libs/ui/include/psemek/ui/impl/stack_layout_base.hpp +++ b/libs/ui/include/psemek/ui/impl/stack_layout_base.hpp @@ -14,7 +14,7 @@ namespace psemek::ui::impl stack_layout_base(); void reshape(geom::box const & new_shape) override; - react::value size_constraints() const override; + react::value size_constraints() const override; void set_children(std::vector> children) override; std::vector> release_children() override; @@ -23,8 +23,8 @@ namespace psemek::ui::impl {} private: - react::source>> children_size_constraints_; - react::value size_constraints_; + react::source>> children_size_constraints_; + react::value size_constraints_; }; } diff --git a/libs/ui/source/impl/box_layout_base.cpp b/libs/ui/source/impl/box_layout_base.cpp index 23adaa36..f3208200 100644 --- a/libs/ui/source/impl/box_layout_base.cpp +++ b/libs/ui/source/impl/box_layout_base.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -12,25 +11,22 @@ namespace psemek::ui::impl static constexpr box_layout::size_policy default_policy = box_layout::weight{}; template - size_polygon compute_size_constraints(std::vector const & size_policies, - std::vector const & children_size_constraints, float margin) + size_constraints compute_size_constraints(std::vector const & size_policies, + std::vector const & children_size_constraints, float margin) { - size_polygon minimized{{0.f, 0.f}, {0.f, max_size}}; - size_polygon weight_unit = minimized; + size_constraints minimized = size_constraints::max(); + size_constraints weight_unit = minimized; float weight_sum = 0.f; for (std::size_t i = 0; i < size_policies.size(); ++i) { if (std::get_if(&size_policies[i])) { - minimized = sum_along(minimized, *children_size_constraints[i], Dimension); + minimized = sum_along(minimized, children_size_constraints[i], Dimension); } else if (auto weight = std::get_if(&size_policies[i])) { - size_polygon child = *children_size_constraints[i]; - for (auto & p : child) - p[Dimension] /= weight->value; - weight_unit = sum_along(weight_unit, child, Dimension); + weight_unit = intersect(weight_unit, scale(children_size_constraints[i], 1.f / weight->value, Dimension)); weight_sum += weight->value; } } @@ -38,17 +34,15 @@ namespace psemek::ui::impl auto result = std::move(minimized); if (weight_sum > 0.f) + result = sum_along(result, scale(weight_unit, weight_sum, Dimension), Dimension); + + if (size_policies.size() > 0) { - for (auto & p : weight_unit) - p[Dimension] *= weight_sum; - result = sum_along(result, weight_unit, Dimension); + geom::vector shift_delta{0.f, 0.f}; + shift_delta[Dimension] = margin * (size_policies.size() - 1); + result = shift(std::move(result), shift_delta); } - geom::vector shift_delta{0.f, 0.f}; - shift_delta[Dimension] = margin; - - result = shift(std::move(result), shift_delta); - return result; } @@ -68,7 +62,7 @@ namespace psemek::ui::impl if (std::get_if(&policy)) { - result[i] = min(*children[i]->size_constraints(), Dimension).front()[Dimension]; + result[i] = min(*children[i]->size_constraints(), Dimension); total_size -= result[i]; } else if (auto weight = std::get_if(&policy)) @@ -98,12 +92,16 @@ namespace psemek::ui::impl : margin_(margin) , size_policies_({}) , children_size_constraints_() - , size_constraints_(react::map([](auto const & size_policies, auto const & children_size_constraints, auto const & margin){ - return compute_size_constraints(size_policies, children_size_constraints, margin); - }, - react::join(react::map(react::unpack_with_default(default_policy), size_policies_)), - react::join(react::map(react::unpack_with_transform([](react::value const & arg){ return &(*arg); }), children_size_constraints_)), - margin_)) + , size_constraints_( + react::map( + [](auto const & size_policies, auto const & children_size_constraints, auto const & margin){ + return compute_size_constraints(size_policies, children_size_constraints, margin); + }, + react::join(react::map(react::unpack_with_default(default_policy), size_policies_)), + react::join(react::map(react::unpack, children_size_constraints_)), + margin_ + ) + ) {} template @@ -134,7 +132,7 @@ namespace psemek::ui::impl } template - react::value box_layout_base::size_constraints() const + react::value box_layout_base::size_constraints() const { return size_constraints_; } @@ -144,13 +142,13 @@ namespace psemek::ui::impl { container::set_children(std::move(children)); - std::vector> children_size_constraints; + std::vector> children_size_constraints; for (auto const & child : this->children()) { if (child) children_size_constraints.push_back(child->size_constraints()); else - children_size_constraints.push_back(default_size_constraints()); + children_size_constraints.push_back(size_constraints::max()); } children_size_constraints_.set(std::move(children_size_constraints)); } diff --git a/libs/ui/source/impl/component.cpp b/libs/ui/source/impl/component.cpp index 42056643..4b468176 100644 --- a/libs/ui/source/impl/component.cpp +++ b/libs/ui/source/impl/component.cpp @@ -3,24 +3,6 @@ namespace psemek::ui::impl { - size_polygon const & component::default_size_polygon() - { - static size_polygon const result{{ - {max_size, 0.f}, - {0.f, 0.f}, - {0.f, max_size}, - {max_size, max_size} - }}; - - return result; - } - - react::value component::default_size_constraints() - { - static react::value const result{default_size_polygon()}; - return result; - } - util::span const> component::children() const { return {}; @@ -36,9 +18,10 @@ namespace psemek::ui::impl shape_ = new_shape; } - react::value component::size_constraints() const + react::value component::size_constraints() const { - return default_size_constraints(); + static react::value const result{size_constraints::max()}; + return result; } } diff --git a/libs/ui/source/impl/single_container_base.cpp b/libs/ui/source/impl/single_container_base.cpp index 7b37379b..2ce179f0 100644 --- a/libs/ui/source/impl/single_container_base.cpp +++ b/libs/ui/source/impl/single_container_base.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -8,8 +7,8 @@ namespace psemek::ui::impl single_container_base::single_container_base(react::value> margin) : margin_(margin) - , child_size_constraints_(default_size_constraints()) - , size_constraints_(react::map([](size_polygon const & child_constraints, geom::vector const & margin){ + , child_size_constraints_(size_constraints::max()) + , size_constraints_(react::map([](struct size_constraints const & child_constraints, geom::vector const & margin){ return shift(child_constraints, margin); }, react::join(child_size_constraints_), margin)) {} @@ -22,7 +21,7 @@ namespace psemek::ui::impl child()->reshape(geom::shrink(new_shape, *margin_)); } - react::value single_container_base::size_constraints() const + react::value single_container_base::size_constraints() const { return size_constraints_; } @@ -30,13 +29,13 @@ namespace psemek::ui::impl void single_container_base::set_child(std::unique_ptr child) { single_container::set_child(std::move(child)); - child_size_constraints_.set(this->child() ? this->child()->size_constraints() : default_size_constraints()); + child_size_constraints_.set(this->child() ? this->child()->size_constraints() : size_constraints::max()); } std::unique_ptr single_container_base::release_child() { auto child = single_container::release_child(); - child_size_constraints_.set(default_size_constraints()); + child_size_constraints_.set(size_constraints::max()); return child; } diff --git a/libs/ui/source/impl/size_constraints.cpp b/libs/ui/source/impl/size_constraints.cpp new file mode 100644 index 00000000..5ac0796f --- /dev/null +++ b/libs/ui/source/impl/size_constraints.cpp @@ -0,0 +1,63 @@ +#include + +#include + +namespace psemek::ui::impl +{ + + size_constraints size_constraints::max() + { + static constexpr float infinity = std::numeric_limits::infinity(); + + return + {{{ + {0.f, infinity}, + {0.f, infinity}, + }}}; + } + + size_constraints shift(size_constraints const & constraints, geom::vector const & delta) + { + return {constraints.box + delta}; + } + + size_constraints scale(size_constraints const & constraints, float factor, int dimension) + { + auto result = constraints; + result.box[dimension].min *= factor; + result.box[dimension].max *= factor; + return result; + } + + float min(size_constraints const & constraints, int dimension) + { + return constraints.box[dimension].min; + } + + size_constraints intersect(size_constraints const & constraints1, size_constraints const & constraints2) + { + return {constraints1.box & constraints2.box}; + } + + geom::interval range(size_constraints const & constraints, int dimension) + { + return constraints.box[dimension]; + } + + size_constraints cut(size_constraints const & constraints, int dimension, geom::interval const & range) + { + size_constraints result = constraints; + result.box[dimension] &= range; + return result; + } + + size_constraints sum_along(size_constraints const & constraints1, size_constraints const & constraints2, int dimension) + { + size_constraints result; + result.box[dimension].min = constraints1.box[dimension].min + constraints2.box[dimension].min; + result.box[dimension].max = constraints1.box[dimension].max + constraints2.box[dimension].max; + result.box[dimension ^ 1] = constraints1.box[dimension ^ 1] & constraints2.box[dimension ^ 1]; + return result; + } + +} diff --git a/libs/ui/source/impl/size_polygon_utils.cpp b/libs/ui/source/impl/size_polygon_utils.cpp deleted file mode 100644 index 37d80af0..00000000 --- a/libs/ui/source/impl/size_polygon_utils.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include -#include -#include -#include - -namespace psemek::ui::impl -{ - - size_polygon shift(size_polygon polygon, geom::vector const & delta) - { - for (auto & p : polygon) - p += delta; - return polygon; - } - - size_polygon min(size_polygon const & polygon, int dimension) - { - if (polygon.empty()) - return {}; - - size_polygon result; - - auto cit = util::make_cyclic_iterator(polygon); - std::size_t iterations = 0; - - for (auto next = std::next(cit); (*next)[dimension] <= (*cit)[dimension] && iterations < polygon.size(); cit = next++, ++iterations); - - if (iterations == polygon.size()) - return polygon; - - for (auto prev = std::prev(cit); (*prev)[dimension] <= (*cit)[dimension]; cit = prev--); - - for (auto cjt = cit; (*cjt)[dimension] == (*cit)[dimension]; ++cjt) - result.push_back(*cjt); - - return result; - } - - size_polygon intersect(size_polygon const & polygon1, size_polygon const & polygon2) - { - // TODO: https://www.cs.jhu.edu/~misha/Spring16/ORourke82.pdf - (void)polygon1; - (void)polygon2; - util::not_implemented(); - } - - geom::interval range(size_polygon const & polygon, int dimension) - { - geom::interval result; - for (auto const & p : polygon) - result |= p[dimension]; - return result; - } - - size_polygon cut(size_polygon const & polygon, int dimension, geom::interval const & range) - { - size_polygon result; - std::size_t iterations = 0; - for (auto it = util::make_cyclic_iterator(polygon), next_it = std::next(it); iterations != polygon.size(); (it = next_it++), ++iterations) - { - auto const & curr = *it; - auto const & next = *next_it; - - auto intersection = [&](float value) - { - // curr + (next - curr) * t = value - float t = (value - curr[dimension]) / (next[dimension] - curr[dimension]); - geom::point p; - p[dimension] = value; - p[dimension ^ 1] = geom::lerp(curr[dimension ^ 1], next[dimension ^ 1], t); - return p; - }; - - auto classify = [&](float value) - { - if (value < range.min) - return -2; - else if (value == range.min) - return -1; - else if (value < range.max) - return 0; - else if (value == range.max) - return 1; - else // (value > range.max) - return 2; - }; - - int const curr_class = classify(curr[dimension]); - int const next_class = classify(next[dimension]); - - if (curr_class >= -1 && curr_class <= 1) - result.push_back(curr); - - bool const min = (curr_class == -2 && next_class >= 0) || (curr_class >= 0 && next_class == -2); - bool const max = (curr_class == 2 && next_class <= 0) || (curr_class <= 0 && next_class == 2); - - - if (range.min == range.max) - { - if (min) result.push_back(intersection(range.min)); - } - else - { - if (min) result.push_back(intersection(range.min)); - if (max) result.push_back(intersection(range.max)); - - if (min && max && curr_class == 2) - std::swap(result.back(), result[result.size() - 2]); - } - } - - return result; - } - - size_polygon sum_along(size_polygon const & polygon1, size_polygon const & polygon2, int dimension) - { - if (polygon1.empty() || polygon2.empty()) - return size_polygon{}; - - int const other_dimension = dimension ^ 1; - - auto range1 = range(polygon1, other_dimension); - auto range2 = range(polygon2, other_dimension); - - auto common_range = range1 & range2; - if (common_range.empty()) - return size_polygon{}; - - auto cut1 = cut(polygon1, other_dimension, common_range); - auto cut2 = cut(polygon2, other_dimension, common_range); - - util::not_implemented(); - } - -} diff --git a/libs/ui/source/impl/stack_layout_base.cpp b/libs/ui/source/impl/stack_layout_base.cpp index 95a7f648..03c25ab5 100644 --- a/libs/ui/source/impl/stack_layout_base.cpp +++ b/libs/ui/source/impl/stack_layout_base.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -9,14 +8,11 @@ namespace psemek::ui::impl namespace { - size_polygon compute_size_constraints(std::vector const & children_size_constraints) + size_constraints compute_size_constraints(std::vector const & children_size_constraints) { - if (children_size_constraints.empty()) - return component::default_size_polygon(); - - auto result = *children_size_constraints.front(); - for (std::size_t i = 1; i < children_size_constraints.size(); ++i) - result = intersect(result, *children_size_constraints[i]); + size_constraints result = size_constraints::max(); + for (auto const & constraints : children_size_constraints) + result = intersect(result, constraints); return result; } @@ -25,7 +21,7 @@ namespace psemek::ui::impl stack_layout_base::stack_layout_base() : size_constraints_(react::map([](auto const & children_size_constraints){ return compute_size_constraints(children_size_constraints); - }, react::join(react::map(react::unpack_with_transform([](react::value const & arg){ return &(*arg); }), children_size_constraints_)))) + }, react::join(react::map(react::unpack, children_size_constraints_)))) {} void stack_layout_base::reshape(geom::box const & new_shape) @@ -35,7 +31,7 @@ namespace psemek::ui::impl child->reshape(new_shape); } - react::value stack_layout_base::size_constraints() const + react::value stack_layout_base::size_constraints() const { return size_constraints_; } @@ -43,13 +39,13 @@ namespace psemek::ui::impl void stack_layout_base::set_children(std::vector> children) { container::set_children(std::move(children)); - std::vector> children_size_constraints; + std::vector> children_size_constraints; for (auto const & child : this->children()) { if (child) children_size_constraints.push_back(child->size_constraints()); else - children_size_constraints.push_back(default_size_constraints()); + children_size_constraints.push_back(size_constraints::max()); } children_size_constraints_.set(std::move(children_size_constraints)); }