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
55[[nodiscard]] constexpr std::optional<float> make_guideline(
57 float bottom,
58 float top,
59 float guideline_width)
60{
61 hi_axiom(is_integral_value(bottom));
62 hi_axiom(is_integral_value(top));
63 hi_axiom(is_integral_value(guideline_width));
65 hi_axiom(guideline_width >= 0.0f);
66
67 hilet guideline_bottom = bottom;
68 hilet guideline_top = top - guideline_width;
69 // XXX use std::round when constexpr.
70 hilet guideline_middle = static_cast<float>(static_cast<long long>((bottom + top - guideline_width) / 2.0f + 0.5f));
71
72 switch (alignment) {
73 case vertical_alignment::none:
74 return {};
75 case vertical_alignment::top:
76 if (guideline_bottom <= top) {
77 return guideline_top;
78 } else {
79 return {};
80 }
81 case vertical_alignment::bottom:
82 if (guideline_top >= bottom) {
83 return guideline_top;
84 } else {
85 return {};
86 }
87 case vertical_alignment::middle:
88 if (guideline_bottom <= guideline_top) {
89 return std::clamp(guideline_middle, guideline_bottom, guideline_top);
90 } else {
91 return {};
92 }
93 }
95}
96
100enum class horizontal_alignment : uint8_t {
103 none = 0,
104
110 flush = 1,
111
116 left = 2,
117
122 center = 3,
123
128 justified = 4,
129
134 right = 5,
135};
136
155[[nodiscard]] constexpr std::optional<float> make_guideline(
157 float left,
158 float right,
159 float guideline_width = 0.0f)
160{
161 hi_axiom(is_integral_value(left));
162 hi_axiom(is_integral_value(right));
163 hi_axiom(is_integral_value(guideline_width));
164 hi_axiom(left <= right);
165 hi_axiom(guideline_width >= 0.0f);
166
167 hilet guideline_left = left;
168 hilet guideline_right = right - guideline_width;
169 // XXX use std::round when constexpr.
170 hilet guideline_center = static_cast<float>(static_cast<long long>((left + right - guideline_width) / 2.0f + 0.5f));
171
172 switch (alignment) {
173 case horizontal_alignment::none:
174 return {};
175 case horizontal_alignment::left:
176 if (guideline_left <= right) {
177 return guideline_left;
178 } else {
179 return {};
180 }
181 case horizontal_alignment::right:
182 if (guideline_right >= left) {
183 return guideline_right;
184 } else {
185 return {};
186 }
187 case horizontal_alignment::center:
188 if (guideline_left <= guideline_right) {
189 return std::clamp(guideline_center, guideline_left, guideline_right);
190 } else {
191 return {};
192 }
193 }
195}
196
199[[nodiscard]] constexpr horizontal_alignment mirror(horizontal_alignment const& rhs) noexcept
200{
201 if (rhs == horizontal_alignment::left) {
202 return horizontal_alignment::right;
203 } else if (rhs == horizontal_alignment::right) {
204 return horizontal_alignment::left;
205 } else {
206 return rhs;
207 }
208}
209
212[[nodiscard]] constexpr horizontal_alignment mirror(horizontal_alignment const& rhs, bool left_to_right) noexcept
213{
214 if (left_to_right) {
215 return rhs;
216 } else {
217 return mirror(rhs);
218 }
219}
220
221[[nodiscard]] constexpr horizontal_alignment resolve(horizontal_alignment const& rhs, bool left_to_right) noexcept
222{
223 if (rhs == horizontal_alignment::flush or rhs == horizontal_alignment::justified) {
224 return left_to_right ? horizontal_alignment::left : horizontal_alignment::right;
225 } else {
226 return rhs;
227 }
228}
229
230[[nodiscard]] constexpr horizontal_alignment resolve_mirror(horizontal_alignment const& rhs, bool left_to_right) noexcept
231{
232 return resolve(mirror(rhs, left_to_right), left_to_right);
233}
234
239public:
240 constexpr alignment() noexcept : _value(0) {}
241 constexpr alignment(alignment const&) noexcept = default;
242 constexpr alignment(alignment&&) noexcept = default;
243 constexpr alignment& operator=(alignment const&) noexcept = default;
244 constexpr alignment& operator=(alignment&&) noexcept = default;
245
246 constexpr explicit alignment(uint8_t value) noexcept : _value(value) {}
247
248 constexpr alignment(horizontal_alignment t, vertical_alignment v = vertical_alignment::none) noexcept :
249 _value((to_underlying(v) << 4) | to_underlying(t))
250 {
251 hi_axiom(to_underlying(v) <= 0xf);
252 hi_axiom(to_underlying(t) <= 0xf);
253 }
254
255 constexpr alignment(vertical_alignment v, horizontal_alignment h = horizontal_alignment::none) noexcept :
256 _value((to_underlying(v) << 4) | to_underlying(h))
257 {
258 hi_axiom(to_underlying(v) <= 0xf);
259 hi_axiom(to_underlying(h) <= 0xf);
260 }
261
262 [[nodiscard]] static constexpr alignment top_flush() noexcept
263 {
264 return {horizontal_alignment::flush, vertical_alignment::top};
265 }
266
267 [[nodiscard]] static constexpr alignment top_left() noexcept
268 {
269 return {horizontal_alignment::left, vertical_alignment::top};
270 }
271
272 [[nodiscard]] static constexpr alignment top_center() noexcept
273 {
274 return {horizontal_alignment::center, vertical_alignment::top};
275 }
276
277 [[nodiscard]] static constexpr alignment top_justified() noexcept
278 {
279 return {horizontal_alignment::justified, vertical_alignment::top};
280 }
281
282 [[nodiscard]] static constexpr alignment top_right() noexcept
283 {
284 return {horizontal_alignment::right, vertical_alignment::top};
285 }
286
287 [[nodiscard]] static constexpr alignment middle_flush() noexcept
288 {
289 return {horizontal_alignment::flush, vertical_alignment::middle};
290 }
291
292 [[nodiscard]] static constexpr alignment middle_left() noexcept
293 {
294 return {horizontal_alignment::left, vertical_alignment::middle};
295 }
296
297 [[nodiscard]] static constexpr alignment middle_center() noexcept
298 {
299 return {horizontal_alignment::center, vertical_alignment::middle};
300 }
301
302 [[nodiscard]] static constexpr alignment middle_justified() noexcept
303 {
304 return {horizontal_alignment::justified, vertical_alignment::middle};
305 }
306
307 [[nodiscard]] static constexpr alignment middle_right() noexcept
308 {
309 return {horizontal_alignment::right, vertical_alignment::middle};
310 }
311
312 [[nodiscard]] static constexpr alignment bottom_left() noexcept
313 {
314 return {horizontal_alignment::left, vertical_alignment::bottom};
315 }
316
317 [[nodiscard]] static constexpr alignment bottom_center() noexcept
318 {
319 return {horizontal_alignment::center, vertical_alignment::bottom};
320 }
321
322 [[nodiscard]] static constexpr alignment bottom_right() noexcept
323 {
324 return {horizontal_alignment::right, vertical_alignment::bottom};
325 }
326
327 [[nodiscard]] constexpr horizontal_alignment horizontal() const noexcept
328 {
329 return static_cast<horizontal_alignment>(_value & 0xf);
330 }
331
332 [[nodiscard]] constexpr vertical_alignment vertical() const noexcept
333 {
334 return static_cast<vertical_alignment>(_value >> 4);
335 }
336
337 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, alignment const& rhs) noexcept = default;
338
339 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, horizontal_alignment const& rhs) noexcept
340 {
341 return lhs.horizontal() == rhs;
342 }
343
344 [[nodiscard]] constexpr friend bool operator==(horizontal_alignment const& lhs, alignment const& rhs) noexcept
345 {
346 return lhs == rhs.horizontal();
347 }
348
349 [[nodiscard]] constexpr friend bool operator==(alignment const& lhs, vertical_alignment const& rhs) noexcept
350 {
351 return lhs.vertical() == rhs;
352 }
353
354 [[nodiscard]] constexpr friend bool operator==(vertical_alignment const& lhs, alignment const& rhs) noexcept
355 {
356 return lhs == rhs.vertical();
357 }
358
359 [[nodiscard]] constexpr friend alignment mirror(alignment const& rhs) noexcept
360 {
361 return alignment{mirror(rhs.horizontal()), rhs.vertical()};
362 }
363
364 [[nodiscard]] constexpr friend alignment mirror(alignment const& rhs, bool left_to_right) noexcept
365 {
366 return alignment{mirror(rhs.horizontal(), left_to_right), rhs.vertical()};
367 }
368
369 [[nodiscard]] constexpr friend alignment resolve(alignment const& rhs, bool left_to_right) noexcept
370 {
371 return alignment{resolve(rhs.horizontal(), left_to_right), rhs.vertical()};
372 }
373
374 [[nodiscard]] constexpr friend alignment resolve_mirror(alignment const& rhs, bool left_to_right) noexcept
375 {
376 return alignment{resolve_mirror(rhs.horizontal(), left_to_right), rhs.vertical()};
377 }
378
379private:
385 uint8_t _value;
386};
387
394constexpr alignment operator|(horizontal_alignment lhs, vertical_alignment rhs) noexcept
395{
396 return alignment{lhs, rhs};
397}
398
405constexpr alignment operator|(vertical_alignment lhs, horizontal_alignment rhs) noexcept
406{
407 return alignment{lhs, rhs};
408}
409
410} // namespace hi::inline v1
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:279
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
constexpr std::optional< float > make_guideline(vertical_alignment alignment, float bottom, float top, float guideline_width)
Create a guideline between two points.
Definition alignment.hpp:55
vertical_alignment
Vertical alignment.
Definition alignment.hpp:19
horizontal_alignment
Horizontal alignment.
Definition alignment.hpp:100
@ 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:199
Horizontal/Vertical alignment combination.
Definition alignment.hpp:238