HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
text_style.hpp
1// Copyright Take Vos 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
5#pragma once
6
7#include "text_decoration.hpp"
8#include "semantic_text_style.hpp"
9#include "../color/module.hpp"
10#include "../i18n/i18n.hpp"
11#include "../unicode/unicode.hpp"
12#include "../utility/utility.hpp"
13#include "../font/font.hpp"
14#include "../telemetry/telemetry.hpp"
15#include "../container/module.hpp"
16#include "../macros.hpp"
17#include <ostream>
18#include <vector>
19#include <algorithm>
20
21namespace hi::inline v1 {
22
24 phrasing_mask phrasing_mask;
25 iso_639 language_filter;
26 iso_15924 script_filter;
27
28 font_family_id family_id;
29 ::hi::color color;
30 float size;
31 font_variant variant;
32 text_decoration decoration;
33
34 text_sub_style() noexcept = default;
35
37 hi::phrasing_mask phrasing_mask,
38 iso_639 language_filter,
39 iso_15924 script_filter,
40 font_family_id family_id,
41 font_variant variant,
42 float size,
43 ::hi::color color,
44 text_decoration decoration) noexcept :
45 phrasing_mask(phrasing_mask),
46 language_filter(language_filter),
47 script_filter(script_filter),
48 family_id(family_id),
49 color(color),
50 size(size),
51 variant(variant),
52 decoration(decoration)
53 {
54 }
55
56 [[nodiscard]] size_t hash() const noexcept
57 {
58 auto r = 0_uz;
59 r ^= std::hash<hi::phrasing_mask>{}(phrasing_mask);
60 r ^= std::hash<iso_639>{}(language_filter);
61 r ^= std::hash<iso_15924>{}(script_filter);
62 r ^= std::hash<font_family_id>{}(family_id);
63 r ^= std::hash<hi::color>{}(color);
64 r ^= std::hash<float>{}(size);
65 r ^= std::hash<font_variant>{}(variant);
66 r ^= std::hash<text_decoration>{}(decoration);
67 return r;
68 }
69
70 [[nodiscard]] float cap_height() const noexcept
71 {
72 hilet& font = find_font(family_id, variant);
73 return font.metrics.cap_height * size;
74 }
75
76 [[nodiscard]] float x_height() const noexcept
77 {
78 hilet& font = find_font(family_id, variant);
79 return font.metrics.x_height * size;
80 }
81
82 [[nodiscard]] bool matches(phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
83 {
84 if (not to_bool(phrasing_mask & to_phrasing_mask(phrasing))) {
85 return false;
86 }
87 if (language_filter and language and language_filter != language) {
88 return false;
89 }
90 if (script_filter and script and script_filter != script) {
91 return false;
92 }
93 return true;
94 }
95
96 [[nodiscard]] friend bool operator==(text_sub_style const&, text_sub_style const&) noexcept = default;
97};
98
99} // namespace hi::inline v1
100
101template<>
102struct std::hash<hi::text_sub_style> {
103 [[nodiscard]] size_t operator()(hi::text_sub_style const& rhs) const noexcept
104 {
105 return rhs.hash();
106 }
107};
108
109namespace hi::inline v1::detail {
110
113 using reference = value_type const&;
115 using iterator = vector_type::const_iterator;
116
117 vector_type _sub_styles;
118
119 constexpr text_style_impl() noexcept = default;
120
121 text_style_impl(std::vector<text_sub_style> sub_styles) noexcept : _sub_styles(std::move(sub_styles))
122 {
123 hi_assert(not empty());
124 hi_assert(all(back().phrasing_mask));
125 hi_assert(back().language_filter.empty());
126 hi_assert(back().script_filter.empty());
127 }
128
129 [[nodiscard]] bool empty() const noexcept
130 {
131 return _sub_styles.empty();
132 }
133
134 explicit operator bool() const noexcept
135 {
136 return not empty();
137 }
138
139 [[nodiscard]] size_t hash() const noexcept
140 {
141 auto r = 0_uz;
142 for (hilet& sub_style : _sub_styles) {
143 r ^= std::hash<text_sub_style>{}(sub_style);
144 }
145 return r;
146 }
147
148 [[nodiscard]] reference back() const noexcept
149 {
150 return _sub_styles.back();
151 }
152
153 [[nodiscard]] iterator begin() const noexcept
154 {
155 return _sub_styles.begin();
156 }
157
158 [[nodiscard]] iterator end() const noexcept
159 {
160 return _sub_styles.end();
161 }
162
163 [[nodiscard]] constexpr friend bool operator==(text_style_impl const&, text_style_impl const&) noexcept = default;
164};
165
166} // namespace hi::inline v1::detail
167
168template<>
169struct std::hash<hi::detail::text_style_impl> {
170 [[nodiscard]] size_t operator()(hi::detail::text_style_impl const& rhs) const noexcept
171 {
172 return rhs.hash();
173 }
174};
175
176namespace hi::inline v1 {
177namespace detail {
178inline auto text_styles = stable_set<text_style_impl>{};
179}
180
182public:
183 using int_type = uint16_t;
184
185 constexpr text_style() : _value(0xffff) {}
186 constexpr text_style(text_style const&) noexcept = default;
187 constexpr text_style(text_style&&) noexcept = default;
188 constexpr text_style& operator=(text_style const&) noexcept = default;
189 constexpr text_style& operator=(text_style&&) noexcept = default;
190 [[nodiscard]] constexpr friend bool operator==(text_style const&, text_style const&) noexcept = default;
191
192 constexpr text_style(semantic_text_style rhs) noexcept : _value(0xff00 + std::to_underlying(rhs)) {}
193
195 {
196 hilet index = detail::text_styles.emplace(std::move(rhs));
197 if (index < 0xff00) {
198 _value = narrow_cast<uint16_t>(index);
199 } else {
200 hi_log_error_once("text-style:error:too-many", "Too many text-styles");
201 // semantic text-style "label".
202 _value = 0xff00;
203 }
204 }
205
206 [[nodiscard]] constexpr bool empty() const noexcept
207 {
208 return _value == 0xffff;
209 }
210
211 constexpr explicit operator bool() const noexcept
212 {
213 return not empty();
214 }
215
216 [[nodiscard]] constexpr bool is_semantic() const noexcept
217 {
218 hi_assert(not empty());
219 return _value >= 0xff00;
220 }
221
222 constexpr explicit operator semantic_text_style() const noexcept
223 {
224 return static_cast<semantic_text_style>(narrow_cast<std::underlying_type_t<semantic_text_style>>(_value - 0xff00));
225 }
226
227 text_sub_style const *operator->() const noexcept
228 {
229 hi_axiom(not empty());
230 if (_value < 0xff00) {
231 return std::addressof(detail::text_styles[_value].back());
232 } else {
233 hi_not_implemented();
234 }
235 }
236
237 text_sub_style const& operator*() const noexcept
238 {
239 hi_axiom(not empty());
240 if (_value < 0xff00) {
241 return detail::text_styles[_value].back();
242 } else {
243 hi_not_implemented();
244 }
245 }
246
247 text_sub_style const& sub_style(phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
248 {
249 for (hilet& style : detail::text_styles[_value]) {
250 if (style.matches(phrasing, language, script)) {
251 return style;
252 }
253 }
254 }
255
256private:
257 int_type _value;
258};
259
260} // namespace hi::inline v1
phrasing
Phrasing.
Definition phrasing.hpp:30
DOXYGEN BUG.
Definition algorithm.hpp:16
text_decoration
Describes how a grapheme should be underlined when rendering the text.
Definition text_decoration.hpp:23
hi_export font const & find_font(font_family_id family_id, font_variant variant=font_variant{}) noexcept
Find a font closest to the variant.
Definition font_book.hpp:412
constexpr bool matches(phrasing_mask const &lhs, phrasing const &rhs) noexcept
Check if the text-phrasing is included in the text-phrasing-mask.
Definition phrasing.hpp:227
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
This is a RGBA floating point color.
Definition color.hpp:45
Definition font_font.hpp:31
hi::font_metrics metrics
The metrics of a font.
Definition font_font.hpp:67
A font variant is one of 16 different fonts that can be part of a family.
Definition font_variant.hpp:19
ISO-639 language code.
Definition iso_639.hpp:25
Definition text_style.hpp:23
Definition text_style.hpp:111
Definition text_style.hpp:181
T addressof(T... args)
T back(T... args)
T begin(T... args)
T empty(T... args)
T end(T... args)
T move(T... args)
T operator()(T... args)