7#include "box_constraints.hpp"
8#include "box_shape.hpp"
10#include "../geometry/geometry.hpp"
11#include "../utility/utility.hpp"
12#include "../macros.hpp"
20hi_export_module(hikogui.layout.grid_layout);
22hi_export
namespace 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 = {};
43 template<std::convertible_to<value_type> Value>
51 first_column(first_column),
53 last_column(last_column),
55 beyond_maximum(beyond_maximum),
56 value(std::forward<Value>(value))
58 hi_assert(first_column < last_column);
59 hi_assert(first_row < last_row);
62 constexpr void set_constraints(
box_constraints const& constraints)
noexcept
64 _constraints = constraints;
67 template<hi::axis Axis>
68 [[
nodiscard]]
constexpr size_t first()
const noexcept
70 if constexpr (
Axis == axis::x) {
72 }
else if constexpr (
Axis == axis::y) {
75 hi_static_no_default();
79 template<hi::axis Axis>
80 [[
nodiscard]]
constexpr size_t last()
const noexcept
82 if constexpr (
Axis == axis::x) {
84 }
else if constexpr (
Axis == axis::y) {
87 hi_static_no_default();
91 template<hi::axis Axis>
92 [[
nodiscard]]
constexpr size_t span()
const noexcept
98 template<hi::axis Axis>
101 if constexpr (
Axis == axis::x) {
102 return _constraints.alignment.horizontal();
103 }
else if constexpr (
Axis == axis::y) {
104 return _constraints.alignment.vertical();
106 hi_static_no_default();
110 template<hi::axis Axis>
111 [[
nodiscard]]
constexpr float minimum()
const noexcept
113 if constexpr (
Axis == axis::x) {
114 return _constraints.minimum.
width();
115 }
else if constexpr (
Axis == axis::y) {
116 return _constraints.minimum.
height();
118 hi_static_no_default();
122 template<hi::axis Axis>
123 [[
nodiscard]]
constexpr float preferred()
const noexcept
125 if constexpr (
Axis == axis::x) {
126 return _constraints.preferred.
width();
127 }
else if constexpr (
Axis == axis::y) {
128 return _constraints.preferred.
height();
130 hi_static_no_default();
134 template<hi::axis Axis>
135 [[
nodiscard]]
constexpr float maximum()
const noexcept
137 if constexpr (
Axis == axis::x) {
138 return _constraints.maximum.
width();
139 }
else if constexpr (
Axis == axis::y) {
140 return _constraints.maximum.
height();
142 hi_static_no_default();
146 template<hi::axis Axis>
147 [[
nodiscard]]
constexpr float margin_before(
bool forward)
const noexcept
149 if constexpr (
Axis == axis::x) {
151 return _constraints.margins.left();
153 return _constraints.margins.right();
155 }
else if constexpr (
Axis == axis::y) {
157 return _constraints.margins.bottom();
159 return _constraints.margins.top();
162 hi_static_no_default();
166 template<hi::axis Axis>
167 [[
nodiscard]]
constexpr float margin_after(
bool forward)
const noexcept
169 if constexpr (
Axis == axis::x) {
171 return _constraints.margins.right();
173 return _constraints.margins.left();
175 }
else if constexpr (
Axis == axis::y) {
177 return _constraints.margins.top();
179 return _constraints.margins.bottom();
182 hi_static_no_default();
190template<hi::axis Axis,
typename T>
195 using value_type = T;
196 using alignment_type = std::conditional_t<axis == axis::y, vertical_alignment, horizontal_alignment>;
248 using iterator = constraint_vector::iterator;
249 using const_iterator = constraint_vector::const_iterator;
250 using reverse_iterator = constraint_vector::reverse_iterator;
251 using reference = constraint_vector::reference;
252 using const_reference = constraint_vector::const_reference;
271 _constraints(
num), _forward(forward)
274 construct_simple_cell(
cell);
279 construct_span_cell(
cell);
286 return empty() ? 0 : _forward ?
front().margin_before :
back().margin_before;
291 return empty() ? 0 : _forward ?
back().margin_after :
front().margin_after;
296 return empty() ? 0 : _forward ?
front().padding_before :
back().padding_before;
301 return empty() ? 0 : _forward ?
back().padding_after :
front().padding_after;
321 [[
nodiscard]]
constexpr float position(cell_type
const&
cell)
const noexcept
326 [[
nodiscard]]
constexpr float extent(cell_type
const&
cell)
const noexcept
331 [[
nodiscard]]
constexpr std::optional<float> guideline(cell_type
const&
cell)
const noexcept
387 return item.beyond_maximum;
427 return _constraints.
size();
434 return _constraints.
empty();
441 return _constraints.
begin();
448 return _constraints.
begin();
455 return _constraints.
cbegin();
462 return _constraints.
end();
469 return _constraints.
end();
476 return _constraints.
cend();
483 return _constraints.
rbegin();
490 return _constraints.
rend();
501 hi_axiom(index <
size());
502 return _constraints[index];
513 hi_axiom(index <
size());
514 return _constraints[index];
525 return _constraints.
front();
536 return _constraints.
front();
547 return _constraints.
back();
558 return _constraints.
back();
570 constraint_vector _constraints = {};
574 bool _forward =
true;
593 layout_shrink(const_iterator first, const_iterator last,
float shrink = 0.0f,
size_t count = 1)
noexcept
598 hi_axiom(shrink >= 0);
614 if (
it->extent >
it->minimum) {
639 layout_expand(const_iterator first, const_iterator last,
float expand = 0.0f,
size_t count = 1)
noexcept
644 hi_axiom(expand >= 0.0f);
661 if (
it->extent <
it->maximum) {
672 for (
auto it = first;
it != last; ++
it) {
673 it->position = position;
676 position +=
it->extent;
677 position +=
it->margin_after;
688 constexpr void construct_simple_cell(cell_type
const&
cell)
noexcept
694 _constraints[i].beyond_maximum |=
cell.beyond_maximum;
711 constexpr void construct_span_cell(cell_type
const&
cell)
noexcept
745 constexpr void construct_fixup()
noexcept
749 if (
it + 1 !=
end()) {
750 it->margin_after = (
it + 1)->margin_before =
std::max(
it->margin_after, (
it + 1)->margin_before);
754 inplace_max(
it->preferred,
it->minimum);
755 inplace_max(
it->maximum,
it->preferred);
778 for (
auto it = first + 1;
it != last; ++
it) {
798 hi_axiom(first <= last);
799 hi_axiom(last <=
size());
810 [[
nodiscard]]
constexpr float position(const_iterator first, const_iterator last)
const noexcept
812 hi_axiom(first != last);
814 return first->position;
816 return (last - 1)->position;
827 [[
nodiscard]]
constexpr float position(
size_t first,
size_t last)
const noexcept
829 hi_axiom(first < last);
830 hi_axiom(last <=
size());
841 [[
nodiscard]]
constexpr float extent(const_iterator first, const_iterator last)
const noexcept
846 for (
auto it = first + 1;
it != last; ++
it) {
847 r +=
it->margin_before;
861 [[
nodiscard]]
constexpr float extent(
size_t first,
size_t last)
const noexcept
863 hi_axiom(first <= last);
864 hi_axiom(last <=
size());
868 [[
nodiscard]]
constexpr std::optional<float> guideline(const_iterator
it)
const noexcept
870 return it->guideline;
873 [[
nodiscard]]
constexpr std::optional<float> guideline(
size_t i)
const noexcept
875 return guideline(
cbegin() + i);
889 using value_type = T;
891 using cell_type = detail::grid_layout_cell<value_type>;
893 using iterator = cell_vector::iterator;
894 using const_iterator = cell_vector::const_iterator;
895 using reference = cell_vector::reference;
896 using const_reference = cell_vector::const_reference;
906 [[
nodiscard]]
constexpr bool empty()
const noexcept
908 return _cells.
empty();
911 [[
nodiscard]]
constexpr size_t size()
const noexcept
913 return _cells.
size();
916 [[
nodiscard]]
constexpr size_t num_columns()
const noexcept
921 [[
nodiscard]]
constexpr size_t num_rows()
const noexcept
926 [[
nodiscard]]
constexpr iterator begin()
noexcept
928 return _cells.
begin();
931 [[
nodiscard]]
constexpr iterator end()
noexcept
936 [[
nodiscard]]
constexpr const_iterator begin()
const noexcept
938 return _cells.
begin();
941 [[
nodiscard]]
constexpr const_iterator end()
const noexcept
946 [[
nodiscard]]
constexpr const_iterator cbegin()
const noexcept
951 [[
nodiscard]]
constexpr const_iterator cend()
const noexcept
953 return _cells.
cend();
956 [[
nodiscard]]
constexpr const_reference operator[](
size_t i)
const noexcept
961 [[
nodiscard]]
constexpr reference operator[](
size_t i)
noexcept
974 [[
nodiscard]]
constexpr bool cell_in_use(
size_t first_column,
size_t first_row,
size_t last_column,
size_t last_row)
noexcept
977 hi_axiom(first_column < last_column);
978 hi_axiom(first_row < last_row);
980 for (
auto const&
cell : _cells) {
981 if (first_column >=
cell.last_column) {
984 if (last_column <=
cell.first_column) {
987 if (first_row >=
cell.last_row) {
990 if (last_row <=
cell.first_row) {
1008 template<forward_of<value_type> Value>
1010 size_t first_column,
1015 bool beyond_maximum =
false)
noexcept
1018 hi_assert(first_column < last_column);
1019 hi_assert(first_row < last_row);
1020 hi_assert(
not cell_in_use(first_column, first_row, last_column, last_row));
1021 auto& r = _cells.
emplace_back(first_column, first_row, last_column, last_row, beyond_maximum, std::forward<Value>(value));
1022 update_after_insert_or_delete();
1034 template<forward_of<value_type> Value>
1043 update_after_insert_or_delete();
1049 _row_constraints = {_cells, num_rows(),
false};
1050 _column_constraints = {_cells, num_columns(), left_to_right};
1052 auto r = box_constraints{};
1053 std::tie(r.minimum.width(), r.preferred.width(), r.maximum.width()) = _column_constraints.update_constraints();
1054 r.margins.left() = _column_constraints.margin_before();
1055 r.margins.right() = _column_constraints.margin_after();
1057 std::tie(r.minimum.height(), r.preferred.height(), r.maximum.height()) = _row_constraints.update_constraints();
1058 r.margins.bottom() = _row_constraints.margin_after();
1059 r.margins.top() = _row_constraints.margin_before();
1062 if (num_rows() == 1
and num_columns() == 1) {
1064 }
else if (num_rows() == 1) {
1066 }
else if (num_columns() == 1) {
1084 _column_constraints.
layout(shape.x(), shape.width(), shape.centerline, 0);
1085 _row_constraints.
layout(shape.y(), shape.height(), shape.baseline, baseline_adjustment);
1088 for (
auto&
cell : _cells) {
1089 cell.shape.rectangle = {
1090 _column_constraints.position(
cell),
1091 _row_constraints.position(
cell),
1092 _column_constraints.extent(
cell),
1093 _row_constraints.extent(
cell)};
1094 cell.shape.centerline = _column_constraints.guideline(
cell);
1095 cell.shape.baseline = _row_constraints.guideline(
cell);
1100 cell_vector _cells = {};
1101 size_t _num_rows = 0;
1102 size_t _num_columns = 0;
1103 mutable detail::grid_layout_axis_constraints<axis::y, value_type> _row_constraints = {};
1104 mutable detail::grid_layout_axis_constraints<axis::x, value_type> _column_constraints = {};
1110 constexpr void sort_cells()
noexcept
1112 std::sort(_cells.begin(), _cells.end(), [](cell_type
const& lhs, cell_type
const& rhs) {
1113 if (lhs.first_row != rhs.first_row) {
1114 return lhs.first_row < rhs.first_row;
1116 return lhs.first_column < rhs.first_column;
1123 constexpr void update_after_insert_or_delete()
noexcept
1129 for (
auto const&
cell : _cells) {
1130 inplace_max(_num_rows,
cell.last_row);
1131 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 guideline_width)
Create a guideline between two points.
Definition alignment.hpp:61
axis
An enumeration of the 3 axis for 3D geometry.
Definition axis.hpp:24
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
The HikoGUI namespace.
Definition recursive_iterator.hpp:15
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378
Horizontal/Vertical alignment combination.
Definition alignment.hpp:244
constexpr float & width() noexcept
Access the x-as-width element from the extent.
Definition extent2.hpp:107
constexpr float & height() noexcept
Access the y-as-height element from the extent.
Definition extent2.hpp:118
2D constraints.
Definition box_constraints.hpp:25
Definition box_shape.hpp:18
Definition grid_layout.hpp:26
Definition grid_layout.hpp:191
constexpr reference operator[](size_t index) noexcept
Get element.
Definition grid_layout.hpp:499
constexpr size_t size() const noexcept
Number of cell on this axis.
Definition grid_layout.hpp:425
constexpr const_reference back() const noexcept
Get the last element.
Definition grid_layout.hpp:555
constexpr bool empty() const noexcept
Check if this axis is empty.
Definition grid_layout.hpp:432
constexpr reference front() noexcept
Get the first element.
Definition grid_layout.hpp:522
constexpr reverse_iterator rend() noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:488
constexpr reverse_iterator rbegin() noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:481
constexpr reference back() noexcept
Get the last element.
Definition grid_layout.hpp:544
constexpr const_iterator end() const noexcept
Iterator to beyond the last cell on this axis.
Definition grid_layout.hpp:467
constexpr const_reference operator[](size_t index) const noexcept
Get element.
Definition grid_layout.hpp:511
constexpr const_iterator cbegin() const noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:453
constexpr iterator end() noexcept
Iterator to beyond the last cell on this axis.
Definition grid_layout.hpp:460
constexpr const_iterator begin() const noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:446
constexpr const_iterator cend() const noexcept
Iterator to beyond the last cell on this axis.
Definition grid_layout.hpp:474
constexpr iterator begin() noexcept
Iterator to the first cell on this axis.
Definition grid_layout.hpp:439
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:362
constexpr const_reference front() const noexcept
Get the first element.
Definition grid_layout.hpp:533
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:316
Definition grid_layout.hpp:200
float margin_after
The right/bottom margin of the cells.
Definition grid_layout.hpp:219
float extent
Size of the cell.
Definition grid_layout.hpp:239
float minimum
The minimum width/height of the cells.
Definition grid_layout.hpp:203
bool beyond_maximum
Allow this cell to be resized beyond the maximum constraint.
Definition grid_layout.hpp:227
float maximum
The maximum width/height of the cells.
Definition grid_layout.hpp:211
float margin_before
The left/top margin of the cells.
Definition grid_layout.hpp:215
float preferred
The preferred width/height of the cells.
Definition grid_layout.hpp:207
std::optional< float > guideline
The before-position within this cell where to align to.
Definition grid_layout.hpp:245
float position
The position of the cell.
Definition grid_layout.hpp:233
Grid layout algorithm.
Definition grid_layout.hpp:887
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:974
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:1009
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:1035
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:1081
T emplace_back(T... args)