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
76 [[nodiscard]] bool matches(text_phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
77 {
78 if (not to_bool(phrasing_mask & to_text_phrasing_mask(phrasing))) {
79 return false;
80 }
81 if (language_filter and language and language_filter != language) {
82 return false;
83 }
84 if (script_filter and script and script_filter != script) {
85 return false;
86 }
87 return true;
88 }
89
90 [[nodiscard]] friend bool operator==(text_sub_style const&, text_sub_style const&) noexcept = default;
91};
92
93} // namespace hi::inline v1
94
95template<>
96struct std::hash<hi::text_sub_style> {
97 [[nodiscard]] size_t operator()(hi::text_sub_style const& rhs) const noexcept
98 {
99 return rhs.hash();
100 }
101};
102
103namespace hi::inline v1::detail {
104
107 using reference = value_type const&;
109 using iterator = vector_type::const_iterator;
110
111 vector_type _sub_styles;
112
113 constexpr text_style_impl() noexcept = default;
114
115 text_style_impl(std::vector<text_sub_style> sub_styles) noexcept : _sub_styles(std::move(sub_styles))
116 {
117 hi_axiom(not empty());
118 hi_axiom(all(back().phrasing_mask));
119 hi_axiom(back().language_filter.empty());
120 hi_axiom(back().script_filter.empty());
121 }
122
123 [[nodiscard]] bool empty() const noexcept
124 {
125 return _sub_styles.empty();
126 }
127
128 explicit operator bool() const noexcept
129 {
130 return not empty();
131 }
132
133 [[nodiscard]] size_t hash() const noexcept
134 {
135 auto r = 0_uz;
136 for (hilet& sub_style : _sub_styles) {
137 r ^= std::hash<text_sub_style>{}(sub_style);
138 }
139 return r;
140 }
141
142 [[nodiscard]] reference back() const noexcept
143 {
144 return _sub_styles.back();
145 }
146
147 [[nodiscard]] iterator begin() const noexcept
148 {
149 return _sub_styles.begin();
150 }
151
152 [[nodiscard]] iterator end() const noexcept
153 {
154 return _sub_styles.end();
155 }
156
157 [[nodiscard]] constexpr friend bool operator==(text_style_impl const&, text_style_impl const&) noexcept = default;
158};
159
160} // namespace hi::inline v1::detail
161
162template<>
163struct std::hash<hi::detail::text_style_impl> {
164 [[nodiscard]] size_t operator()(hi::detail::text_style_impl const& rhs) const noexcept
165 {
166 return rhs.hash();
167 }
168};
169
170namespace hi::inline v1 {
171namespace detail {
172inline auto text_styles = stable_set<text_style_impl>{};
173}
174
176public:
177 using int_type = uint16_t;
178
179 constexpr text_style() : _value(0xffff) {}
180
181 constexpr text_style(semantic_text_style rhs) noexcept : _value(0xff00 + to_underlying(rhs)) {}
182
184 {
185 hilet index = detail::text_styles.emplace(std::move(rhs));
186 if (index < 0xff00) {
187 _value = narrow_cast<uint16_t>(index);
188 } else {
189 hi_log_error_once("text-style:error:too-many", "Too many text-styles");
190 // semantic text-style "label".
191 _value = 0xff00;
192 }
193 }
194
195 [[nodiscard]] constexpr bool empty() const noexcept
196 {
197 return _value == 0xffff;
198 }
199
200 constexpr explicit operator bool() const noexcept
201 {
202 return not empty();
203 }
204
205 [[nodiscard]] constexpr bool is_semantic() const noexcept
206 {
207 hi_axiom(not empty());
208 return _value >= 0xff00;
209 }
210
211 constexpr explicit operator semantic_text_style() const noexcept
212 {
213 return static_cast<semantic_text_style>(narrow_cast<std::underlying_type_t<semantic_text_style>>(_value - 0xff00));
214 }
215
216 text_sub_style const *operator->() const noexcept
217 {
218 hi_axiom(not empty());
219 if (_value < 0xff00) {
220 return std::addressof(detail::text_styles[_value].back());
221 } else {
222 hi_not_implemented();
223 }
224 }
225
226 text_sub_style const& operator*() const noexcept
227 {
228 hi_axiom(not empty());
229 if (_value < 0xff00) {
230 return detail::text_styles[_value].back();
231 } else {
232 hi_not_implemented();
233 }
234 }
235
236 text_sub_style const& sub_style(text_phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
237 {
238 for (hilet& style : detail::text_styles[_value]) {
239 if (style.matches(phrasing, language, script)) {
240 return style;
241 }
242 }
243 }
244
245private:
246 int_type _value;
247};
248
249} // namespace hi::inline v1
#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
The HikoGUI namespace.
Definition ascii.hpp:19
This is a RGBA floating point color.
Definition color.hpp:39
ISO-15924 script code.
Definition iso_15924.hpp:18
ISO-639 language code.
Definition iso_639.hpp:25
Definition language.hpp:18
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:105
Definition text_style.hpp:175
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)