constrained.hpp
1 2 3 4 5 6 7 8 9 10 | #pragma once #include <planet/affine/extents2d.hpp> #include <limits> #include <optional> namespace planet::ui { |
Constrained scalar values
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | template<typename T> class constrained1d { T m_value{}, m_desired{}, m_min{}, m_max{std::numeric_limits<value_type>::max()}; auto constrain() { m_value = m_desired; if (m_value < m_min) { m_value = m_min; } else if (m_value > m_max) { m_value = m_max; } return m_value; } public: using value_type = T; |
Construction
34 35 36 37 38 39 | constexpr constrained1d() noexcept {} explicit constexpr constrained1d(value_type t, value_type min = {}) : m_value{t}, m_desired{t}, m_min{min} {} constexpr constrained1d( value_type t, value_type min, value_type max) noexcept : m_value{t}, m_desired{t}, m_min{min}, m_max{max} {} |
Access to held values
43 44 45 | value_type value() const noexcept { return m_value; } value_type min() const noexcept { return m_min; } value_type max() const noexcept { return m_max; } |
The normalised value to a scale of 0 to 1
47 48 49 50 51 52 53 | value_type normalised_value() const noexcept { if (m_max != m_min) { return (m_value - m_min) / (m_max - m_min); } else { return {}; } } |
The current value remapped to another constrained
55 56 57 | value_type remapped_to(constrained1d const &c) const noexcept { return c.m_min + (normalised_value() * (c.m_max - c.m_min)); } |
Change held values
61 62 63 64 65 66 67 68 69 70 71 72 | value_type desire(value_type const m) { m_desired = m; return constrain(); } value_type min(value_type const m) { m_min = m; return constrain(); } value_type max(value_type const m) { m_max = m; return constrain(); } |
Comparisons
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | bool is_at_least_as_constrained_as(constrained1d const &o) const { return m_min >= o.m_min and m_max <= o.m_max; } // TODO std::equality_comparable_with<value_type> // When android NDK gets the concepts header template<typename R> friend bool operator==(constrained1d const &l, constrained1d<R> const &r) { return l.m_value == r.value(); } friend bool operator==(constrained1d const &l, value_type const r) { return l.m_value == r; } }; |
Maximum constraints
94 95 96 97 98 99 | template<typename T> constrained1d<T> maximum_of(constrained1d<T> const &l, constrained1d<T> const &r) { return {std::max(l.value(), r.value()), std::max(l.min(), r.min()), std::max(l.max(), r.max())}; } |
Constrained area
103 104 105 106 107 | template<typename T> struct constrained2d { using value_type = T; using axis_constrained_type = constrained1d<value_type>; axis_constrained_type width, height; |
Construction
111 112 113 114 115 116 117 118 119 120 121 122 | constexpr constrained2d() noexcept {} constexpr constrained2d(value_type w, value_type h) noexcept : width{w}, height{h} {} constexpr constrained2d( axis_constrained_type const &w, axis_constrained_type const &h) : width{w}, height{h} {} constexpr constrained2d( affine::extents2d const ex, affine::extents2d const min, affine::extents2d const max) : width(ex.width, min.width, max.width), height{ex.height, min.height, max.height} {} |
Force a fixed size with no latitude for change
124 125 126 | explicit constexpr constrained2d(affine::extents2d const ex) noexcept : width{ex.width, ex.width, ex.width}, height{ex.height, ex.height, ex.height} {} |
Conversions
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | affine::extents2d extents() const noexcept { return {width.value(), height.value()}; } affine::point2d position() const noexcept { return {width.value(), height.value()}; } affine::extents2d min_extents() const noexcept { return {width.min(), height.min()}; } affine::extents2d max_extents() const noexcept { return {width.max(), height.max()}; } affine::point2d min_position() const noexcept { return {width.min(), height.min()}; } affine::point2d max_position() const noexcept { return {width.max(), height.max()}; } |
Change
152 153 154 155 156 157 158 159 160 161 | affine::point2d desire(affine::point2d const &p) noexcept { return {width.desire(p.x()), height.desire(p.y())}; } affine::extents2d desire(affine::extents2d const &e) noexcept { return {width.desire(e.width), height.desire(e.height)}; } void max(affine::extents2d const &e) noexcept { width.max(e.width); height.max(e.height); } |
Queries
165 166 167 168 169 170 171 172 173 174 175 176 | bool is_at_least_as_constrained_as(constrained2d const &o) const { return width.is_at_least_as_constrained_as(o.width) and height.is_at_least_as_constrained_as(o.height); } friend bool operator==(constrained2d const &l, constrained2d const &r) { return l.width == r.width and l.height == r.height; } }; } |