diff options
Diffstat (limited to 'include/cru/ui/render/MeasureRequirement.hpp')
-rw-r--r-- | include/cru/ui/render/MeasureRequirement.hpp | 209 |
1 files changed, 180 insertions, 29 deletions
diff --git a/include/cru/ui/render/MeasureRequirement.hpp b/include/cru/ui/render/MeasureRequirement.hpp index 661f40a9..5af5a057 100644 --- a/include/cru/ui/render/MeasureRequirement.hpp +++ b/include/cru/ui/render/MeasureRequirement.hpp @@ -1,23 +1,34 @@ #pragma once #include "Base.hpp" +#include <algorithm> #include <limits> namespace cru::ui::render { -class MeasureLength { +constexpr Size Min(const Size& left, const Size& right) { + return Size{std::min(left.width, right.width), + std::min(left.height, right.height)}; +} + +constexpr Size Max(const Size& left, const Size& right) { + return Size{std::max(left.width, right.width), + std::max(left.height, right.height)}; +} + +class MeasureLength final { public: struct tag_not_specify_t {}; constexpr static tag_not_specify_t tag_not_specify{}; - constexpr MeasureLength() : MeasureLength(0) {} + constexpr MeasureLength() : MeasureLength(tag_not_specify) {} constexpr MeasureLength(tag_not_specify_t) : length_(-1) {} constexpr MeasureLength(float length) : length_(length) { Expects(length >= 0); } MeasureLength(const MeasureLength& other) = default; - MeasureLength& operator=(const MeasureLength& other) = default; - MeasureLength& operator=(float length) { + constexpr MeasureLength& operator=(const MeasureLength& other) = default; + constexpr MeasureLength& operator=(float length) { Expects(length >= 0); length_ = length; return *this; @@ -25,17 +36,44 @@ class MeasureLength { ~MeasureLength() = default; - constexpr static MeasureLength NotSpecify() { + constexpr static MeasureLength NotSpecified() { return MeasureLength{tag_not_specify}; } - // What not specify means depends on situation. - // For max size, it means no limit. - constexpr bool IsNotSpecify() const { return length_ < 0; } + constexpr bool IsSpecified() const { return length_ >= 0.0f; } + + // What not specified means depends on situation. + constexpr bool IsNotSpecified() const { return length_ < 0.0f; } + + constexpr float GetLengthOr(float value) const { + return length_ < 0 ? value : length_; + } // If not specify max value of float is returned. - constexpr float GetLength() const { - return length_ < 0 ? std::numeric_limits<float>::max() : length_; + constexpr float GetLengthOrMax() const { + return GetLengthOr(std::numeric_limits<float>::max()); + } + + // If not specify 0 is returned. + constexpr float GetLengthOr0() const { return GetLengthOr(0.f); } + + // If not specify, return value is undefined. + constexpr float GetLengthOrUndefined() const { return length_; } + + // Not operator overload because this semantics is not very clear. + constexpr MeasureLength Plus(float length) const { + if (IsSpecified()) + return length_ + length; + else + return NotSpecified(); + } + + // Not operator overload because this semantics is not very clear. + constexpr MeasureLength Minus(float length) const { + if (IsSpecified()) + return std::max(length_ - length, 0.f); + else + return NotSpecified(); } constexpr bool operator==(MeasureLength other) const { @@ -46,38 +84,151 @@ class MeasureLength { return !operator==(other); } + constexpr static MeasureLength Min(MeasureLength left, MeasureLength right) { + if (left.IsNotSpecified()) { + if (right.IsNotSpecified()) + return NotSpecified(); + else + return right; + } else { + if (left.IsNotSpecified()) + return left; + else + return std::min(left.length_, right.length_); + } + } + + constexpr static MeasureLength Max(MeasureLength left, MeasureLength right) { + if (left.IsNotSpecified()) { + if (right.IsNotSpecified()) + return NotSpecified(); + else + return right; + } else { + if (left.IsNotSpecified()) + return left; + else + return std::max(left.length_, right.length_); + } + } + private: - // -1 for infinate + // -1 for not specify float length_; }; +struct MeasureSize { + MeasureLength width; + MeasureLength height; + + constexpr MeasureSize() = default; + constexpr MeasureSize(MeasureLength width, MeasureLength height) + : width(width), height(height) {} + constexpr MeasureSize(const Size& size) + : width(size.width), height(size.height) {} + constexpr MeasureSize(const MeasureSize& other) = default; + + MeasureSize& operator=(const MeasureSize& other) = default; + constexpr MeasureSize& operator=(const Size& other) { + width = other.width; + height = other.height; + return *this; + } + + constexpr Size GetSizeOrMax() const { + return Size{width.GetLengthOrMax(), height.GetLengthOrMax()}; + } + + constexpr Size GetSizeOr0() const { + return Size{width.GetLengthOr0(), height.GetLengthOr0()}; + } + + constexpr MeasureSize Plus(const Size& size) const { + return MeasureSize{width.Plus(size.width), height.Plus(size.height)}; + } + + constexpr MeasureSize Minus(const Size& size) const { + return MeasureSize{width.Minus(size.width), height.Minus(size.height)}; + } + + constexpr MeasureSize OverrideBy(const MeasureSize& size) const { + return MeasureSize{ + size.width.IsSpecified() ? size.width.GetLengthOrUndefined() + : this->width, + size.height.IsSpecified() ? size.height.GetLengthOrUndefined() + : this->height, + }; + } + + constexpr static MeasureSize NotSpecified() { + return MeasureSize{MeasureLength::NotSpecified(), + MeasureLength::NotSpecified()}; + } + + constexpr static MeasureSize Min(const MeasureSize& left, + const MeasureSize& right) { + return MeasureSize{MeasureLength::Min(left.width, right.width), + MeasureLength::Min(left.height, right.height)}; + } + + constexpr static MeasureSize Max(const MeasureSize& left, + const MeasureSize& right) { + return MeasureSize{MeasureLength::Max(left.width, right.width), + MeasureLength::Max(left.height, right.height)}; + } +}; + struct MeasureRequirement { - MeasureLength max_width; - MeasureLength max_height; + MeasureSize max; + MeasureSize min; constexpr MeasureRequirement() = default; - constexpr MeasureRequirement(MeasureLength max_width, - MeasureLength max_height) - : max_width(max_width), max_height(max_height) {} - - constexpr MeasureRequirement(const Size& max_size) - : max_width(max_size.width), max_height(max_size.height) {} + constexpr MeasureRequirement(const MeasureSize& max, const MeasureSize& min) + : max(max), min(min) {} constexpr bool Satisfy(const Size& size) const { - if (!max_width.IsNotSpecify() && max_width.GetLength() < size.width) - return false; - if (!max_height.IsNotSpecify() && max_height.GetLength() < size.height) - return false; - return true; + return max.width.GetLengthOrMax() >= size.width && + max.height.GetLengthOrMax() >= size.height && + min.width.GetLengthOr0() <= size.width && + min.height.GetLengthOr0() <= size.height; + } + + constexpr MeasureRequirement Normalize() const { + MeasureRequirement result = *this; + if (result.min.width.GetLengthOr0() > result.max.width.GetLengthOrMax()) + result.min.width = result.max.width; + + if (result.min.height.GetLengthOr0() > result.max.height.GetLengthOrMax()) + result.min.height = result.max.height; + return result; + } + + constexpr Size Coerce(const Size& size) const { + // This order guarentees result is the same as normalized. + return Min(Max(size, min.GetSizeOr0()), max.GetSizeOrMax()); } - constexpr Size GetMaxSize() const { - return Size{max_width.GetLength(), max_height.GetLength()}; + constexpr MeasureSize Coerce(const MeasureSize& size) const { + MeasureSize result = size; + if (result.width.IsSpecified()) + // This order guarentees result is the same as normalized. + result.width = std::min(std::max(min.width.GetLengthOr0(), + result.width.GetLengthOrUndefined()), + max.width.GetLengthOrMax()); + + if (result.height.IsSpecified()) + // This order guarentees result is the same as normalized. + result.height = std::min(std::max(min.height.GetLengthOr0(), + result.height.GetLengthOrUndefined()), + max.height.GetLengthOrMax()); + + return result; } - constexpr static MeasureRequirement Infinate() { - return MeasureRequirement{MeasureLength::NotSpecify(), - MeasureLength::NotSpecify()}; + constexpr static MeasureRequirement Merge(const MeasureRequirement& left, + const MeasureRequirement& right) { + return MeasureRequirement{MeasureSize::Min(left.max, right.max), + MeasureSize::Max(left.min, right.min)}; } }; } // namespace cru::ui::render |