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 "../utility/module.hpp"
12#include <optional>
13
14namespace hi::inline v1 {
15
19enum class vertical_alignment : uint8_t {
22 none = 0,
23
26 top = 1,
27
30 middle = 2,
31
34 bottom = 3
35};
36
57template<arithmetic T>
58[[nodiscard]] constexpr std::optional<T>
59make_guideline(vertical_alignment alignment, T bottom, T top, T padding_bottom, T padding_top, T guideline_width)
60{
62 hi_axiom(guideline_width >= T{});
63
64 hilet guideline_bottom = bottom + padding_bottom;
65 hilet guideline_top = top - padding_top - guideline_width;
66 hilet guideline_middle = (bottom + top - guideline_width) / T{2};
67
68 switch (alignment) {
69 case vertical_alignment::none:
70 return {};
71 case vertical_alignment::top:
72 if (guideline_bottom <= top) {
73 return guideline_top;
74 } else {
75 return {};
76 }
77 case vertical_alignment::bottom:
78 if (guideline_top >= bottom) {
79 return guideline_top;
80 } else {
81 return {};
82 }
83 case vertical_alignment::middle:
84 if (guideline_bottom <= guideline_top) {
85 return std::clamp(guideline_middle, guideline_bottom, guideline_top);
86 } else {
87 return {};
88 }
89 }
91}
92
96enum class horizontal_alignment : uint8_t {
99 none = 0,
100
106 flush = 1,
107
112 left = 2,
113
118 center = 3,
119
124 justified = 4,
125
130 right = 5,
131};
132
154template<arithmetic T>
155[[nodiscard]] constexpr std::optional<T>
156make_guideline(horizontal_alignment alignment, T left, T right, T padding_left, T padding_right, T guideline_width = T{0})
157{
158 hi_axiom(left <= right);
159 hi_axiom(guideline_width >= T{0});
160
161 hilet guideline_left = left + padding_left;
162 hilet guideline_right = right - padding_right - guideline_width;
163 hilet guideline_center = (left + right - guideline_width) / T{2};
164
165 switch (alignment) {
166 case horizontal_alignment::none:
167 return {};
168 case horizontal_alignment::left:
169 if (guideline_left <= right) {
170 return guideline_left;
171 } else {
172 return {};
173 }
174 case horizontal_alignment::right:
175 if (guideline_right >= left) {
176 return guideline_right;
177 } else {
178 return {};
179 }
180 case horizontal_alignment::center:
181 if (guideline_left <= guideline_right) {
182 return std::clamp(guideline_center, guideline_left, guideline_right);
183 } else {
184 return {};
185 }
186 }
188}
189
192[[nodiscard]] constexpr horizontal_alignment mirror(horizontal_alignment const& rhs) noexcept
193{
194 if (rhs == horizontal_alignment::left) {
195 return horizontal_alignment::right;
196 } else if (rhs == horizontal_alignment::right) {
197 return horizontal_alignment::left;
198 } else {
199 return rhs;
200 }
201}
202
205[[nodiscard]] constexpr horizontal_alignment mirror(horizontal_alignment const& rhs, bool left_to_right) noexcept
206{
207 if (left_to_right) {
208 return rhs;
209 } else {
210 return mirror(rhs);
211 }
212}
213
214[[nodiscard]] constexpr horizontal_alignment resolve(horizontal_alignment const& rhs, bool left_to_right) noexcept
215{
216 if (rhs == horizontal_alignment::flush or rhs == horizontal_alignment::justified) {
217 return left_to_right ? horizontal_alignment::left : horizontal_alignment::right;
218 } else {
219 return rhs;
220 }
221}
222
223[[nodiscard]] constexpr horizontal_alignment resolve_mirror(horizontal_alignment const& rhs, bool left_to_right) noexcept
224{
225 return resolve(mirror(rhs, left_to_right), left_to_right);
226}
227
232public:
233 constexpr alignment() noexcept : _value(0) {}
234 constexpr alignment(alignment const&) noexcept = default;
235 constexpr alignment(alignment&&) noexcept = default;
236 constexpr alignment& operator=(alignment const&) noexcept = default;
237 constexpr alignment& operator=(alignment&&) noexcept = default;
238
239 constexpr explicit alignment(uint8_t value) noexcept : _value(value) {}
240
241 constexpr alignment(horizontal_alignment t, vertical_alignment v = vertical_alignment::none) noexcept :
242 _value((to_underlying(v) << 4) | to_underlying(t))
243 {
244 hi_axiom(to_underlying(v) <= 0xf);
245 hi_axiom(to_underlying(t) <= 0xf);
246 }
247
248 constexpr alignment(vertical_alignment v, horizontal_alignment h = horizontal_alignment::none) noexcept :
249 _value((to_underlying(v) << 4) | to_underlying(h))
250 {
251 hi_axiom(to_underlying(v) <= 0xf);
252 hi_axiom(to_underlying(h) <= 0xf);
253 }
254
255 [[nodiscard]] static constexpr alignment top_flush() noexcept
256 {
257 return {horizontal_alignment::flush, vertical_alignment::top};
258 }
259
260 [[nodiscard]] static constexpr alignment top_left() noexcept
261 {
262 return {horizontal_alignment::left, vertical_alignment::top};
263 }
264
265 [[nodiscard]] static constexpr alignment top_center() noexcept
266 {
267 return {horizontal_alignment::center, vertical_alignment::top};
268 }
269
270 [[nodiscard]] static constexpr alignment top_justified() noexcept
271 {
272 return {horizontal_alignment::justified, vertical_alignment::top};
273 }
274
275 [[nodiscard]] static constexpr alignment top_right() noexcept
276 {
277 return {horizontal_alignment::right, vertical_alignment::top};
278 }
279
280 [[nodiscard]] static constexpr alignment middle_flush() noexcept
281 {
282 return {horizontal_alignment::flush, vertical_alignment::middle};
283 }
284
285 [[nodiscard]] static constexpr alignment middle_left() noexcept
286 {
287 return {horizontal_alignment::left, vertical_alignment::middle};
288 }
289
290 [[nodiscard]] static constexpr alignment middle_center() noexcept
291 {
292 return {horizontal_alignment::center, vertical_alignment::middle};
293 }
294
295 [[nodiscard]] static constexpr alignment middle_justified() noexcept
296 {
297 return {horizontal_alignment::justified, vertical_alignment::middle};
298 }
299
300 [[nodiscard]] static constexpr alignment middle_right() noexcept
301 {
302 return {horizontal_alignment::right, vertical_alignment::middle};
303 }
304
305 [[nodiscard]] static constexpr alignment bottom_left() noexcept
306 {
307 return {horizontal_alignment::left, vertical_alignment::bottom};
308 }
309
310 [[nodiscard]] static constexpr alignment bottom_center() noexcept
311 {
312 return {horizontal_alignment::center, vertical_alignment::bottom};
313 }
314
315 [[nodiscard]] static constexpr alignment bottom_right() noexcept
316 {
317 return {horizontal_alignment::right, vertical_alignment::bottom};
318 }
319
320 [[nodiscard]] constexpr horizontal_alignment horizontal() const noexcept
321 {
322 return static_cast<horizontal_alignment>(_value & 0xf);
323 }
324
325 [[nodiscard]] constexpr vertical_alignment vertical() const noexcept
326 {
327 return static_cast<vertical_alignment>(_value >> 4);
328 }
329
330 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, alignment const& rhs) noexcept = default;
331
332 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, horizontal_alignment const& rhs) noexcept
333 {
334 return lhs.horizontal() == rhs;
335 }
336
337 [[nodiscard]] constexpr friend bool operator==(horizontal_alignment const& lhs, alignment const& rhs) noexcept
338 {
339 return lhs == rhs.horizontal();
340 }
341
342 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, vertical_alignment const& rhs) noexcept
343 {
344 return lhs.vertical() == rhs;
345 }
346
347 [[nodiscard]] constexpr friend bool operator==(vertical_alignment const& lhs, alignment const& rhs) noexcept
348 {
349 return lhs == rhs.vertical();
350 }
351
352 [[nodiscard]] constexpr friend alignment mirror(alignment const& rhs) noexcept
353 {
354 return alignment{mirror(rhs.horizontal()), rhs.vertical()};
355 }
356
357 [[nodiscard]] constexpr friend alignment mirror(alignment const& rhs, bool left_to_right) noexcept
358 {
359 return alignment{mirror(rhs.horizontal(), left_to_right), rhs.vertical()};
360 }
361
362 [[nodiscard]] constexpr friend alignment resolve(alignment const& rhs, bool left_to_right) noexcept
363 {
364 return alignment{resolve(rhs.horizontal(), left_to_right), rhs.vertical()};
365 }
366
367 [[nodiscard]] constexpr friend alignment resolve_mirror(alignment const& rhs, bool left_to_right) noexcept
368 {
369 return alignment{resolve_mirror(rhs.horizontal(), left_to_right), rhs.vertical()};
370 }
371
372private:
378 uint8_t _value;
379};
380
387constexpr alignment operator|(horizontal_alignment lhs, vertical_alignment rhs) noexcept
388{
389 return alignment{lhs, rhs};
390}
391
398constexpr alignment operator|(vertical_alignment lhs, horizontal_alignment rhs) noexcept
399{
400 return alignment{lhs, rhs};
401}
402
403} // namespace hi::inline v1
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:264
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
vertical_alignment
Vertical alignment.
Definition alignment.hpp:19
horizontal_alignment
Horizontal alignment.
Definition alignment.hpp:96
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:59
@ 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:13
constexpr horizontal_alignment mirror(horizontal_alignment const &rhs) noexcept
Mirror the horizontal alignment.
Definition alignment.hpp:192
Horizontal/Vertical alignment combination.
Definition alignment.hpp:231
T left(T... args)