1 #ifndef TERMOX_WIDGET_LAYOUTS_DETAIL_LAYOUT_SPAN_HPP
2 #define TERMOX_WIDGET_LAYOUTS_DETAIL_LAYOUT_SPAN_HPP
10 #include <termox/widget/size_policy.hpp>
11 #include <termox/widget/widget.hpp>
13 namespace ox::layout::detail {
24 template <
typename Get_policy_t>
27 using Container_t = std::vector<Dimension>;
30 template <
typename Get_limit_t>
33 using Underlying_t = Container_t::iterator;
36 using iterator_category = std::forward_iterator_tag;
37 using value_type = Underlying_t::value_type;
38 using difference_type = Underlying_t::difference_type;
39 using pointer = Underlying_t::pointer;
40 using reference = Underlying_t::reference;
44 Iterator(Underlying_t iter,
46 Get_policy_t get_policy,
47 Get_limit_t get_limit)
50 get_policy_{get_policy},
53 while (iter_ != end && iter_->widget ==
nullptr)
58 Iterator(Iterator
const&) =
delete;
59 Iterator(Iterator&&) =
delete;
60 auto operator=(Iterator
const&) -> Iterator& =
delete;
61 auto operator=(Iterator&&) -> Iterator& =
delete;
62 ~Iterator() =
default;
65 auto operator++() -> Iterator&
67 if (iter_->length == get_limit_(get_policy_(*iter_->widget)))
68 iter_->widget =
nullptr;
71 }
while (iter_ != end_ && iter_->widget ==
nullptr);
75 [[nodiscard]]
auto operator*()
const -> reference {
return *iter_; }
77 [[nodiscard]]
auto operator->()
const -> pointer
79 return iter_.operator->();
82 [[nodiscard]]
auto operator==(Container_t::iterator other)
const ->
bool
84 return this->iter_ == other;
87 [[nodiscard]]
auto operator!=(Container_t::iterator other)
const ->
bool
89 return this->iter_ != other;
92 [[nodiscard]]
auto get_policy()
const ->
Size_policy const&
94 return get_policy_(*iter_->widget);
100 Get_policy_t get_policy_;
101 Get_limit_t get_limit_;
107 template <
typename Get_limit_t>
108 Iterator(
typename Layout_span::Container_t::iterator iter,
109 typename Layout_span::Container_t::iterator end,
110 Get_policy_t get_policy,
111 Get_limit_t get_limit) -> Iterator<decltype(get_limit)>;
116 template <
typename Iter>
120 Get_policy_t&& get_policy)
125 get_policy_{std::forward<Get_policy_t>(get_policy)}
133 total_stretch_ = this->calculate_total_stretch();
141 total_inverse_stretch_ = this->calculate_total_inverse_stretch();
145 [[nodiscard]]
auto end() -> Container_t::iterator
147 return dimensions_.end();
150 [[nodiscard]]
auto total_stretch() const ->
double
152 return total_stretch_;
155 [[nodiscard]]
auto total_inverse_stretch() const ->
double
157 return total_inverse_stretch_;
160 [[nodiscard]]
auto entire_length() const ->
int
162 return std::accumulate(
163 dimensions_.begin(), dimensions_.end(), 0,
164 [](
int total, Dimension
const& d) { return total + d.length; });
167 [[nodiscard]]
auto size() const -> std::
size_t
169 return std::count_if(dimensions_.begin(), dimensions_.end(),
170 [](
auto const& d) { return d.widget != nullptr; });
173 [[nodiscard]]
auto get_results() const -> std::vector<
int>
175 auto result = std::vector<int>{};
176 result.reserve(dimensions_.size());
177 std::transform(dimensions_.begin(), dimensions_.end(),
178 std::back_inserter(result),
179 [](
auto const& d) { return d.length; });
184 Container_t dimensions_;
185 Get_policy_t get_policy_;
186 mutable double total_stretch_ = 0.;
187 mutable double total_inverse_stretch_ = 0.;
191 template <
typename Iter>
192 [[nodiscard]]
static auto generate_zero_init_dimensions(Iter first,
196 auto result = Container_t{};
197 result.reserve(std::distance(first, last));
198 std::transform(first, last, std::back_inserter(result),
199 [](
auto& child) -> Dimension {
200 return {&child, 0uL};
205 template <
typename Iter_t>
206 static void handle_edge(Iter_t first,
208 std::size_t leftover,
213 first->length = leftover;
217 while (first != last) {
223 static void invalidate_each(Container_t& dimensions)
225 for (
auto& d : dimensions)
234 static auto set_each_to_min(Container_t& dimensions,
236 Get_policy_t get_policy) ->
bool
240 auto const end = std::end(dimensions);
241 for (
auto iter = std::begin(dimensions); iter != end; ++iter) {
242 auto const& policy = get_policy(*(iter->widget));
243 auto const min = policy.min();
245 if (min_sum > length) {
246 auto const leftover = length - (min_sum - min);
247 handle_edge(iter, end, leftover, policy.can_ignore_min());
248 invalidate_each(dimensions);
257 static void set_each_to_hint(Container_t& dimensions,
258 Get_policy_t get_policy)
261 std::for_each(std::begin(dimensions), std::end(dimensions),
262 [get_policy](
auto& dimension) {
264 get_policy(*dimension.widget).hint();
268 template <
typename Iter>
269 [[nodiscard]]
static auto build_dimensions(Iter first,
271 std::size_t primary_length,
272 Get_policy_t get_policy)
275 auto dimensions = generate_zero_init_dimensions(first, last);
276 if (!set_each_to_min(dimensions, primary_length, get_policy))
277 set_each_to_hint(dimensions, get_policy);
283 template <
typename Get_limit_t>
284 [[nodiscard]]
auto begin(Get_limit_t get_limit)
286 auto const begin = dimensions_.begin();
287 auto const end = dimensions_.end();
288 auto temp = Iterator{begin, end, get_policy_, get_limit};
291 return Iterator{begin, end, get_policy_, get_limit};
294 [[nodiscard]]
auto calculate_total_stretch() const ->
double
297 auto const end = dimensions_.end();
298 for (
auto iter = dimensions_.begin(); iter != end; ++iter) {
299 if (iter->widget !=
nullptr)
300 sum += get_policy_(*iter->widget).stretch();
305 [[nodiscard]]
auto calculate_total_inverse_stretch() const ->
double
308 auto const end = dimensions_.end();
309 for (
auto iter = dimensions_.begin(); iter != end; ++iter) {
310 if (iter->widget !=
nullptr)
311 sum += (1. / get_policy_(*iter->widget).stretch());
316 [[nodiscard]]
auto find_valid_begin()
const
318 auto const end = dimensions_.end();
319 for (
auto iter = dimensions_.begin(); iter != end; ++iter) {
320 if (iter->widget !=
nullptr)
Defines how a Layout should resize a Widget in one length Dimension.
Definition: size_policy.hpp:11
void max(int value)
Set the maximum length/height that the owning Widget can be.
Definition: size_policy.cpp:32
void min(int value)
Set the minimum length that the owning Widget should be.
Definition: size_policy.cpp:24
Container view to iterate over a Widget's children, yielding layout info.
Definition: layout_span.hpp:25
Layout_span(Iter first, Iter last, int primary_length, Get_policy_t &&get_policy)
Construct, only considers children from first up to last.
Definition: layout_span.hpp:117
auto begin_min()
Return iterator to the first element, will skip when length == min.
Definition: layout_span.hpp:139
auto begin_max()
Return iterator to the first element, will skip when length == max.
Definition: layout_span.hpp:131
Definition: layout_span.hpp:15