7#include "../utility/module.hpp"
8#include "../color/module.hpp"
9#include "../font/module.hpp"
10#include "../text/module.hpp"
11#include "../i18n/module.hpp"
12#include "../file/module.hpp"
13#include "theme_mode.hpp"
14#include "theme_state.hpp"
15#include "theme_length.hpp"
16#include "theme_model.hpp"
21namespace hi {
inline namespace v1 {
23enum class style_sheet_value_mask {
28 font_family_id = 0b0001'0000,
35[[nodiscard]]
constexpr style_sheet_value_mask
36operator|(style_sheet_value_mask
const& lhs, style_sheet_value_mask
const& rhs)
noexcept
38 return static_cast<style_sheet_value_mask
>(to_underlying(lhs) | to_underlying(rhs));
41[[nodiscard]]
constexpr style_sheet_value_mask
42operator&(style_sheet_value_mask
const& lhs, style_sheet_value_mask
const& rhs)
noexcept
44 return static_cast<style_sheet_value_mask
>(to_underlying(lhs) & to_underlying(rhs));
47[[nodiscard]]
constexpr bool to_bool(style_sheet_value_mask
const& rhs)
noexcept
49 return static_cast<bool>(to_underlying(rhs));
52struct style_sheet_value : std::variant<hi::pixels, hi::dips, hi::em_quads, hi::color, font_family_id, font_weight, font_style> {
53 using super = std::variant<hi::pixels, hi::dips, hi::em_quads, hi::color, font_family_id, font_weight, font_style>;
58 if (
auto pixels_ptr = std::get_if<hi::pixels>(&length)) {
59 return super{*pixels_ptr};
60 }
else if (
auto dips_ptr = std::get_if<hi::dips>(&length)) {
61 return super{*dips_ptr};
62 }
else if (
auto em_quads_ptr = std::get_if<hi::em_quads>(&length)) {
63 return super{*em_quads_ptr};
77 mutable bool pattern_cache_valid =
false;
79 [[nodiscard]]
constexpr bool matches(std::string_view model_path)
const noexcept
81 if (not pattern_cache_valid) {
82 pattern_cache = get_path_as_glob_pattern();
83 pattern_cache_valid =
true;
85 return pattern_cache.
matches(model_path);
88 [[nodiscard]]
constexpr std::string get_path_as_glob_string()
const noexcept
98 for (
auto i = 0_uz; i != is_child.
size(); ++i) {
99 r += is_child[i] ?
"/" :
"/**/";
106 [[nodiscard]]
constexpr glob_pattern get_path_as_glob_pattern()
const noexcept
113 [[nodiscard]]
bool matches(std::string_view path)
const noexcept
115 for (
hilet& pattern : *
this) {
116 if (pattern.matches(path)) {
124enum class style_sheet_declaration_name {
126 border_bottom_left_radius,
127 border_bottom_right_radius,
129 border_top_left_radius,
130 border_top_right_radius,
133 caret_secondary_color,
134 caret_overwrite_color,
154constexpr auto style_sheet_declaration_name_metadata = enum_metadata{
155 style_sheet_declaration_name::background_color,
"background-color",
156 style_sheet_declaration_name::border_bottom_left_radius,
"border-bottom-left-radius",
157 style_sheet_declaration_name::border_bottom_right_radius,
"border-bottom-right-radius",
158 style_sheet_declaration_name::border_color,
"border-color",
159 style_sheet_declaration_name::border_top_left_radius,
"border-top-left-radius",
160 style_sheet_declaration_name::border_top_right_radius,
"border-top-right-radius",
161 style_sheet_declaration_name::border_width,
"border-width",
162 style_sheet_declaration_name::caret_primary_color,
"caret-primary-color",
163 style_sheet_declaration_name::caret_secondary_color,
"caret-secondary-color",
164 style_sheet_declaration_name::caret_overwrite_color,
"caret-overwrite-color",
165 style_sheet_declaration_name::caret_compose_color,
"caret-compose-color",
166 style_sheet_declaration_name::fill_color,
"fill-color",
167 style_sheet_declaration_name::font_color,
"font-color",
168 style_sheet_declaration_name::font_family,
"font-family",
169 style_sheet_declaration_name::font_size,
"font-size",
170 style_sheet_declaration_name::font_style,
"font-style",
171 style_sheet_declaration_name::font_weight,
"font-weight",
172 style_sheet_declaration_name::height,
"height",
173 style_sheet_declaration_name::margin_bottom,
"margin-bottom",
174 style_sheet_declaration_name::margin_left,
"margin-left",
175 style_sheet_declaration_name::margin_right,
"margin-right",
176 style_sheet_declaration_name::margin_top,
"margin-top",
177 style_sheet_declaration_name::selection_color,
"selection-color",
178 style_sheet_declaration_name::spacing_horizontal,
"spacing-horizontal",
179 style_sheet_declaration_name::spacing_vertical,
"spacing-vertical",
180 style_sheet_declaration_name::width,
"width",
185constexpr auto style_sheet_declaration_name_value_mask_metadata = enum_metadata{
186 style_sheet_declaration_name::background_color, style_sheet_value_mask::color,
187 style_sheet_declaration_name::border_bottom_left_radius, style_sheet_value_mask::length,
188 style_sheet_declaration_name::border_bottom_right_radius, style_sheet_value_mask::length,
189 style_sheet_declaration_name::border_color, style_sheet_value_mask::color,
190 style_sheet_declaration_name::border_top_left_radius, style_sheet_value_mask::length,
191 style_sheet_declaration_name::border_top_right_radius, style_sheet_value_mask::length,
192 style_sheet_declaration_name::border_width, style_sheet_value_mask::length,
193 style_sheet_declaration_name::caret_primary_color, style_sheet_value_mask::color,
194 style_sheet_declaration_name::caret_secondary_color, style_sheet_value_mask::color,
195 style_sheet_declaration_name::caret_overwrite_color, style_sheet_value_mask::color,
196 style_sheet_declaration_name::caret_compose_color, style_sheet_value_mask::color,
197 style_sheet_declaration_name::fill_color, style_sheet_value_mask::color,
198 style_sheet_declaration_name::font_color, style_sheet_value_mask::color,
199 style_sheet_declaration_name::font_family, style_sheet_value_mask::font_family_id,
200 style_sheet_declaration_name::font_size, style_sheet_value_mask::dips,
201 style_sheet_declaration_name::font_style, style_sheet_value_mask::font_style,
202 style_sheet_declaration_name::font_weight, style_sheet_value_mask::font_weight,
203 style_sheet_declaration_name::height, style_sheet_value_mask::length,
204 style_sheet_declaration_name::margin_bottom, style_sheet_value_mask::length,
205 style_sheet_declaration_name::margin_left, style_sheet_value_mask::length,
206 style_sheet_declaration_name::margin_right, style_sheet_value_mask::length,
207 style_sheet_declaration_name::margin_top, style_sheet_value_mask::length,
208 style_sheet_declaration_name::selection_color, style_sheet_value_mask::color,
209 style_sheet_declaration_name::spacing_horizontal, style_sheet_value_mask::length,
210 style_sheet_declaration_name::spacing_vertical, style_sheet_value_mask::length,
211 style_sheet_declaration_name::width, style_sheet_value_mask::length,
216 style_sheet_declaration_name name;
218 bool important =
false;
223 theme_state state = {};
224 theme_state_mask state_mask = {};
225 text_phrasing_mask phrasing_mask = {};
226 language_tag language_mask = {};
230 [[nodiscard]]
constexpr size_t size()
const noexcept
232 return declarations.
size();
237 return declarations[i];
240 [[nodiscard]]
constexpr std::string get_selector_as_string()
const noexcept
244 auto r = selector[0].get_path_as_glob_string();
245 for (
auto i = 1_uz; i != selector.
size(); ++i) {
247 r += selector[i].get_path_as_glob_string();
253 [[nodiscard]] generator<theme_state> matching_states(
std::string const& model_path)
const noexcept
255 if (selector.matches(model_path)) {
256 for (
auto i = theme_state{}; i != theme_state{theme_state_size}; ++i) {
257 if ((i & state_mask) == state) {
266 for (
auto model_state : matching_states(model_path)) {
267 auto& sub_model = model[model_state];
268 for (
hilet & [ name, value, important ] : declarations) {
269 _activate_model_declaration(phase, model_path, sub_model, name, value, important);
282 hi_axiom(std::holds_alternative<hi::color>(value));
283 text_style.color = std::get<hi::color>(value);
293 hi_axiom(std::holds_alternative<hi::font_family_id>(value));
294 text_style.family_id = std::get<hi::font_family_id>(value);
304 hi_axiom(std::holds_alternative<hi::font_style>(value));
305 text_style.variant.set_style(std::get<hi::font_style>(value));
315 hi_axiom(std::holds_alternative<hi::dips>(value));
318 text_style.size = round_cast<int>(std::get<hi::dips>(value).count() * -4.0);
320 if (not language_mask and not to_bool(phrasing_mask)) {
321 sub_model.line_height = std::get<hi::dips>(value);
326 sub_model.cap_height = std::get<hi::dips>(value) * 0.7;
327 sub_model.x_height = std::get<hi::dips>(value) * 0.48;
338 hi_axiom(std::holds_alternative<hi::font_weight>(value));
339 text_style.variant.set_weight(std::get<hi::font_weight>(value));
342 template<style_sheet_declaration_name Name>
348 template<style_sheet_declaration_name Name>
354#define HI_X_COLOR_VALUE(NAME) \
356 hi_no_inline void _activate_model_color<style_sheet_declaration_name::NAME>( \
357 int phase, theme_sub_model& sub_model, style_sheet_value value, bool important) const noexcept \
363 if (not sub_model.NAME##_important or important) { \
364 sub_model.NAME = std::get<hi::color>(value); \
366 sub_model.NAME##_important |= important; \
367 sub_model.NAME##_assigned = 1; \
370 HI_X_COLOR_VALUE(background_color)
371 HI_X_COLOR_VALUE(border_color)
372 HI_X_COLOR_VALUE(fill_color)
373 HI_X_COLOR_VALUE(selection_color)
374 HI_X_COLOR_VALUE(caret_primary_color)
375 HI_X_COLOR_VALUE(caret_secondary_color)
376 HI_X_COLOR_VALUE(caret_overwrite_color)
377 HI_X_COLOR_VALUE(caret_compose_color)
378#undef HI_X_COLOR_VALUE
380#define HI_X_LENGTH_VALUE(NAME) \
382 hi_no_inline void _activate_model_length<style_sheet_declaration_name::NAME>( \
383 int phase, theme_sub_model& sub_model, style_sheet_value value, bool important) const noexcept \
389 if (not sub_model.NAME##_important or important) { \
390 if (hilet dp_ptr = std::get_if<hi::dips>(&value)) { \
391 sub_model.NAME = *dp_ptr; \
392 } else if (hilet px_ptr = std::get_if<hi::pixels>(&value)) { \
393 sub_model.NAME = *px_ptr; \
394 } else if (hilet em_ptr = std::get_if<hi::em_quads>(&value)) { \
395 sub_model.NAME = static_cast<hi::dips>(sub_model.line_height) * em_ptr->count(); \
400 sub_model.NAME##_important |= important; \
401 sub_model.NAME##_assigned = 1; \
404 HI_X_LENGTH_VALUE(width)
405 HI_X_LENGTH_VALUE(height)
406 HI_X_LENGTH_VALUE(border_width)
407 HI_X_LENGTH_VALUE(border_bottom_left_radius)
408 HI_X_LENGTH_VALUE(border_bottom_right_radius)
409 HI_X_LENGTH_VALUE(border_top_left_radius)
410 HI_X_LENGTH_VALUE(border_top_right_radius)
411 HI_X_LENGTH_VALUE(margin_left)
412 HI_X_LENGTH_VALUE(margin_bottom)
413 HI_X_LENGTH_VALUE(margin_right)
414 HI_X_LENGTH_VALUE(margin_top)
415 HI_X_LENGTH_VALUE(spacing_horizontal)
416 HI_X_LENGTH_VALUE(spacing_vertical)
417#undef HI_X_LENGTH_VALUE
419 void _activate_model_declaration(
423 style_sheet_declaration_name name,
425 bool important)
const noexcept
427 using enum style_sheet_declaration_name;
430 case background_color:
431 return _activate_model_color<background_color>(phase, sub_model, value, important);
432 case border_bottom_left_radius:
433 return _activate_model_length<border_bottom_left_radius>(phase, sub_model, value, important);
434 case border_bottom_right_radius:
435 return _activate_model_length<border_bottom_right_radius>(phase, sub_model, value, important);
437 return _activate_model_color<border_color>(phase, sub_model, value, important);
438 case border_top_left_radius:
439 return _activate_model_length<border_top_left_radius>(phase, sub_model, value, important);
440 case border_top_right_radius:
441 return _activate_model_length<border_top_right_radius>(phase, sub_model, value, important);
443 return _activate_model_length<border_width>(phase, sub_model, value, important);
444 case caret_primary_color:
445 return _activate_model_color<caret_primary_color>(phase, sub_model, value, important);
446 case caret_secondary_color:
447 return _activate_model_color<caret_secondary_color>(phase, sub_model, value, important);
448 case caret_overwrite_color:
449 return _activate_model_color<caret_overwrite_color>(phase, sub_model, value, important);
450 case caret_compose_color:
451 return _activate_model_color<caret_compose_color>(phase, sub_model, value, important);
453 return _activate_model_color<fill_color>(phase, sub_model, value, important);
455 return _activate_model_font_color(phase, sub_model, value);
457 return _activate_model_font_family(phase, sub_model, value);
459 return _activate_model_font_size(phase, sub_model, value);
461 return _activate_model_font_style(phase, sub_model, value);
463 return _activate_model_font_weight(phase, sub_model, value);
465 return _activate_model_length<height>(phase, sub_model, value, important);
467 return _activate_model_length<margin_bottom>(phase, sub_model, value, important);
469 return _activate_model_length<margin_left>(phase, sub_model, value, important);
471 return _activate_model_length<margin_right>(phase, sub_model, value, important);
473 return _activate_model_length<margin_top>(phase, sub_model, value, important);
474 case selection_color:
475 return _activate_model_color<selection_color>(phase, sub_model, value, important);
476 case spacing_horizontal:
477 return _activate_model_length<spacing_horizontal>(phase, sub_model, value, important);
478 case spacing_vertical:
479 return _activate_model_length<spacing_vertical>(phase, sub_model, value, important);
481 return _activate_model_length<width>(phase, sub_model, value, important);
495 [[nodiscard]]
constexpr size_t size()
const noexcept
497 return rule_sets.
size();
518 void _clear() const noexcept
526 void _activate_colors() const noexcept
528 for (
hilet& color_name : color::list()) {
530 return x.first == color_name;
533 if (it != colors.
end()) {
536 *color_ptr = it->second;
538 hi_log_info(
"Named color '{}' assigned value by theme '{}:{}'", color_name, name, mode);
540 hi_log_error(
"Named color '{}' not declared in theme '{}:{}'", color_name, name, mode);
545 void _activate(
int phase)
const noexcept
550 for (
hilet& rule_set : rule_sets) {
551 rule_set.activate_model(phase, model_path, model);
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:199
#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 hi_axiom_not_null(expression,...)
Assert if an expression is not nullptr.
Definition assert.hpp:272
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
font_weight
Definition font_weight.hpp:17
geometry/margins.hpp
Definition cache.hpp:11
unit< em_length_tag, double > em_quads
Em-quad: A font's line-height.
Definition units.hpp:196
unit< px_length_tag, double > pixels
A physical pixel on a display.
Definition units.hpp:192
unit< si_length_tag, double, std::ratio< 254, 960 '000 >::type > dips
Device Independent Pixels: 1/96 inch.
Definition units.hpp:188
font_style
The different styles a font-family comes with.
Definition font_style.hpp:24
theme_model_base & theme_model_by_key(std::string const &key)
Get a theme-model by key.
Definition theme_model.hpp:597
std::vector< std::string > theme_model_keys() noexcept
Get a list of all the keys registered at program startup.
Definition theme_model.hpp:586
static color * find(std::string const &name) noexcept
Find a color by name.
Definition color.hpp:310
A glob pattern.
Definition glob.hpp:41
constexpr bool matches(std::u32string_view str) const noexcept
Match the pattern with the given string.
Definition glob.hpp:209
Definition text_style.hpp:15
text_style & find_or_add(text_phrasing_mask phrasing_mask, language_tag language_mask) noexcept
Find or add an text_style to the text-theme.
Definition text_theme.hpp:40
Definition style_sheet.hpp:52
Definition style_sheet.hpp:72
Definition style_sheet.hpp:112
Definition style_sheet.hpp:215
Definition style_sheet.hpp:221
Definition style_sheet.hpp:488
void activate() const noexcept
Activate style sheet as the current theme.
Definition style_sheet.hpp:507
Definition theme_length.hpp:12
All the data of a theme for a specific widget-component at a specific state.
Definition theme_model.hpp:117
The theme models for all states for a specific widget component.
Definition theme_model.hpp:293