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 "font_variant.hpp"
8#include "text_decoration.hpp"
9#include "font_family_id.hpp"
10#include "text_phrasing.hpp"
11#include "semantic_text_style.hpp"
12#include "../color/color.hpp"
13#include "../i18n/iso_15924.hpp"
14#include "../i18n/iso_639.hpp"
15#include "../numbers.hpp"
16#include "../log.hpp"
17#include "../stable_set.hpp"
18#include "../cast.hpp"
19#include "../assert.hpp"
20#include <ostream>
21#include <vector>
22#include <algorithm>
23
24namespace hi::inline v1 {
25class font_book;
26
28 text_phrasing_mask phrasing_mask;
29 iso_639 language_filter;
30 iso_15924 script_filter;
31
32 font_family_id family_id;
33 ::hi::color color;
34 float size;
35 font_variant variant;
36 text_decoration decoration;
37
38 text_sub_style() noexcept = default;
39
41 text_phrasing_mask phrasing_mask,
42 iso_639 language_filter,
43 iso_15924 script_filter,
44 font_family_id family_id,
45 font_variant variant,
46 float size,
47 ::hi::color color,
48 text_decoration decoration) noexcept :
49 phrasing_mask(phrasing_mask),
50 language_filter(language_filter),
51 script_filter(script_filter),
52 family_id(family_id),
53 color(color),
54 size(size),
55 variant(variant),
56 decoration(decoration)
57 {
58 }
59
60 [[nodiscard]] size_t hash() const noexcept
61 {
62 auto r = 0_uz;
63 r ^= std::hash<text_phrasing_mask>{}(phrasing_mask);
64 r ^= std::hash<iso_639>{}(language_filter);
65 r ^= std::hash<iso_15924>{}(script_filter);
66 r ^= std::hash<font_family_id>{}(family_id);
68 r ^= std::hash<float>{}(size);
69 r ^= std::hash<font_variant>{}(variant);
70 r ^= std::hash<text_decoration>{}(decoration);
71 return r;
72 }
73
74 [[nodiscard]] float cap_height(font_book const& font_book) const noexcept;
75 [[nodiscard]] float x_height(font_book const& font_book) const noexcept;
76
77 [[nodiscard]] bool matches(text_phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
78 {
79 if (not to_bool(phrasing_mask & to_text_phrasing_mask(phrasing))) {
80 return false;
81 }
82 if (language_filter and language and language_filter != language) {
83 return false;
84 }
85 if (script_filter and script and script_filter != script) {
86 return false;
87 }
88 return true;
89 }
90
91 [[nodiscard]] friend bool operator==(text_sub_style const&, text_sub_style const&) noexcept = default;
92};
93
94} // namespace hi::inline v1
95
96template<>
97struct std::hash<hi::text_sub_style> {
98 [[nodiscard]] size_t operator()(hi::text_sub_style const& rhs) const noexcept
99 {
100 return rhs.hash();
101 }
102};
103
104namespace hi::inline v1::detail {
105
108 using reference = value_type const&;
110 using iterator = vector_type::const_iterator;
111
112 vector_type _sub_styles;
113
114 constexpr text_style_impl() noexcept = default;
115
116 text_style_impl(std::vector<text_sub_style> sub_styles) noexcept : _sub_styles(std::move(sub_styles))
117 {
118 hi_assert(not empty());
119 hi_assert(all(back().phrasing_mask));
120 hi_assert(back().language_filter.empty());
121 hi_assert(back().script_filter.empty());
122 }
123
124 [[nodiscard]] bool empty() const noexcept
125 {
126 return _sub_styles.empty();
127 }
128
129 explicit operator bool() const noexcept
130 {
131 return not empty();
132 }
133
134 [[nodiscard]] size_t hash() const noexcept
135 {
136 auto r = 0_uz;
137 for (hilet& sub_style : _sub_styles) {
138 r ^= std::hash<text_sub_style>{}(sub_style);
139 }
140 return r;
141 }
142
143 [[nodiscard]] reference back() const noexcept
144 {
145 return _sub_styles.back();
146 }
147
148 [[nodiscard]] iterator begin() const noexcept
149 {
150 return _sub_styles.begin();
151 }
152
153 [[nodiscard]] iterator end() const noexcept
154 {
155 return _sub_styles.end();
156 }
157
158 [[nodiscard]] constexpr friend bool operator==(text_style_impl const&, text_style_impl const&) noexcept = default;
159};
160
161} // namespace hi::inline v1::detail
162
163template<>
164struct std::hash<hi::detail::text_style_impl> {
165 [[nodiscard]] size_t operator()(hi::detail::text_style_impl const& rhs) const noexcept
166 {
167 return rhs.hash();
168 }
169};
170
171namespace hi::inline v1 {
172namespace detail {
173inline auto text_styles = stable_set<text_style_impl>{};
174}
175
177public:
178 using int_type = uint16_t;
179
180 constexpr text_style() : _value(0xffff) {}
181
182 constexpr text_style(semantic_text_style rhs) noexcept : _value(0xff00 + to_underlying(rhs)) {}
183
185 {
186 hilet index = detail::text_styles.emplace(std::move(rhs));
187 if (index < 0xff00) {
188 _value = narrow_cast<uint16_t>(index);
189 } else {
190 hi_log_error_once("text-style:error:too-many", "Too many text-styles");
191 // semantic text-style "label".
192 _value = 0xff00;
193 }
194 }
195
196 [[nodiscard]] constexpr bool empty() const noexcept
197 {
198 return _value == 0xffff;
199 }
200
201 constexpr explicit operator bool() const noexcept
202 {
203 return not empty();
204 }
205
206 [[nodiscard]] constexpr bool is_semantic() const noexcept
207 {
208 hi_assert(not empty());
209 return _value >= 0xff00;
210 }
211
212 constexpr explicit operator semantic_text_style() const noexcept
213 {
214 return static_cast<semantic_text_style>(narrow_cast<std::underlying_type_t<semantic_text_style>>(_value - 0xff00));
215 }
216
217 text_sub_style const *operator->() const noexcept
218 {
219 hi_axiom(not empty());
220 if (_value < 0xff00) {
221 return std::addressof(detail::text_styles[_value].back());
222 } else {
224 }
225 }
226
227 text_sub_style const& operator*() const noexcept
228 {
229 hi_axiom(not empty());
230 if (_value < 0xff00) {
231 return detail::text_styles[_value].back();
232 } else {
234 }
235 }
236
237 text_sub_style const& sub_style(text_phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
238 {
239 for (hilet& style : detail::text_styles[_value]) {
240 if (style.matches(phrasing, language, script)) {
241 return style;
242 }
243 }
244 }
245
246private:
247 int_type _value;
248};
249
250} // namespace hi::inline v1
Utilities to assert and bound check.
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:87
#define hi_not_implemented(...)
This part of the code has not been implemented yet.
Definition assert.hpp:193
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:133
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
This file contains constants and conversion functions.
DOXYGEN BUG.
Definition algorithm.hpp:15
text_phrasing
Definition text_phrasing.hpp:15
text_decoration
Describes how a grapheme should be underlined when rendering the text.
Definition text_decoration.hpp:20
geometry/margins.hpp
Definition assert.hpp:18
This is a RGBA floating point color.
Definition color.hpp:39
ISO-15924 script code.
Definition iso_15924.hpp:19
ISO-639 language code.
Definition iso_639.hpp:25
Definition language.hpp:17
font_book keeps track of multiple fonts.
Definition font_book.hpp:31
A font variant is one of 16 different fonts that can be part of a family.
Definition font_variant.hpp:16
Definition text_style.hpp:27
Definition text_style.hpp:106
Definition text_style.hpp:176
Definition concepts.hpp:39
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)