7#include "box_constraints.hpp"
8#include "box_shape.hpp"
10#include "../geometry/module.hpp"
11#include "../utility/utility.hpp"
12#include "../macros.hpp"
22namespace hi {
inline namespace v1 {
29 size_t first_column = 0;
31 size_t last_column = 0;
33 bool beyond_maximum =
false;
34 value_type value = {};
49 std::convertible_to<value_type>
auto&& value)
noexcept :
50 first_column(first_column),
52 last_column(last_column),
54 beyond_maximum(beyond_maximum),
55 value(hi_forward(value))
57 hi_assert(first_column < last_column);
58 hi_assert(first_row < last_row);
61 constexpr void set_constraints(
box_constraints const& constraints)
noexcept
63 _constraints = constraints;
66 template<hi::axis Axis>
67 [[
nodiscard]]
constexpr size_t first()
const noexcept
69 if constexpr (
Axis == axis::x) {
71 }
else if constexpr (
Axis == axis::y) {
74 hi_static_no_default();
78 template<hi::axis Axis>
79 [[
nodiscard]]
constexpr size_t last()
const noexcept
81 if constexpr (
Axis == axis::x) {
83 }
else if constexpr (
Axis == axis::y) {
86 hi_static_no_default();
90 template<hi::axis Axis>
91 [[
nodiscard]]
constexpr size_t span()
const noexcept
97 template<hi::axis Axis>
100 if constexpr (
Axis == axis::x) {
101 return _constraints.alignment.horizontal();
102 }
else if constexpr (
Axis == axis::y) {
103 return _constraints.alignment.vertical();
105 hi_static_no_default();
109 template<hi::axis Axis>
110 [[
nodiscard]]
constexpr float minimum()
const noexcept
112 if constexpr (
Axis == axis::x) {
113 return _constraints.minimum.
width();
114 }
else if constexpr (
Axis == axis::y) {
115 return _constraints.minimum.
height();
117 hi_static_no_default();
121 template<hi::axis Axis>
122 [[
nodiscard]]
constexpr float preferred()
const noexcept
124 if constexpr (
Axis == axis::x) {
125 return _constraints.preferred.
width();
126 }
else if constexpr (
Axis == axis::y) {
127 return _constraints.preferred.
height();
129 hi_static_no_default();
133 template<hi::axis Axis>
134 [[
nodiscard]]
constexpr float maximum()
const noexcept
136 if constexpr (
Axis == axis::x) {
137 return _constraints.maximum.
width();
138 }
else if constexpr (
Axis == axis::y) {
139 return _constraints.maximum.
height();
141 hi_static_no_default();
145 template<hi::axis Axis>
146 [[
nodiscard]]
constexpr float margin_before(
bool forward)
const noexcept
148 if constexpr (
Axis == axis::x) {
150 return _constraints.margins.left();
152 return _constraints.margins.right();
154 }
else if constexpr (
Axis == axis::y) {
156 return _constraints.margins.bottom();
158 return _constraints.margins.top();
161 hi_static_no_default();
165 template<hi::axis Axis>
166 [[
nodiscard]]
constexpr float margin_after(
bool forward)
const noexcept
168 if constexpr (
Axis == axis::x) {
170 return _constraints.margins.right();
172 return _constraints.margins.left();
174 }
else if constexpr (
Axis == axis::y) {
176 return _constraints.margins.top();
178 return _constraints.margins.bottom();
181 hi_static_no_default();
185 template<hi::axis Axis>
186 [[
nodiscard]]
constexpr float padding_before(
bool forward)
const noexcept
188 if constexpr (
Axis == axis::x) {
190 return _constraints.padding.left();
192 return _constraints.padding.right();
194 }
else if constexpr (
Axis == axis::y) {
196 return _constraints.padding.bottom();
198 return _constraints.padding.top();
201 hi_static_no_default();
205 template<hi::axis Axis>
206 [[
nodiscard]]
constexpr float padding_after(
bool forward)
const noexcept
208 if constexpr (
Axis == axis::x) {
210 return _constraints.padding.right();
212 return _constraints.padding.left();
214 }
else if constexpr (
Axis == axis::y) {
216 return _constraints.padding.top();
218 return _constraints.padding.bottom();
221 hi_static_no_default();
229template<hi::axis Axis,
typename T>
234 using value_type = T;
235 using alignment_type = std::conditional_t<axis == axis::y, vertical_alignment, horizontal_alignment>;
295 using iterator = constraint_vector::iterator;
296 using const_iterator = constraint_vector::const_iterator;
297 using reverse_iterator = constraint_vector::reverse_iterator;
298 using reference = constraint_vector::reference;
299 using const_reference = constraint_vector::const_reference;
318 _constraints(
num), _forward(forward)
321 construct_simple_cell(
cell);
326 construct_span_cell(
cell);
333 return empty() ? 0 : _forward ?
front().margin_before :
back().margin_before;
338 return empty() ? 0 : _forward ?
back().margin_after :
front().margin_after;
343 return empty() ? 0 : _forward ?
front().padding_before :
back().padding_before;
348 return empty() ? 0 : _forward ?
back().padding_after :
front().padding_after;
368 [[
nodiscard]]
constexpr float position(cell_type
const&
cell)
const noexcept
373 [[
nodiscard]]
constexpr float extent(cell_type
const&
cell)
const noexcept
378 [[
nodiscard]]
constexpr std::optional<float> guideline(cell_type
const&
cell)
const noexcept
381 return guideline(
cell.first<
axis>());
434 return item.beyond_maximum;
474 return _constraints.
size();
481 return _constraints.
empty();
488 return _constraints.
begin();
495 return _constraints.
begin();
502 return _constraints.
cbegin();
509 return _constraints.
end();
516 return _constraints.
end();
523 return _constraints.
cend();
530 return _constraints.
rbegin();
537 return _constraints.
rend();
548 hi_axiom(index <
size());
549 return _constraints[index];
560 hi_axiom(index <
size());
561 return _constraints[index];
572 return _constraints.
front();
583 return _constraints.
front();
594 return _constraints.
back();
605 return _constraints.
back();
617 constraint_vector _constraints = {};
621 bool _forward =
true;
640 layout_shrink(const_iterator first, const_iterator last,
float shrink = 0.0f,
size_t count = 1)
noexcept
645 hi_axiom(shrink >= 0);
661 if (
it->extent >
it->minimum) {
686 layout_expand(const_iterator first, const_iterator last,
float expand = 0.0f,
size_t count = 1)
noexcept
691 hi_axiom(expand >= 0.0f);
708 if (
it->extent <
it->maximum) {
719 for (
auto it = first;
it != last; ++
it) {
720 it->position = position;
724 position +=
it->extent;
725 position +=
it->margin_after;
736 constexpr void construct_simple_cell(cell_type
const&
cell)
noexcept
738 inplace_max(_constraints[
cell.first<axis>()].margin_before,
cell.margin_before<axis>(_forward));
739 inplace_max(_constraints[
cell.last<axis>() - 1].margin_after,
cell.margin_after<axis>(_forward));
740 inplace_max(_constraints[
cell.first<axis>()].padding_before,
cell.padding_before<axis>(_forward));
741 inplace_max(_constraints[
cell.last<axis>() - 1].padding_after,
cell.padding_after<axis>(_forward));
743 for (
auto i =
cell.first<axis>(); i !=
cell.last<
axis>(); ++i) {
744 _constraints[i].beyond_maximum |=
cell.beyond_maximum;
747 if (
cell.span<axis>() == 1) {
748 inplace_max(_constraints[
cell.first<axis>()].alignment,
cell.alignment<axis>());
749 inplace_max(_constraints[
cell.first<axis>()].minimum,
cell.minimum<axis>());
750 inplace_max(_constraints[
cell.first<axis>()].preferred,
cell.preferred<axis>());
751 inplace_min(_constraints[
cell.first<axis>()].maximum,
cell.maximum<axis>());
761 constexpr void construct_span_cell(cell_type
const&
cell)
noexcept
765 if (
cell.span<axis>() > 1) {
769 for (
auto i =
cell.first<axis>(); i !=
cell.last<
axis>(); ++i) {
776 for (
auto i =
cell.first<axis>(); i !=
cell.last<
axis>(); ++i) {
783 for (
auto i =
cell.first<axis>(); i !=
cell.last<
axis>(); ++i) {
795 constexpr void construct_fixup()
noexcept
799 if (
it + 1 !=
end()) {
800 it->margin_after = (
it + 1)->margin_before =
std::max(
it->margin_after, (
it + 1)->margin_before);
804 inplace_max(
it->preferred,
it->minimum);
805 inplace_max(
it->maximum,
it->preferred);
808 if (
it->padding_before +
it->padding_after >
it->minimum) {
836 for (
auto it = first + 1;
it != last; ++
it) {
856 hi_axiom(first <= last);
857 hi_axiom(last <=
size());
868 [[
nodiscard]]
constexpr float position(const_iterator first, const_iterator last)
const noexcept
870 hi_axiom(first != last);
872 return first->position;
874 return (last - 1)->position;
885 [[
nodiscard]]
constexpr float position(
size_t first,
size_t last)
const noexcept
887 hi_axiom(first < last);
888 hi_axiom(last <=
size());
899 [[
nodiscard]]
constexpr float extent(const_iterator first, const_iterator last)
const noexcept
904 for (
auto it = first + 1;
it != last; ++
it) {
905 r +=
it->margin_before;
919 [[
nodiscard]]
constexpr float extent(
size_t first,
size_t last)
const noexcept
921 hi_axiom(first <= last);
922 hi_axiom(last <=
size());
926 [[
nodiscard]]
constexpr std::optional<float> guideline(const_iterator
it)
const noexcept
928 return it->guideline;
931 [[
nodiscard]]
constexpr std::optional<float> guideline(
size_t i)
const noexcept
933 return guideline(
cbegin() + i);
947 using value_type = T;
949 using cell_type = detail::grid_layout_cell<value_type>;
951 using iterator = cell_vector::iterator;
952 using const_iterator = cell_vector::const_iterator;
953 using reference = cell_vector::reference;
954 using const_reference = cell_vector::const_reference;
964 [[
nodiscard]]
constexpr bool empty()
const noexcept
966 return _cells.
empty();
969 [[
nodiscard]]
constexpr size_t size()
const noexcept
971 return _cells.
size();
974 [[
nodiscard]]
constexpr size_t num_columns()
const noexcept
979 [[
nodiscard]]
constexpr size_t num_rows()
const noexcept
984 [[
nodiscard]]
constexpr iterator begin()
noexcept
986 return _cells.
begin();
989 [[
nodiscard]]
constexpr iterator end()
noexcept
994 [[
nodiscard]]
constexpr const_iterator begin()
const noexcept
996 return _cells.
begin();
999 [[
nodiscard]]
constexpr const_iterator end()
const noexcept
1001 return _cells.
end();
1004 [[
nodiscard]]
constexpr const_iterator cbegin()
const noexcept
1009 [[
nodiscard]]
constexpr const_iterator cend()
const noexcept
1011 return _cells.
cend();
1014 [[
nodiscard]]
constexpr const_reference operator[](
size_t i)
const noexcept
1019 [[
nodiscard]]
constexpr reference operator[](
size_t i)
noexcept
1032 [[
nodiscard]]
constexpr bool cell_in_use(
size_t first_column,
size_t first_row,
size_t last_column,
size_t last_row)
noexcept
1035 hi_axiom(first_column < last_column);
1036 hi_axiom(first_row < last_row);
1038 for (hilet&
cell : _cells) {
1039 if (first_column >=
cell.last_column) {
1042 if (last_column <=
cell.first_column) {
1045 if (first_row >=
cell.last_row) {
1048 if (last_row <=
cell.first_row) {
1066 template<forward_of<value_type> Value>
1068 size_t first_column,
1073 bool beyond_maximum =
false)
noexcept
1076 hi_assert(first_column < last_column);
1077 hi_assert(first_row < last_row);
1078 hi_assert(
not cell_in_use(first_column, first_row, last_column, last_row));
1079 auto& r = _cells.
emplace_back(first_column, first_row, last_column, last_row, beyond_maximum, std::forward<Value>(value));
1080 update_after_insert_or_delete();
1092 template<forward_of<value_type> Value>
1095 return add_cell(column,
row, column + 1,
row + 1, std::forward<Value>(value), beyond_maximum);
1101 update_after_insert_or_delete();
1107 _row_constraints = {_cells, num_rows(),
false};
1108 _column_constraints = {_cells, num_columns(), left_to_right};
1110 auto r = box_constraints{};
1111 std::tie(r.minimum.width(), r.preferred.width(), r.maximum.width()) = _column_constraints.update_constraints();
1112 r.margins.left() = _column_constraints.margin_before();
1113 r.margins.right() = _column_constraints.margin_after();
1114 r.padding.left() = _column_constraints.padding_before();
1115 r.padding.right() = _column_constraints.padding_after();
1117 std::tie(r.minimum.height(), r.preferred.height(), r.maximum.height()) = _row_constraints.update_constraints();
1118 r.margins.bottom() = _row_constraints.margin_after();
1119 r.margins.top() = _row_constraints.margin_before();
1120 r.padding.bottom() = _row_constraints.padding_after();
1121 r.padding.top() = _row_constraints.padding_before();
1124 if (num_rows() == 1
and num_columns() == 1) {
1126 }
else if (num_rows() == 1) {
1128 }
else if (num_columns() == 1) {
1146 _column_constraints.
layout(shape.x(), shape.width(), shape.centerline, 0);
1147 _row_constraints.
layout(shape.y(), shape.height(), shape.baseline, baseline_adjustment);
1150 for (
auto&
cell : _cells) {
1151 cell.shape.rectangle = {
1152 _column_constraints.position(
cell),
1153 _row_constraints.position(
cell),
1154 _column_constraints.extent(
cell),
1155 _row_constraints.extent(
cell)};
1156 cell.shape.centerline = _column_constraints.guideline(
cell);
1157 cell.shape.baseline = _row_constraints.guideline(
cell);
1162 cell_vector _cells = {};
1163 size_t _num_rows = 0;
1164 size_t _num_columns = 0;
1165 mutable detail::grid_layout_axis_constraints<axis::y, value_type> _row_constraints = {};
1166 mutable detail::grid_layout_axis_constraints<axis::x, value_type> _column_constraints = {};
1172 constexpr void sort_cells()
noexcept
1174 std::sort(_cells.begin(), _cells.end(), [](cell_type
const& lhs, cell_type
const& rhs) {
1175 if (lhs.first_row != rhs.first_row) {
1176 return lhs.first_row < rhs.first_row;
1178 return lhs.first_column < rhs.first_column;
1185 constexpr void update_after_insert_or_delete()
noexcept
1191 for (hilet&
cell : _cells) {
1192 inplace_max(_num_rows,
cell.last_row);
1193 inplace_max(_num_columns,
cell.last_column);
Utilities for parsing spreadsheet addresses.
constexpr std::optional< float > make_guideline(vertical_alignment alignment, float bottom, float top, float padding_bottom, float padding_top, float guideline_width)
Create a guideline between two points.
Definition alignment.hpp:60
axis
An enumeration of the 3 axis for 3D geometry.
Definition axis.hpp:19
@ middle
Align to the vertical-middle.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Horizontal/Vertical alignment combination.
Definition alignment.hpp:242
constexpr float & width() noexcept
Access the x-as-width element from the extent.
Definition extent2.hpp:104
constexpr float & height() noexcept
Access the y-as-height element from the extent.
Definition extent2.hpp:115
2D constraints.
Definition box_constraints.hpp:25
Definition box_shape.hpp:18
Definition grid_layout.hpp:26
Definition grid_layout.hpp:230
constexpr reference operator[](size_t index) noexcept
Get element.
Definition grid_layout.hpp:546
constexpr size_t size() const noexcept
Number of cell on this axis.
Definition grid_layout.hpp:472
constexpr const_reference back() const noexcept
Get the last element.
Definition grid_layout.hpp:602
constexpr bool empty() const noexcept
Check if this axis is empty.
Definition grid_layout.hpp:479
constexpr reference front() noexcept
Get the first element.
Definition grid_layout.hpp:569
constexpr reverse_iterator rend() noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:535
constexpr reverse_iterator rbegin() noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:528
constexpr reference back() noexcept
Get the last element.
Definition grid_layout.hpp:591
constexpr const_iterator end() const noexcept
Iterator to beyond the last cell on this axis.
Definition grid_layout.hpp:514
constexpr const_reference operator[](size_t index) const noexcept
Get element.
Definition grid_layout.hpp:558
constexpr const_iterator cbegin() const noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:500
constexpr iterator end() noexcept
Iterator to beyond the last cell on this axis.
Definition grid_layout.hpp:507
constexpr const_iterator begin() const noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:493
constexpr const_iterator cend() const noexcept
Iterator to beyond the last cell on this axis.
Definition grid_layout.hpp:521
constexpr iterator begin() noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:486
constexpr void layout(float new_position, float new_extent, std::optional< float > external_guideline, float guideline_width) noexcept
Layout each cell along an axis.
Definition grid_layout.hpp:409
constexpr const_reference front() const noexcept
Get the first element.
Definition grid_layout.hpp:580
constexpr std::tuple< float, float, float > constraints(cell_type const &cell) const noexcept
Get the minimum, preferred, maximum size of the span.
Definition grid_layout.hpp:363
Definition grid_layout.hpp:239
float margin_after
The right/bottom margin of the cells.
Definition grid_layout.hpp:258
float extent
Size of the cell.
Definition grid_layout.hpp:286
float padding_before
The left/top padding of the cells.
Definition grid_layout.hpp:262
float padding_after
The right/bottom padding of the cells.
Definition grid_layout.hpp:266
float minimum
The minimum width/height of the cells.
Definition grid_layout.hpp:242
bool beyond_maximum
Allow this cell to be resized beyond the maximum constraint.
Definition grid_layout.hpp:274
float maximum
The maximum width/height of the cells.
Definition grid_layout.hpp:250
float margin_before
The left/top margin of the cells.
Definition grid_layout.hpp:254
float preferred
The preferred width/height of the cells.
Definition grid_layout.hpp:246
std::optional< float > guideline
The before-position within this cell where to align to.
Definition grid_layout.hpp:292
float position
The position of the cell.
Definition grid_layout.hpp:280
Grid layout algorithm.
Definition grid_layout.hpp:945
constexpr bool cell_in_use(size_t first_column, size_t first_row, size_t last_column, size_t last_row) noexcept
Check if the cell on the grid is already in use.
Definition grid_layout.hpp:1032
constexpr reference add_cell(size_t first_column, size_t first_row, size_t last_column, size_t last_row, Value &&value, bool beyond_maximum=false) noexcept
Check if the cell on the grid is already in use.
Definition grid_layout.hpp:1067
constexpr reference add_cell(size_t column, size_t row, Value &&value, bool beyond_maximum=false) noexcept
Check if the cell on the grid is already in use.
Definition grid_layout.hpp:1093
constexpr void set_layout(box_shape const &shape, float baseline_adjustment) noexcept
Layout the cells based on the width and height.
Definition grid_layout.hpp:1143
Definition concepts.hpp:42
T emplace_back(T... args)