5#include "style_attributes.hpp"
6#include "../parser/parser.hpp"
7#include "../container/container.hpp"
8#include "../macros.hpp"
13hi_export_module(hikogui.theme : theme_tag);
15hi_export
namespace hi {
19template<std::input_iterator It, std::sentinel_for<It> ItEnd>
20[[nodiscard]]
constexpr expected_optional<std::string, std::string> parse_style_path_id(It& it, ItEnd last)
22 hi_assert(it != last);
29 if (it == last or *it != token::id) {
33 auto r =
static_cast<std::string
>(*it);
38template<std::input_iterator It, std::sentinel_for<It> ItEnd>
39[[nodiscard]]
constexpr expected_optional<std::string, std::string> parse_style_path_class(It& it, ItEnd last)
41 hi_assert(it != last);
48 if (it == last or *it != token::id) {
52 auto r =
static_cast<std::string
>(*it);
57template<std::input_iterator It, std::sentinel_for<It> ItEnd>
58[[nodiscard]]
constexpr expected_optional<horizontal_alignment, std::string> parse_style_horizontal_alignment(It& it, ItEnd last)
60 hi_assert(it != last);
62 if (*it != token::id) {
69 }
else if (*it ==
"flush") {
72 }
else if (*it ==
"left") {
75 }
else if (*it ==
"center") {
78 }
else if (*it ==
"justified") {
81 }
else if (*it ==
"right") {
89template<std::input_iterator It, std::sentinel_for<It> ItEnd>
90[[nodiscard]]
constexpr expected_optional<vertical_alignment, std::string> parse_style_vertical_alignment(It& it, ItEnd last)
92 hi_assert(it != last);
94 if (*it != token::id) {
101 }
else if (*it ==
"top") {
104 }
else if (*it ==
"middle") {
107 }
else if (*it ==
"bottom") {
114template<std::input_iterator It, std::sentinel_for<It> ItEnd>
115[[nodiscard]]
constexpr expected_optional<unit::length_f, std::string> parse_style_length(It& it, ItEnd last)
117 hi_assert(it != last);
119 if (*it != token::integer and *it != token::real) {
123 auto const value =
static_cast<float>(*it);
126 if (it == last or *it != token::id) {
128 return unit::dips(value);
129 }
else if (*it ==
"px") {
131 return unit::pixels(value);
132 }
else if (*it ==
"dp" or *it ==
"dip") {
134 return unit::dips(value);
135 }
else if (*it ==
"pt") {
137 return unit::points(value);
138 }
else if (*it ==
"in") {
140 return au::inches(value);
141 }
else if (*it ==
"cm") {
143 return au::centi(au::meters)(value);
146 return unit::dips(value);
150template<std::input_iterator It, std::sentinel_for<It> ItEnd>
151[[nodiscard]]
constexpr expected_optional<color, std::string> parse_style_color(It& it, ItEnd last)
153 hi_assert(it != last);
155 if (*it == token::id and *it ==
"rgb") {
157 if (it == last or *it !=
'(') {
162 if (it == last or (*it != token::integer and *it != token::real)) {
164 std::format(
"{}: Expecting a number as first argument to rgb_color.",
token_location(it, last))};
166 auto const red =
static_cast<float>(*it);
169 if (it == last or *it !=
',') {
171 std::format(
"{}: Expecting a comma ',' after first argument to rgb_color.",
token_location(it, last))};
175 if (it == last or (*it != token::integer and *it != token::real)) {
177 std::format(
"{}: Expecting a number as second argument to rgb_color.",
token_location(it, last))};
179 auto const green =
static_cast<float>(*it);
182 if (it == last or *it !=
',') {
184 std::format(
"{}: Expecting a comma ',' after second argument to rgb_color.",
token_location(it, last))};
188 if (it == last or (*it != token::integer and *it != token::real)) {
190 std::format(
"{}: Expecting a number as third argument to rgb_color.",
token_location(it, last))};
192 auto const blue =
static_cast<float>(*it);
195 if (it == last or *it !=
')') {
200 return color{red, green, blue, 1.0f};
202 }
else if (*it == token::id and *it ==
"rgba") {
204 if (it == last or *it !=
'(') {
209 if (it == last or (*it != token::integer and *it != token::real)) {
211 std::format(
"{}: Expecting a number as first argument to rgba_color.",
token_location(it, last))};
213 auto const red =
static_cast<float>(*it);
216 if (it == last or *it !=
',') {
218 std::format(
"{}: Expecting a comma ',' after first argument to rgba_color.",
token_location(it, last))};
222 if (it == last or (*it != token::integer and *it != token::real)) {
224 std::format(
"{}: Expecting a number as second argument to rgba_color.",
token_location(it, last))};
226 auto const green =
static_cast<float>(*it);
229 if (it == last or *it !=
',') {
231 std::format(
"{}: Expecting a comma ',' after second argument to rgba_color.",
token_location(it, last))};
235 if (it == last or (*it != token::integer and *it != token::real)) {
237 std::format(
"{}: Expecting a number as third argument to rgba_color.",
token_location(it, last))};
239 auto const blue =
static_cast<float>(*it);
242 if (it == last or *it !=
',') {
244 std::format(
"{}: Expecting a comma ',' after third argument to rgba_color.",
token_location(it, last))};
248 if (it == last or (*it != token::integer and *it != token::real)) {
250 std::format(
"{}: Expecting a number as forth argument to rgba_color.",
token_location(it, last))};
252 auto const alpha =
static_cast<float>(*it);
255 if (it == last or *it !=
')') {
260 return color{red, green, blue, alpha};
262 }
else if (*it == token::id) {
263 auto const color_name =
static_cast<std::string
>(*it);
266 if (
auto const* color_ptr =
color::find(color_name)) {
272 }
else if (*it == token::sstr or *it == token::dstr) {
273 auto const color_name =
static_cast<std::string
>(*it);
276 if (color_name.starts_with(
"#")) {
280 }
catch (std::exception
const &e) {
284 }
else if (
auto const* color_ptr =
color::find(color_name)) {
295template<std::input_iterator It, std::sentinel_for<It> ItEnd>
296[[nodiscard]]
constexpr expected_optional<style_attributes, std::string> parse_style_attribute(It& it, ItEnd last)
298#define HIX_VALUE(VALUE_PARSER, NAME, ATTRIBUTE) \
299 if (name == NAME) { \
300 if (auto const value = VALUE_PARSER(it, last)) { \
301 auto r = style_attributes{}; \
302 r.set_##ATTRIBUTE(*value, true); \
304 } else if (value.has_error()) { \
305 return std::unexpected(value.error()); \
307 return std::unexpected(std::format("{}: Unknown value {} for attribute '{}'", token_location(it, last), *it, name)); \
311 hi_assert(it != last);
313 if (it.size() < 3 or it[0] != token::id or it[1] !=
'=') {
317 auto const name =
static_cast<std::string
>(it[0]);
320 HIX_VALUE(parse_style_length,
"width", width)
321 HIX_VALUE(parse_style_length,
"height", height)
322 HIX_VALUE(parse_style_length,
"margin-left", margin_left)
323 HIX_VALUE(parse_style_length,
"margin-bottom", margin_bottom)
324 HIX_VALUE(parse_style_length,
"margin-right", margin_right)
325 HIX_VALUE(parse_style_length,
"margin-top", margin_top)
326 HIX_VALUE(parse_style_length,
"margin",
margin)
327 HIX_VALUE(parse_style_length,
"padding-left", padding_left)
328 HIX_VALUE(parse_style_length,
"padding-bottom", padding_bottom)
329 HIX_VALUE(parse_style_length,
"padding-right", padding_right)
330 HIX_VALUE(parse_style_length,
"padding-top", padding_top)
331 HIX_VALUE(parse_style_length,
"padding", padding)
332 HIX_VALUE(parse_style_length,
"border-width", border_width)
333 HIX_VALUE(parse_style_length,
"border-bottom-left-radius", border_bottom_left_radius)
334 HIX_VALUE(parse_style_length,
"border-bottom-right-radius", border_bottom_right_radius)
335 HIX_VALUE(parse_style_length,
"border-top-left-radius", border_top_left_radius)
336 HIX_VALUE(parse_style_length,
"border-top-right-radius", border_top_right_radius)
337 HIX_VALUE(parse_style_length,
"border-radius", border_radius)
338 HIX_VALUE(parse_style_color,
"foreground-color", foreground_color)
339 HIX_VALUE(parse_style_color,
"background-color", background_color)
340 HIX_VALUE(parse_style_color,
"border-color", border_color)
352template<std::input_iterator It, std::sentinel_for<It> ItEnd>
355 constexpr auto config = [] {
357 r.has_double_quote_string_literal = 1;
358 r.has_single_quote_string_literal = 1;
359 r.filter_white_space = 1;
360 r.minus_in_identifier = 1;
364 auto lexer_it = lexer<config>.parse(first, last);
367 auto attributes = hi::style_attributes{};
368 auto id = std::string{};
369 auto classes = std::vector<std::string>{};
370 while (token_it != std::default_sentinel) {
371 if (
auto attribute = detail::parse_style_attribute(token_it, std::default_sentinel)) {
372 attributes.apply(*attribute);
375 }
else if (attribute.has_error()) {
379 if (
auto new_id = detail::parse_style_path_id(token_it, std::default_sentinel)) {
387 }
else if (new_id.has_error()) {
391 if (
auto new_class = detail::parse_style_path_class(token_it, std::default_sentinel)) {
392 classes.push_back(*new_class);
395 }
else if (new_class.has_error()) {
402 return std::tuple{attributes, id, classes};
407 return parse_style(str.begin(), str.end());
color color_from_sRGB(float r, float g, float b, float a) noexcept
Convert gama corrected sRGB color to the linear color.
Definition sRGB.hpp:149
vertical_alignment
Vertical alignment.
Definition alignment.hpp:25
horizontal_alignment
Horizontal alignment.
Definition alignment.hpp:102
@ none
No alignment.
Definition alignment.hpp:28
@ middle
Align to the vertical-middle.
Definition alignment.hpp:36
@ bottom
Align to the bottom.
Definition alignment.hpp:40
@ top
Align to the top.
Definition alignment.hpp:32
@ none
No alignment.
Definition alignment.hpp:105
@ right
Align the text to the right side.
Definition alignment.hpp:136
@ left
Align the text to the left side.
Definition alignment.hpp:118
@ flush
Align the text naturally based on the writing direction of each paragraph.
Definition alignment.hpp:112
@ justified
Stretch the text to be flush to both sides.
Definition alignment.hpp:130
@ center
Align the text in the center.
Definition alignment.hpp:124
The HikoGUI namespace.
Definition array_generic.hpp:21
The HikoGUI API version 1.
Definition array_generic.hpp:22
hi_export constexpr std::string token_location(It &it, ItEnd last, std::string_view path) noexcept
Create a location string for error messages.
Definition token.hpp:163
@ color
A color value was modified.
Definition style_modify_mask.hpp:27
@ margin
A margin or padding value was modified.
Definition style_modify_mask.hpp:39
auto make_lookahead_iterator(It first, ItEnd last=std::default_sentinel) noexcept
Create a lookahead_iterator from a forward iterator.
Definition lookahead_iterator.hpp:227
static color * find(std::string const &name) noexcept
Find a color by name.
Definition color_intf.hpp:298
Definition expected_optional.hpp:18