HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
alignment.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2019, 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
9#pragma once
10
11#include "../assert.hpp"
12#include "../cast.hpp"
13#include "../concepts.hpp"
14#include "../math.hpp"
15#include <optional>
16
17namespace hi::inline v1 {
18
22enum class vertical_alignment : uint8_t {
25 none = 0,
26
29 top = 1,
30
33 middle = 2,
34
37 bottom = 3
38};
39
59template<arithmetic T>
60[[nodiscard]] constexpr std::optional<T>
61make_guideline(vertical_alignment alignment, T bottom, T top, T padding_bottom, T padding_top, T guideline_width)
62{
64 hi_axiom(guideline_width >= T{});
65
66 hilet guideline_bottom = bottom + padding_bottom;
67 hilet guideline_top = top - padding_top - guideline_width;
68 hilet guideline_middle = (bottom + top - guideline_width) / T{2};
69
70 switch (alignment) {
71 case vertical_alignment::none:
72 return {};
73 case vertical_alignment::top:
74 if (guideline_bottom <= top) {
75 return guideline_top;
76 } else {
77 return {};
78 }
79 case vertical_alignment::bottom:
80 if (guideline_top >= bottom) {
81 return guideline_top;
82 } else {
83 return {};
84 }
85 case vertical_alignment::middle:
86 if (guideline_bottom <= guideline_top) {
87 return std::clamp(guideline_middle, guideline_bottom, guideline_top);
88 } else {
89 return {};
90 }
91 }
93}
94
98enum class horizontal_alignment : uint8_t {
101 none = 0,
102
108 flush = 1,
109
114 left = 2,
115
120 center = 3,
121
126 justified = 4,
127
132 right = 5,
133};
134
155template<arithmetic T>
156[[nodiscard]] constexpr std::optional<T>
157make_guideline(horizontal_alignment alignment, T left, T right, T padding_left, T padding_right, T guideline_width = T{0})
158{
159 hi_axiom(left <= right);
160 hi_axiom(guideline_width >= T{0});
161
162 hilet guideline_left = left + padding_left;
163 hilet guideline_right = right - padding_right - guideline_width;
164 hilet guideline_center = (left + right - guideline_width) / T{2};
165
166 switch (alignment) {
167 case horizontal_alignment::none:
168 return {};
169 case horizontal_alignment::left:
170 if (guideline_left <= right) {
171 return guideline_left;
172 } else {
173 return {};
174 }
175 case horizontal_alignment::right:
176 if (guideline_right >= left) {
177 return guideline_right;
178 } else {
179 return {};
180 }
181 case horizontal_alignment::center:
182 if (guideline_left <= guideline_right) {
183 return std::clamp(guideline_center, guideline_left, guideline_right);
184 } else {
185 return {};
186 }
187 }
189}
190
193[[nodiscard]] constexpr horizontal_alignment mirror(horizontal_alignment const& rhs) noexcept
194{
195 if (rhs == horizontal_alignment::left) {
196 return horizontal_alignment::right;
197 } else if (rhs == horizontal_alignment::right) {
198 return horizontal_alignment::left;
199 } else {
200 return rhs;
201 }
202}
203
206[[nodiscard]] constexpr horizontal_alignment mirror(horizontal_alignment const& rhs, bool left_to_right) noexcept
207{
208 if (left_to_right) {
209 return rhs;
210 } else {
211 return mirror(rhs);
212 }
213}
214
215[[nodiscard]] constexpr horizontal_alignment resolve(horizontal_alignment const& rhs, bool left_to_right) noexcept
216{
217 if (rhs == horizontal_alignment::flush or rhs == horizontal_alignment::justified) {
218 return left_to_right ? horizontal_alignment::left : horizontal_alignment::right;
219 } else {
220 return rhs;
221 }
222}
223
224[[nodiscard]] constexpr horizontal_alignment resolve_mirror(horizontal_alignment const& rhs, bool left_to_right) noexcept
225{
226 return resolve(mirror(rhs, left_to_right), left_to_right);
227}
228
233public:
234 constexpr alignment() noexcept : _value(0) {}
235 constexpr alignment(alignment const&) noexcept = default;
236 constexpr alignment(alignment&&) noexcept = default;
237 constexpr alignment& operator=(alignment const&) noexcept = default;
238 constexpr alignment& operator=(alignment&&) noexcept = default;
239
240 constexpr explicit alignment(uint8_t value) noexcept : _value(value) {}
241
242 constexpr alignment(horizontal_alignment t, vertical_alignment v = vertical_alignment::none) noexcept :
243 _value((to_underlying(v) << 4) | to_underlying(t))
244 {
245 hi_axiom(to_underlying(v) <= 0xf);
246 hi_axiom(to_underlying(t) <= 0xf);
247 }
248
249 constexpr alignment(vertical_alignment v, horizontal_alignment h = horizontal_alignment::none) noexcept :
250 _value((to_underlying(v) << 4) | to_underlying(h))
251 {
252 hi_axiom(to_underlying(v) <= 0xf);
253 hi_axiom(to_underlying(h) <= 0xf);
254 }
255
256 [[nodiscard]] static constexpr alignment top_flush() noexcept
257 {
258 return {horizontal_alignment::flush, vertical_alignment::top};
259 }
260
261 [[nodiscard]] static constexpr alignment top_left() noexcept
262 {
263 return {horizontal_alignment::left, vertical_alignment::top};
264 }
265
266 [[nodiscard]] static constexpr alignment top_center() noexcept
267 {
268 return {horizontal_alignment::center, vertical_alignment::top};
269 }
270
271 [[nodiscard]] static constexpr alignment top_justified() noexcept
272 {
273 return {horizontal_alignment::justified, vertical_alignment::top};
274 }
275
276 [[nodiscard]] static constexpr alignment top_right() noexcept
277 {
278 return {horizontal_alignment::right, vertical_alignment::top};
279 }
280
281 [[nodiscard]] static constexpr alignment middle_flush() noexcept
282 {
283 return {horizontal_alignment::flush, vertical_alignment::middle};
284 }
285
286 [[nodiscard]] static constexpr alignment middle_left() noexcept
287 {
288 return {horizontal_alignment::left, vertical_alignment::middle};
289 }
290
291 [[nodiscard]] static constexpr alignment middle_center() noexcept
292 {
293 return {horizontal_alignment::center, vertical_alignment::middle};
294 }
295
296 [[nodiscard]] static constexpr alignment middle_justified() noexcept
297 {
298 return {horizontal_alignment::justified, vertical_alignment::middle};
299 }
300
301 [[nodiscard]] static constexpr alignment middle_right() noexcept
302 {
303 return {horizontal_alignment::right, vertical_alignment::middle};
304 }
305
306 [[nodiscard]] static constexpr alignment bottom_left() noexcept
307 {
308 return {horizontal_alignment::left, vertical_alignment::bottom};
309 }
310
311 [[nodiscard]] static constexpr alignment bottom_center() noexcept
312 {
313 return {horizontal_alignment::center, vertical_alignment::bottom};
314 }
315
316 [[nodiscard]] static constexpr alignment bottom_right() noexcept
317 {
318 return {horizontal_alignment::right, vertical_alignment::bottom};
319 }
320
321 [[nodiscard]] constexpr horizontal_alignment horizontal() const noexcept
322 {
323 return static_cast<horizontal_alignment>(_value & 0xf);
324 }
325
326 [[nodiscard]] constexpr vertical_alignment vertical() const noexcept
327 {
328 return static_cast<vertical_alignment>(_value >> 4);
329 }
330
331 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, alignment const& rhs) noexcept = default;
332
333 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, horizontal_alignment const& rhs) noexcept
334 {
335 return lhs.horizontal() == rhs;
336 }
337
338 [[nodiscard]] constexpr friend bool operator==(horizontal_alignment const& lhs, alignment const& rhs) noexcept
339 {
340 return lhs == rhs.horizontal();
341 }
342
343 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, vertical_alignment const& rhs) noexcept
344 {
345 return lhs.vertical() == rhs;
346 }
347
348 [[nodiscard]] constexpr friend bool operator==(vertical_alignment const& lhs, alignment const& rhs) noexcept
349 {
350 return lhs == rhs.vertical();
351 }
352
353 [[nodiscard]] constexpr friend alignment mirror(alignment const& rhs) noexcept
354 {
355 return alignment{mirror(rhs.horizontal()), rhs.vertical()};
356 }
357
358 [[nodiscard]] constexpr friend alignment mirror(alignment const& rhs, bool left_to_right) noexcept
359 {
360 return alignment{mirror(rhs.horizontal(), left_to_right), rhs.vertical()};
361 }
362
363 [[nodiscard]] constexpr friend alignment resolve(alignment const& rhs, bool left_to_right) noexcept
364 {
365 return alignment{resolve(rhs.horizontal(), left_to_right), rhs.vertical()};
366 }
367
368 [[nodiscard]] constexpr friend alignment resolve_mirror(alignment const& rhs, bool left_to_right) noexcept
369 {
370 return alignment{resolve_mirror(rhs.horizontal(), left_to_right), rhs.vertical()};
371 }
372
373private:
379 uint8_t _value;
380};
381
388constexpr alignment operator|(horizontal_alignment lhs, vertical_alignment rhs) noexcept
389{
390 return alignment{lhs, rhs};
391}
392
399constexpr alignment operator|(vertical_alignment lhs, horizontal_alignment rhs) noexcept
400{
401 return alignment{lhs, rhs};
402}
403
404} // namespace hi::inline v1
Utilities to assert and bound check.
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:148
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:133
Miscellaneous math functions.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
vertical_alignment
Vertical alignment.
Definition alignment.hpp:22
horizontal_alignment
Horizontal alignment.
Definition alignment.hpp:98
constexpr std::optional< T > make_guideline(vertical_alignment alignment, T bottom, T top, T padding_bottom, T padding_top, T guideline_width)
Create a guideline between two points.
Definition alignment.hpp:61
@ middle
Align to the vertical-middle.
@ bottom
Align to the bottom.
@ top
Align to the top.
@ justified
Stretch the text to be flush to both sides.
@ center
Align the text in the center.
DOXYGEN BUG.
Definition algorithm.hpp:15
constexpr horizontal_alignment mirror(horizontal_alignment const &rhs) noexcept
Mirror the horizontal alignment.
Definition alignment.hpp:193
Horizontal/Vertical alignment combination.
Definition alignment.hpp:232
T left(T... args)