aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/render/MeasureRequirement.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/cru/ui/render/MeasureRequirement.hpp')
-rw-r--r--include/cru/ui/render/MeasureRequirement.hpp209
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