23 class LinearLayout :
public Layout
26 spk::HorizontalAlignment _horizontalAlignment = spk::HorizontalAlignment::Centered;
27 spk::VerticalAlignment _verticalAlignment = spk::VerticalAlignment::Centered;
32 return (_computeMinimalSize());
35 return (_computeMinimalSize());
39 template <
typename THorizontal,
typename TVertical,
typename... TArgs>
40 auto _executeOrientationDefined(THorizontal &&p_horizontalFunction, TVertical &&p_verticalFunction, TArgs &&...p_args)
const
43 if constexpr (TOrientation == Orientation::Horizontal)
45 return std::forward<THorizontal>(p_horizontalFunction)(
46 std::forward<TArgs>(p_args)...);
50 return std::forward<TVertical>(p_verticalFunction)(
51 std::forward<TArgs>(p_args)...);
55 spk::Vector2UInt _baseElementSize(
const Element &p_element)
const
60 return (spk::Vector2UInt{
65 spk::Vector2UInt _computeMinimalSize()
const
69 for (
size_t i = 0; i <
_elements().size(); i++)
71 const spk::Vector2UInt &tmpSize = _baseElementSize(
_elements()[i]);
75 case Orientation::Vertical:
76 result.
x = std::max(result.
x, tmpSize.
x);
77 result.
y += tmpSize.
y;
79 case Orientation::Horizontal:
80 result.
y = std::max(result.
y, tmpSize.
y);
81 result.
x += tmpSize.
x;
89 static constexpr bool _isVertical()
91 return TOrientation == Orientation::Vertical;
94 std::int64_t _crossAxisOffset(
const std::int64_t &p_difference)
const
96 return _executeOrientationDefined(
97 [&]() -> std::int64_t {
98 switch (_verticalAlignment)
100 case spk::VerticalAlignment::Top:
102 case spk::VerticalAlignment::Down:
104 case spk::VerticalAlignment::Centered:
106 return p_difference / 2;
109 [&]() -> std::int64_t {
110 switch (_horizontalAlignment)
112 case spk::HorizontalAlignment::Left:
114 case spk::HorizontalAlignment::Right:
116 case spk::HorizontalAlignment::Centered:
118 return p_difference / 2;
123 static SizePolicy::Value _secondaryAxisPolicy(
const SizePolicy::Value &p_mainPolicy)
125 switch (p_mainPolicy)
127 case SizePolicy::Desired:
128 case SizePolicy::Minimum:
129 return (p_mainPolicy);
131 return (SizePolicy::Extend);
138 std::vector<Element> _pullElementOnPriority(
const SizePolicy::Value &p_value)
140 std::vector<Element> result;
144 if (_executeOrientationDefined(
145 [&](
const Element &p_e) ->
bool {
148 [&](
const Element &p_e) ->
bool {
153 result.push_back(element);
160 spk::Vector2UInt _getSpaceToAssign(
const spk::Extend2D &p_extend)
164 _executeOrientationDefined(
175 using MainAxisViewRegionSize = std::vector<size_t>;
176 using SecondaryAxisViewRegionSize = std::vector<size_t>;
178 size_t _computeSizeToAssign(
const spk::Extend2D &p_extend, MainAxisViewRegionSize &p_mainAxisViewRegionSize)
180 size_t result = _executeOrientationDefined(
182 return (p_extend.size.
x);
185 return (p_extend.size.
y);
188 if (p_mainAxisViewRegionSize.empty() ==
false)
190 result -= (p_mainAxisViewRegionSize.size() - 1) * _executeOrientationDefined(
199 for (
const auto &size : p_mainAxisViewRegionSize)
214 using ElementIndexVector = std::vector<size_t>;
216 ElementIndexVector _getElementWithSizePolicy(
const SizePolicy::Value &p_value)
218 ElementIndexVector result;
220 for (
size_t i = 0; i <
_elements().size(); i++)
222 if (_executeOrientationDefined(
238 size_t _updateViewRegionSize(
const size_t &p_spaceToAssign, MainAxisViewRegionSize &p_mainAxisViewRegionSize,
const SizePolicy::Value &p_value)
240 size_t sizeLeft = p_spaceToAssign;
241 ElementIndexVector targetElements = _getElementWithSizePolicy(p_value);
243 if (targetElements.empty())
248 for (
size_t i = 0; i < targetElements.size(); i++)
250 size_t index = targetElements[i];
251 size_t currentSize = p_mainAxisViewRegionSize[index];
254 size_t sizeToAdd = sizeLeft / targetElements.size();
256 for (
size_t i = 0; i < targetElements.size();)
258 size_t index = targetElements[i];
259 size_t currentSize = p_mainAxisViewRegionSize[index];
261 size_t elementMaxSize = _executeOrientationDefined(
262 [&](
const Element &p_e) ->
size_t {
265 [&](
const Element &p_e) ->
size_t {
270 if (elementMaxSize <= currentSize + sizeToAdd)
272 p_mainAxisViewRegionSize[targetElements[i]] = elementMaxSize;
273 targetElements.erase(targetElements.begin() + i);
275 if (sizeLeft < elementMaxSize)
279 sizeLeft -= (elementMaxSize - currentSize);
280 if (targetElements.empty())
284 sizeToAdd = sizeLeft / targetElements.size();
292 for (
size_t i = 0; i < targetElements.size(); i++)
294 size_t index = targetElements[i];
295 size_t currentSize = p_mainAxisViewRegionSize[index];
297 p_mainAxisViewRegionSize[targetElements[i]] = currentSize + sizeToAdd;
298 sizeLeft -= sizeToAdd;
309 ~LinearLayout()
override =
default;
315 template <Orientation TLocalOrientation = TOrientation,
typename std::enable_if_t<TLocalOrientation == Orientation::Horizontal,
int> = 0>
318 _verticalAlignment = p_alignment;
325 template <Orientation TLocalOrientation = TOrientation,
typename std::enable_if_t<TLocalOrientation == Orientation::Vertical,
int> = 0>
328 _horizontalAlignment = p_alignment;
335 template <Orientation TLocalOrientation = TOrientation,
typename std::enable_if_t<TLocalOrientation == Orientation::Horizontal,
int> = 0>
338 return (_verticalAlignment);
345 template <Orientation TLocalOrientation = TOrientation,
typename std::enable_if_t<TLocalOrientation == Orientation::Vertical,
int> = 0>
348 return (_horizontalAlignment);
357 MainAxisViewRegionSize mainAxisViewRegionSize;
358 SecondaryAxisViewRegionSize secondaryAxisViewRegionSize;
360 mainAxisViewRegionSize.resize(
_elements().size());
361 secondaryAxisViewRegionSize.resize(
_elements().size());
363 for (
size_t i = 0; i <
_elements().size(); i++)
365 spk::Vector2UInt elementMinSize = _baseElementSize(
_elements()[i]);
366 spk::Vector2UInt elementMaxSize =
_elements()[i].element->sizeHint().maximal();
368 _executeOrientationDefined(
370 mainAxisViewRegionSize[i] = elementMinSize.
x;
372 secondaryAxisViewRegionSize[i] = std::min(elementMaxSize.
y, (crossPolicy == SizePolicy::Desired || crossPolicy == SizePolicy::Minimum ? elementMinSize.
y : p_geometry.height));
375 mainAxisViewRegionSize[i] = elementMinSize.
y;
377 secondaryAxisViewRegionSize[i] = std::min(elementMaxSize.
x, (crossPolicy == SizePolicy::Desired || crossPolicy == SizePolicy::Minimum ? elementMinSize.
x : p_geometry.width));
381 size_t sizeToAssign = _computeSizeToAssign(p_geometry, mainAxisViewRegionSize);
383 sizeToAssign = _updateViewRegionSize(sizeToAssign, mainAxisViewRegionSize, SizePolicy::Extend);
384 sizeToAssign = _updateViewRegionSize(sizeToAssign, mainAxisViewRegionSize, SizePolicy::Standard);
386 const std::int64_t geometryMainAxisSize = _executeOrientationDefined(
387 [&]() -> std::int64_t {
388 return (
static_cast<std::int64_t
>(p_geometry.size.
x));
390 [&]() -> std::int64_t {
391 return (
static_cast<std::int64_t
>(p_geometry.size.
y));
394 const std::int64_t geometryCrossAxisSize = _executeOrientationDefined(
395 [&]() -> std::int64_t {
396 return (
static_cast<std::int64_t
>(p_geometry.size.
y));
398 [&]() -> std::int64_t {
399 return (
static_cast<std::int64_t
>(p_geometry.size.
x));
402 const std::int64_t clampedCenterOffset = std::clamp<std::int64_t>(
403 static_cast<std::int64_t
>(0),
404 static_cast<std::int64_t
>(std::numeric_limits<spk::Vector2Int::value_type>::min()),
405 static_cast<std::int64_t
>(std::numeric_limits<spk::Vector2Int::value_type>::max()));
407 spk::Vector2Int anchor = p_geometry.anchor;
408 _executeOrientationDefined(
415 for (
size_t i = 0; i <
_elements().size(); i++)
417 spk::Vector2UInt elementSize = _executeOrientationDefined(
419 return (spk::Vector2UInt(mainAxisViewRegionSize[i], secondaryAxisViewRegionSize[i]));
422 return (spk::Vector2UInt(secondaryAxisViewRegionSize[i], mainAxisViewRegionSize[i]));
425 spk::Vector2Int elementAnchor = anchor;
426 const std::int64_t crossAxisSize = _executeOrientationDefined(
427 [&]() -> std::int64_t {
428 return (
static_cast<std::int64_t
>(elementSize.
y));
430 [&]() -> std::int64_t {
431 return (
static_cast<std::int64_t
>(elementSize.
x));
434 const std::int64_t crossDifference = geometryCrossAxisSize - crossAxisSize;
435 const std::int64_t crossAxisOffset = _crossAxisOffset(crossDifference);
436 const std::int64_t clampedCrossOffset = std::clamp<std::int64_t>(
438 static_cast<std::int64_t
>(std::numeric_limits<spk::Vector2Int::value_type>::min()),
439 static_cast<std::int64_t
>(std::numeric_limits<spk::Vector2Int::value_type>::max()));
441 _executeOrientationDefined(
449 _elements()[i].element->setGeometry({elementAnchor, elementSize});
451 _executeOrientationDefined(
468 const SizePolicy::Value secondaryPolicy = _secondaryAxisPolicy(p_sizePolicy);
470 return (
SizePolicy{p_sizePolicy, secondaryPolicy});
473 return (
SizePolicy{secondaryPolicy, p_sizePolicy});
493 _executeOrientationDefined(