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,
152constexpr auto style_sheet_declaration_name_metadata = enum_metadata{
153 style_sheet_declaration_name::background_color,
"background-color",
154 style_sheet_declaration_name::border_bottom_left_radius,
"border-bottom-left-radius",
155 style_sheet_declaration_name::border_bottom_right_radius,
"border-bottom-right-radius",
156 style_sheet_declaration_name::border_color,
"border-color",
157 style_sheet_declaration_name::border_top_left_radius,
"border-top-left-radius",
158 style_sheet_declaration_name::border_top_right_radius,
"border-top-right-radius",
159 style_sheet_declaration_name::border_width,
"border-width",
160 style_sheet_declaration_name::caret_primary_color,
"caret-primary-color",
161 style_sheet_declaration_name::caret_secondary_color,
"caret-secondary-color",
162 style_sheet_declaration_name::caret_overwrite_color,
"caret-overwrite-color",
163 style_sheet_declaration_name::caret_compose_color,
"caret-compose-color",
164 style_sheet_declaration_name::fill_color,
"fill-color",
165 style_sheet_declaration_name::font_color,
"font-color",
166 style_sheet_declaration_name::font_family,
"font-family",
167 style_sheet_declaration_name::font_size,
"font-size",
168 style_sheet_declaration_name::font_style,
"font-style",
169 style_sheet_declaration_name::font_weight,
"font-weight",
170 style_sheet_declaration_name::height,
"height",
171 style_sheet_declaration_name::margin_bottom,
"margin-bottom",
172 style_sheet_declaration_name::margin_left,
"margin-left",
173 style_sheet_declaration_name::margin_right,
"margin-right",
174 style_sheet_declaration_name::margin_top,
"margin-top",
175 style_sheet_declaration_name::selection_color,
"selection-color",
176 style_sheet_declaration_name::width,
"width",
181constexpr auto style_sheet_declaration_name_value_mask_metadata = enum_metadata{
182 style_sheet_declaration_name::background_color, style_sheet_value_mask::color,
183 style_sheet_declaration_name::border_bottom_left_radius, style_sheet_value_mask::length,
184 style_sheet_declaration_name::border_bottom_right_radius, style_sheet_value_mask::length,
185 style_sheet_declaration_name::border_color, style_sheet_value_mask::color,
186 style_sheet_declaration_name::border_top_left_radius, style_sheet_value_mask::length,
187 style_sheet_declaration_name::border_top_right_radius, style_sheet_value_mask::length,
188 style_sheet_declaration_name::border_width, style_sheet_value_mask::length,
189 style_sheet_declaration_name::caret_primary_color, style_sheet_value_mask::color,
190 style_sheet_declaration_name::caret_secondary_color, style_sheet_value_mask::color,
191 style_sheet_declaration_name::caret_overwrite_color, style_sheet_value_mask::color,
192 style_sheet_declaration_name::caret_compose_color, style_sheet_value_mask::color,
193 style_sheet_declaration_name::fill_color, style_sheet_value_mask::color,
194 style_sheet_declaration_name::font_color, style_sheet_value_mask::color,
195 style_sheet_declaration_name::font_family, style_sheet_value_mask::font_family_id,
196 style_sheet_declaration_name::font_size, style_sheet_value_mask::dips,
197 style_sheet_declaration_name::font_style, style_sheet_value_mask::font_style,
198 style_sheet_declaration_name::font_weight, style_sheet_value_mask::font_weight,
199 style_sheet_declaration_name::height, style_sheet_value_mask::length,
200 style_sheet_declaration_name::margin_bottom, style_sheet_value_mask::length,
201 style_sheet_declaration_name::margin_left, style_sheet_value_mask::length,
202 style_sheet_declaration_name::margin_right, style_sheet_value_mask::length,
203 style_sheet_declaration_name::margin_top, style_sheet_value_mask::length,
204 style_sheet_declaration_name::selection_color, style_sheet_value_mask::color,
205 style_sheet_declaration_name::width, style_sheet_value_mask::length,
210 style_sheet_declaration_name name;
212 bool important =
false;
217 theme_state state = {};
218 theme_state_mask state_mask = {};
219 text_phrasing_mask phrasing_mask = {};
220 language_tag language_mask = {};
224 [[nodiscard]]
constexpr size_t size()
const noexcept
226 return declarations.
size();
231 return declarations[i];
234 [[nodiscard]]
constexpr std::string get_selector_as_string()
const noexcept
238 auto r = selector[0].get_path_as_glob_string();
239 for (
auto i = 1_uz; i != selector.
size(); ++i) {
241 r += selector[i].get_path_as_glob_string();
247 [[nodiscard]] generator<theme_state> matching_states(
std::string const& model_path)
const noexcept
249 if (selector.matches(model_path)) {
250 for (
auto i = theme_state{}; i != theme_state{theme_state_size}; ++i) {
251 if ((i & state_mask) == state) {
260 for (
auto model_state : matching_states(model_path)) {
261 auto& sub_model = model[model_state];
262 for (
hilet & [ name, value, important ] : declarations) {
263 _activate_model_declaration(phase, model_path, sub_model, name, value, important);
276 hi_axiom(std::holds_alternative<hi::color>(value));
277 text_style.color = std::get<hi::color>(value);
287 hi_axiom(std::holds_alternative<hi::font_family_id>(value));
288 text_style.family_id = std::get<hi::font_family_id>(value);
298 hi_axiom(std::holds_alternative<hi::font_style>(value));
299 text_style.variant.set_style(std::get<hi::font_style>(value));
309 hi_axiom(std::holds_alternative<hi::dips>(value));
312 text_style.size = -narrow_cast<float>(std::get<hi::dips>(value).count());
314 if (not language_mask and not to_bool(phrasing_mask)) {
315 sub_model.line_height = std::get<hi::dips>(value);
320 sub_model.cap_height = std::get<hi::dips>(value) * 0.7;
321 sub_model.x_height = std::get<hi::dips>(value) * 0.48;
332 hi_axiom(std::holds_alternative<hi::font_weight>(value));
333 text_style.variant.set_weight(std::get<hi::font_weight>(value));
336 template<style_sheet_declaration_name Name>
342 template<style_sheet_declaration_name Name>
348#define HI_X_COLOR_VALUE(NAME) \
350 hi_no_inline void _activate_model_color<style_sheet_declaration_name::NAME>( \
351 int phase, theme_sub_model& sub_model, style_sheet_value value, bool important) const noexcept \
357 if (not sub_model.NAME##_important or important) { \
358 sub_model.NAME = std::get<hi::color>(value); \
360 sub_model.NAME##_important |= important; \
361 sub_model.NAME##_assigned = 1; \
364 HI_X_COLOR_VALUE(background_color)
365 HI_X_COLOR_VALUE(border_color)
366 HI_X_COLOR_VALUE(fill_color)
367 HI_X_COLOR_VALUE(selection_color)
368 HI_X_COLOR_VALUE(caret_primary_color)
369 HI_X_COLOR_VALUE(caret_secondary_color)
370 HI_X_COLOR_VALUE(caret_overwrite_color)
371 HI_X_COLOR_VALUE(caret_compose_color)
372#undef HI_X_COLOR_VALUE
374#define HI_X_LENGTH_VALUE(NAME) \
376 hi_no_inline void _activate_model_length<style_sheet_declaration_name::NAME>( \
377 int phase, theme_sub_model& sub_model, style_sheet_value value, bool important) const noexcept \
383 if (not sub_model.NAME##_important or important) { \
384 if (hilet dp_ptr = std::get_if<hi::dips>(&value)) { \
385 sub_model.NAME = *dp_ptr; \
386 } else if (hilet px_ptr = std::get_if<hi::pixels>(&value)) { \
387 sub_model.NAME = *px_ptr; \
388 } else if (hilet em_ptr = std::get_if<hi::em_quads>(&value)) { \
389 sub_model.NAME = static_cast<hi::dips>(sub_model.line_height) * em_ptr->count(); \
394 sub_model.NAME##_important |= important; \
395 sub_model.NAME##_assigned = 1; \
398 HI_X_LENGTH_VALUE(width)
399 HI_X_LENGTH_VALUE(height)
400 HI_X_LENGTH_VALUE(border_width)
401 HI_X_LENGTH_VALUE(border_bottom_left_radius)
402 HI_X_LENGTH_VALUE(border_bottom_right_radius)
403 HI_X_LENGTH_VALUE(border_top_left_radius)
404 HI_X_LENGTH_VALUE(border_top_right_radius)
405 HI_X_LENGTH_VALUE(margin_left)
406 HI_X_LENGTH_VALUE(margin_bottom)
407 HI_X_LENGTH_VALUE(margin_right)
408 HI_X_LENGTH_VALUE(margin_top)
409#undef HI_X_LENGTH_VALUE
411 void _activate_model_declaration(
415 style_sheet_declaration_name name,
417 bool important)
const noexcept
419 using enum style_sheet_declaration_name;
422 case background_color:
423 return _activate_model_color<background_color>(phase, sub_model, value, important);
424 case border_bottom_left_radius:
425 return _activate_model_length<border_bottom_left_radius>(phase, sub_model, value, important);
426 case border_bottom_right_radius:
427 return _activate_model_length<border_bottom_right_radius>(phase, sub_model, value, important);
429 return _activate_model_color<border_color>(phase, sub_model, value, important);
430 case border_top_left_radius:
431 return _activate_model_length<border_top_left_radius>(phase, sub_model, value, important);
432 case border_top_right_radius:
433 return _activate_model_length<border_top_right_radius>(phase, sub_model, value, important);
435 return _activate_model_length<border_width>(phase, sub_model, value, important);
436 case caret_primary_color:
437 return _activate_model_color<caret_primary_color>(phase, sub_model, value, important);
438 case caret_secondary_color:
439 return _activate_model_color<caret_secondary_color>(phase, sub_model, value, important);
440 case caret_overwrite_color:
441 return _activate_model_color<caret_overwrite_color>(phase, sub_model, value, important);
442 case caret_compose_color:
443 return _activate_model_color<caret_compose_color>(phase, sub_model, value, important);
445 return _activate_model_color<fill_color>(phase, sub_model, value, important);
447 return _activate_model_font_color(phase, sub_model, value);
449 return _activate_model_font_family(phase, sub_model, value);
451 return _activate_model_font_size(phase, sub_model, value);
453 return _activate_model_font_style(phase, sub_model, value);
455 return _activate_model_font_weight(phase, sub_model, value);
457 return _activate_model_length<height>(phase, sub_model, value, important);
459 return _activate_model_length<margin_bottom>(phase, sub_model, value, important);
461 return _activate_model_length<margin_left>(phase, sub_model, value, important);
463 return _activate_model_length<margin_right>(phase, sub_model, value, important);
465 return _activate_model_length<margin_top>(phase, sub_model, value, important);
466 case selection_color:
467 return _activate_model_color<selection_color>(phase, sub_model, value, important);
469 return _activate_model_length<width>(phase, sub_model, value, important);
483 [[nodiscard]]
constexpr size_t size()
const noexcept
485 return rule_sets.
size();
506 void _clear() const noexcept
514 void _activate_colors() const noexcept
516 for (
hilet& color_name : color::list()) {
518 return x.first == color_name;
521 if (it != colors.
end()) {
524 *color_ptr = it->second;
526 hi_log_info(
"Named color '{}' assigned value by theme '{}:{}'", color_name, name, mode);
528 hi_log_error(
"Named color '{}' not declared in theme '{}:{}'", color_name, name, mode);
533 void _activate(
int phase)
const noexcept
538 for (
hilet& rule_set : rule_sets) {
539 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:564
std::vector< std::string > theme_model_keys() noexcept
Get a list of all the keys registered at program startup.
Definition theme_model.hpp:553
static color * find(std::string const &name) noexcept
Find a color by name.
Definition color.hpp:311
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:209
Definition style_sheet.hpp:215
Definition style_sheet.hpp:476
void activate() const noexcept
Activate style sheet as the current theme.
Definition style_sheet.hpp:495
Definition theme_length.hpp:12
All the data of a theme for a specific widget-component at a specific state.
Definition theme_model.hpp:109
The theme models for all states for a specific widget component.
Definition theme_model.hpp:273