Skip to content

Instantly share code, notes, and snippets.

@linkdd
Created July 30, 2025 02:19
Show Gist options
  • Save linkdd/03389d8907c0cef7d07f551865b54d8f to your computer and use it in GitHub Desktop.
Save linkdd/03389d8907c0cef7d07f551865b54d8f to your computer and use it in GitHub Desktop.
Clay Style Sheet (CSS)

See

What is this?

I made a parser for a CSS dialect (with far less features) to style my C++ game UI (which is made with Clay).

Why? Well, plenty of reasons why not, so I'll just say:

  • for the fun
  • because maintaining the UI style in C++ was a pain
  • for the FUN

Should you do this? Absolutely not.

element#root {
layout-sizing-width: grow(0, 0);
layout-sizing-height: grow(0, 0);
layout-direction: left-to-right;
image: 'textures/backgrounds/main-menu.png';
background-color: rgba(0, 0, 0, 255);
}
element#gap {
layout-sizing-width: 5%;
layout-sizing-height: grow(0, 0);
}
element#menu {
layout-sizing-width: 15%;
layout-sizing-height: grow(0, 0);
layout-direction: top-to-bottom;
layout-padding: 16;
layout-child-gap: 24;
background-color: rgba(16, 16, 16, 196);
border-width: outside(2);
border-color: rgba(96, 96, 96, 255);
}
element#container {
layout-sizing-width: grow(0, 0);
layout-sizing-height: grow(0, 0);
layout-padding: 64;
}
element#window {
layout-sizing-width: 100%;
layout-sizing-height: grow(0, 0);
layout-direction: top-to-bottom;
layout-padding: 16;
layout-child-gap: 16;
background-color: rgba(16, 16, 16, 196);
border-width: outside(2);
border-color: rgba(96, 96, 96, 255);
}
element#form {
layout-sizing-width: grow(0, 0);
layout-sizing-height: grow(0, 0);
layout-direction: top-to-bottom;
layout-child-alignment-x: center;
layout-child-alignment-y: top;
layout-padding: 8;
layout-child-gap: 8;
}
element#form-field {
layout-sizing-width: grow(0, 0);
layout-sizing-height: fit(0, 0);
layout-direction: left-to-right;
layout-child-alignment-x: left;
layout-child-alignment-y: center;
layout-padding: 8;
layout-child-gap: 8;
}
text#form-field-label {
font-face: 'fonts/Unitblock.ttf';
font-size: 18;
color: rgba(255, 193, 140, 255);
}
text#form-field-error {
font-face: 'fonts/Unitblock.ttf';
font-size: 18;
color: rgba(218, 109, 66, 255);
}
input#form-field-control {
&.container {
layout-sizing-width: grow(0, 0);
layout-sizing-height: 36;
layout-child-alignment-x: left;
layout-child-alignment-y: center;
layout-padding: 8;
background-color: rgba(16, 16, 16, 255);
border-width: outside(2);
border-color: rgba(96, 96, 96, 255);
&:hover {
border-color: rgba(132, 36, 12, 255);
}
&:active {
border-color: rgba(218, 109, 66, 255);
}
}
&.content {
font-face: 'fonts/Unitblock.ttf';
font-size: 18;
color: rgba(204, 204, 204, 255);
}
}
element#form-button-group {
layout-sizing-width: grow(0, 0);
layout-sizing-height: fit(0, 0);
layout-direction: left-to-right;
layout-child-alignment-x: center;
layout-child-alignment-y: center;
layout-padding: 8;
layout-child-gap: 64;
}
button#primary {
&.container {
layout-sizing-width: grow(0, 0);
layout-sizing-height: 48;
layout-child-alignment-x: center;
layout-child-alignment-y: center;
background-color: rgba(86, 50, 50, 255);
&:hover {
background-color: rgba(132, 36, 12, 255);
}
&:active {
background-color: rgba(218, 109, 66, 255);
}
}
&.label {
font-face: 'fonts/Unitblock.ttf';
font-size: 24;
color: rgba(255, 193, 140, 255);
}
}
element#separator {
layout-sizing-width: grow(0, 0);
layout-sizing-height: grow(0, 0);
}
#include <lexy/action/parse.hpp>
#include <lexy/input/string_input.hpp>
#include <lexy_ext/report_error.hpp>
#include <engine/ui/styles/parser.hpp>
namespace engine::ui::styles::parser {
stylesheet eval(manager& ui_manager, const std::string& source) {
auto input = lexy::string_input(source);
auto result = lexy::parse<document>(input, ui_manager, lexy_ext::report_error);
if (result.has_value()) {
return result.value();
}
else {
throw std::runtime_error{"Failed to parse stylesheet"};
}
}
}
#pragma once
#include <cstdint>
#include <sstream>
#include <string>
#include <filesystem>
#include <utility>
#include <functional>
#include <vector>
#include <lexy/dsl.hpp>
#include <lexy/callback.hpp>
#include <clay.h>
#include <engine/ui/styles/types.hpp>
#include <engine/ui/manager.hpp>
namespace engine::ui::styles::parser {
namespace dsl = lexy::dsl;
namespace basic {
// MARK: identifier
struct identifier {
static constexpr auto rule = dsl::identifier(
dsl::ascii::alpha,
dsl::ascii::alpha_digit_underscore / dsl::lit_c<'-'>
);
static constexpr auto value = lexy::as_string<std::string>;
};
// MARK: boolean
struct boolean {
struct true_ {
static constexpr auto rule = LEXY_LIT("true");
static constexpr auto value = lexy::constant(true);
};
struct false_ {
static constexpr auto rule = LEXY_LIT("false");
static constexpr auto value = lexy::constant(false);
};
static constexpr auto rule = dsl::p<true_> | dsl::p<false_>;
static constexpr auto value = lexy::forward<bool>;
};
// MARK: float
struct float_ {
static constexpr auto rule
= dsl::sign
+ dsl::integer<int>
+ dsl::opt(dsl::lit_c<'.'> >> dsl::integer<int>)
;
static constexpr auto value = lexy::callback<float>(
[](lexy::minus_sign, int i, int d) -> float {
auto result = 0.0f;
auto oss = std::ostringstream{};
oss << "-" << i << "." << d;
auto iss = std::istringstream{oss.str()};
iss >> result;
return result;
},
[](lexy::minus_sign, int i, lexy::nullopt) -> float {
return -static_cast<float>(i);
},
[](lexy::plus_sign, int i, int d) -> float {
auto result = 0.0f;
auto oss = std::ostringstream{};
oss << i << "." << d;
auto iss = std::istringstream{oss.str()};
iss >> result;
return result;
},
[](lexy::plus_sign, int i, lexy::nullopt) -> float {
return static_cast<float>(i);
},
[](int i, int d) -> float {
auto result = 0.0f;
auto oss = std::ostringstream{};
oss << i << "." << d;
auto iss = std::istringstream{oss.str()};
iss >> result;
return result;
},
[](int i, lexy::nullopt) -> float {
return static_cast<float>(i);
}
);
};
// MARK: color
struct color {
static constexpr auto rule
= LEXY_LIT("rgba")
+ dsl::parenthesized(dsl::times<4>(dsl::p<float_>, dsl::sep(dsl::comma)))
;
static constexpr auto value = lexy::construct<Clay_Color>;
};
// MARK: str
struct str {
static constexpr auto rule = dsl::single_quoted(dsl::ascii::print);
static constexpr auto value = lexy::as_string<std::string>;
};
}
namespace property_set {
template <typename T>
struct as_property {
struct _property_value {
static constexpr auto rule = T::property_value_rule;
static constexpr auto value = T::property_value_eval;
};
static constexpr auto rule
= T::property_name_rule
>> dsl::lit_c<':'>
>> dsl::p<_property_value>
>> dsl::lit_c<';'>
;
using property_value_type = std::pair<T, typename T::property_value_type>;
static constexpr auto value = lexy::callback<property_value_type>(
[](typename T::property_value_type value) {
return std::make_pair(T{}, value);
}
);
};
// MARK: elt props
struct element_properties {
struct _layout_sizing_axis {
using property_value_type = Clay_SizingAxis;
struct fit_value {
static constexpr auto rule
= LEXY_LIT("fit")
>> dsl::parenthesized(dsl::times<2>(dsl::p<basic::float_>, dsl::sep(dsl::comma)))
;
static constexpr auto value = lexy::callback<property_value_type>(
[](float min, float max) {
return CLAY_SIZING_FIT(min, max);
}
);
};
struct grow_value {
static constexpr auto rule
= LEXY_LIT("grow")
>> dsl::parenthesized(dsl::times<2>(dsl::p<basic::float_>, dsl::sep(dsl::comma)))
;
static constexpr auto value = lexy::callback<property_value_type>(
[](float min, float max) {
return CLAY_SIZING_GROW(min, max);
}
);
};
struct percent_value {
static constexpr auto rule
= dsl::p<basic::float_>
+ LEXY_LIT("%")
;
static constexpr auto value = lexy::callback<property_value_type>(
[](float percent) {
return CLAY_SIZING_PERCENT(percent / 100.0f);
}
);
};
struct fixed_value {
static constexpr auto rule = dsl::p<basic::float_>;
static constexpr auto value = lexy::callback<property_value_type>(
[](float size) {
return CLAY_SIZING_FIXED(size);
}
);
};
static constexpr auto property_value_rule
= dsl::p<fit_value>
| dsl::p<grow_value>
| dsl::peek(dsl::p<percent_value>) >> dsl::p<percent_value>
| dsl::peek(dsl::p<fixed_value>) >> dsl::p<fixed_value>
;
static constexpr auto property_value_eval
= lexy::forward<property_value_type>;
};
struct layout_sizing_width : public _layout_sizing_axis {
static constexpr auto property_name_rule = LEXY_LIT("layout-sizing-width");
};
using prop_layout_sizing_width = as_property<layout_sizing_width>;
struct layout_sizing_height : public _layout_sizing_axis {
static constexpr auto property_name_rule = LEXY_LIT("layout-sizing-height");
};
using prop_layout_sizing_height = as_property<layout_sizing_height>;
struct layout_padding {
using property_value_type = Clay_Padding;
static constexpr auto property_name_rule = LEXY_LIT("layout-padding");
static constexpr auto property_value_rule = dsl::integer<uint16_t>;
static constexpr auto property_value_eval
= lexy::callback<property_value_type>([](uint16_t padding) {
return CLAY_PADDING_ALL(padding);
});
};
using prop_layout_padding = as_property<layout_padding>;
struct layout_padding_left {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("layout-padding-left");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_padding_left = as_property<layout_padding_left>;
struct layout_padding_right {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("layout-padding-right");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_padding_right = as_property<layout_padding_right>;
struct layout_padding_top {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("layout-padding-top");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_padding_top = as_property<layout_padding_top>;
struct layout_padding_bottom {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("layout-padding-bottom");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_padding_bottom = as_property<layout_padding_bottom>;
struct layout_child_gap {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("layout-child-gap");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_child_gap = as_property<layout_child_gap>;
struct layout_child_alignment_x {
using property_value_type = Clay_LayoutAlignmentX;
struct left_value {
static constexpr auto rule = LEXY_LIT("left");
static constexpr auto value = lexy::constant(CLAY_ALIGN_X_LEFT);
};
struct center_value {
static constexpr auto rule = LEXY_LIT("center");
static constexpr auto value = lexy::constant(CLAY_ALIGN_X_CENTER);
};
struct right_value {
static constexpr auto rule = LEXY_LIT("right");
static constexpr auto value = lexy::constant(CLAY_ALIGN_X_RIGHT);
};
static constexpr auto property_name_rule = LEXY_LIT("layout-child-alignment-x");
static constexpr auto property_value_rule
= dsl::p<left_value>
| dsl::p<center_value>
| dsl::p<right_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_child_alignment_x = as_property<layout_child_alignment_x>;
struct layout_child_alignment_y {
using property_value_type = Clay_LayoutAlignmentY;
struct top_value {
static constexpr auto rule = LEXY_LIT("top");
static constexpr auto value = lexy::constant(CLAY_ALIGN_Y_TOP);
};
struct center_value {
static constexpr auto rule = LEXY_LIT("center");
static constexpr auto value = lexy::constant(CLAY_ALIGN_Y_CENTER);
};
struct bottom_value {
static constexpr auto rule = LEXY_LIT("bottom");
static constexpr auto value = lexy::constant(CLAY_ALIGN_Y_BOTTOM);
};
static constexpr auto property_name_rule = LEXY_LIT("layout-child-alignment-y");
static constexpr auto property_value_rule
= dsl::p<top_value>
| dsl::p<center_value>
| dsl::p<bottom_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_child_alignment_y = as_property<layout_child_alignment_y>;
struct layout_direction {
using property_value_type = Clay_LayoutDirection;
struct left_to_right_value {
static constexpr auto rule = LEXY_LIT("left-to-right");
static constexpr auto value = lexy::constant(CLAY_LEFT_TO_RIGHT);
};
struct top_to_bottom_value {
static constexpr auto rule = LEXY_LIT("top-to-bottom");
static constexpr auto value = lexy::constant(CLAY_TOP_TO_BOTTOM);
};
static constexpr auto property_name_rule = LEXY_LIT("layout-direction");
static constexpr auto property_value_rule
= dsl::p<left_to_right_value>
| dsl::p<top_to_bottom_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_layout_direction = as_property<layout_direction>;
struct background_color {
using property_value_type = Clay_Color;
static constexpr auto property_name_rule = LEXY_LIT("background-color");
static constexpr auto property_value_rule = dsl::p<basic::color>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_background_color = as_property<background_color>;
struct corner_radius {
using property_value_type = Clay_CornerRadius;
static constexpr auto property_name_rule = LEXY_LIT("corner-radius");
static constexpr auto property_value_rule = dsl::times<4>(dsl::p<basic::float_>);
static constexpr auto property_value_eval = lexy::construct<property_value_type>;
};
using prop_corner_radius = as_property<corner_radius>;
struct corner_radius_top_left {
using property_value_type = float;
static constexpr auto property_name_rule = LEXY_LIT("corner-radius-top-left");
static constexpr auto property_value_rule = dsl::p<basic::float_>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_corner_radius_top_left = as_property<corner_radius_top_left>;
struct corner_radius_top_right {
using property_value_type = float;
static constexpr auto property_name_rule = LEXY_LIT("corner-radius-top-right");
static constexpr auto property_value_rule = dsl::p<basic::float_>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_corner_radius_top_right = as_property<corner_radius_top_right>;
struct corner_radius_bottom_left {
using property_value_type = float;
static constexpr auto property_name_rule = LEXY_LIT("corner-radius-bottom-left");
static constexpr auto property_value_rule = dsl::p<basic::float_>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_corner_radius_bottom_left = as_property<corner_radius_bottom_left>;
struct corner_radius_bottom_right {
using property_value_type = float;
static constexpr auto property_name_rule = LEXY_LIT("corner-radius-bottom-right");
static constexpr auto property_value_rule = dsl::p<basic::float_>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_corner_radius_bottom_right = as_property<corner_radius_bottom_right>;
struct aspect_ratio {
using property_value_type = Clay_AspectRatioElementConfig;
static constexpr auto property_name_rule = LEXY_LIT("aspect-ratio");
static constexpr auto property_value_rule = dsl::p<basic::float_>;
static constexpr auto property_value_eval = lexy::construct<property_value_type>;
};
using prop_aspect_ratio = as_property<aspect_ratio>;
struct image {
using property_value_type = std::filesystem::path;
static constexpr auto property_name_rule = LEXY_LIT("image");
static constexpr auto property_value_rule = dsl::p<basic::str>;
static constexpr auto property_value_eval = lexy::construct<property_value_type>;
};
using prop_image = as_property<image>;
struct floating_offset {
using property_value_type = Clay_Vector2;
static constexpr auto property_name_rule = LEXY_LIT("floating-offset");
static constexpr auto property_value_rule = dsl::times<2>(dsl::p<basic::float_>);
static constexpr auto property_value_eval = lexy::construct<property_value_type>;
};
using prop_floating_offset = as_property<floating_offset>;
struct floating_expand {
using property_value_type = Clay_Dimensions;
static constexpr auto property_name_rule = LEXY_LIT("floating-expand");
static constexpr auto property_value_rule = dsl::times<2>(dsl::p<basic::float_>);
static constexpr auto property_value_eval = lexy::construct<property_value_type>;
};
using prop_floating_expand = as_property<floating_expand>;
struct floating_zindex {
using property_value_type = int16_t;
static constexpr auto property_name_rule = LEXY_LIT("floating-zindex");
static constexpr auto property_value_rule = dsl::integer<int16_t>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_floating_zindex = as_property<floating_zindex>;
struct _floating_attach_point_type {
using property_value_type = Clay_FloatingAttachPointType;
struct left_top_value {
static constexpr auto rule = LEXY_LIT("left-top");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_LEFT_TOP);
};
struct left_center_value {
static constexpr auto rule = LEXY_LIT("left-center");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_LEFT_CENTER);
};
struct left_bottom_value {
static constexpr auto rule = LEXY_LIT("left-bottom");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_LEFT_BOTTOM);
};
struct center_top_value {
static constexpr auto rule = LEXY_LIT("center-top");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_CENTER_TOP);
};
struct center_center_value {
static constexpr auto rule = LEXY_LIT("center-center");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_CENTER_CENTER);
};
struct center_bottom_value {
static constexpr auto rule = LEXY_LIT("center-bottom");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_CENTER_BOTTOM);
};
struct right_top_value {
static constexpr auto rule = LEXY_LIT("right-top");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_RIGHT_TOP);
};
struct right_center_value {
static constexpr auto rule = LEXY_LIT("right-center");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_RIGHT_CENTER);
};
struct right_bottom_value {
static constexpr auto rule = LEXY_LIT("right-bottom");
static constexpr auto value = lexy::constant(CLAY_ATTACH_POINT_RIGHT_BOTTOM);
};
static constexpr auto property_value_rule
= dsl::p<left_top_value>
| dsl::p<left_center_value>
| dsl::p<left_bottom_value>
| dsl::p<center_top_value>
| dsl::p<center_center_value>
| dsl::p<center_bottom_value>
| dsl::p<right_top_value>
| dsl::p<right_center_value>
| dsl::p<right_bottom_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
struct floating_attach_point_element : public _floating_attach_point_type {
static constexpr auto property_name_rule = LEXY_LIT("floating-attach-point-element");
};
using prop_floating_attach_point_element = as_property<floating_attach_point_element>;
struct floating_attach_point_parent : public _floating_attach_point_type {
static constexpr auto property_name_rule = LEXY_LIT("floating-attach-point-parent");
};
using prop_floating_attach_point_parent = as_property<floating_attach_point_parent>;
struct floating_pointer_capture_mode {
using property_value_type = Clay_PointerCaptureMode;
struct capture_value {
static constexpr auto rule = LEXY_LIT("capture");
static constexpr auto value = lexy::constant(CLAY_POINTER_CAPTURE_MODE_CAPTURE);
};
struct passthrough_value {
static constexpr auto rule = LEXY_LIT("passthrough");
static constexpr auto value = lexy::constant(CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH);
};
static constexpr auto property_name_rule = LEXY_LIT("floating-pointer-capture-mode");
static constexpr auto property_value_rule
= dsl::p<capture_value>
| dsl::p<passthrough_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_floating_pointer_capture_mode = as_property<floating_pointer_capture_mode>;
struct floating_attach_to {
using property_value_type = Clay_FloatingAttachToElement;
struct none_value {
static constexpr auto rule = LEXY_LIT("none");
static constexpr auto value = lexy::constant(CLAY_ATTACH_TO_NONE);
};
struct parent_value {
static constexpr auto rule = LEXY_LIT("parent");
static constexpr auto value = lexy::constant(CLAY_ATTACH_TO_PARENT);
};
struct element_value {
static constexpr auto rule = LEXY_LIT("element");
static constexpr auto value = lexy::constant(CLAY_ATTACH_TO_ELEMENT_WITH_ID);
};
struct root_value {
static constexpr auto rule = LEXY_LIT("root");
static constexpr auto value = lexy::constant(CLAY_ATTACH_TO_ROOT);
};
static constexpr auto property_name_rule = LEXY_LIT("floating-attach-to");
static constexpr auto property_value_rule
= dsl::p<none_value>
| dsl::p<parent_value>
| dsl::p<element_value>
| dsl::p<root_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_floating_attach_to = as_property<floating_attach_to>;
struct floating_clip_to {
using property_value_type = Clay_FloatingClipToElement;
struct none_value {
static constexpr auto rule = LEXY_LIT("none");
static constexpr auto value = lexy::constant(CLAY_CLIP_TO_NONE);
};
struct parent_value {
static constexpr auto rule = LEXY_LIT("parent");
static constexpr auto value = lexy::constant(CLAY_CLIP_TO_ATTACHED_PARENT);
};
static constexpr auto property_name_rule = LEXY_LIT("floating-clip-to");
static constexpr auto property_value_rule
= dsl::p<none_value>
| dsl::p<parent_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_floating_clip_to = as_property<floating_clip_to>;
struct clip_horizontal {
using property_value_type = bool;
static constexpr auto property_name_rule = LEXY_LIT("clip-horizontal");
static constexpr auto property_value_rule = dsl::p<basic::boolean>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_clip_horizontal = as_property<clip_horizontal>;
struct clip_vertical {
using property_value_type = bool;
static constexpr auto property_name_rule = LEXY_LIT("clip-vertical");
static constexpr auto property_value_rule = dsl::p<basic::boolean>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_clip_vertical = as_property<clip_vertical>;
struct clip_child_offset {
using property_value_type = Clay_Vector2;
static constexpr auto property_name_rule = LEXY_LIT("clip-child-offset");
static constexpr auto property_value_rule = dsl::times<2>(dsl::p<basic::float_>);
static constexpr auto property_value_eval = lexy::construct<property_value_type>;
};
using prop_clip_child_offset = as_property<clip_child_offset>;
struct border_color {
using property_value_type = Clay_Color;
static constexpr auto property_name_rule = LEXY_LIT("border-color");
static constexpr auto property_value_rule = dsl::p<basic::color>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_border_color = as_property<border_color>;
struct border_width {
using property_value_type = Clay_BorderWidth;
struct outside_value {
static constexpr auto rule
= LEXY_LIT("outside")
+ dsl::parenthesized(dsl::integer<uint16_t>)
;
static constexpr auto value = lexy::callback<property_value_type>(
[](uint16_t width) -> property_value_type {
return CLAY_BORDER_OUTSIDE(width);
}
);
};
struct all_value {
static constexpr auto rule
= LEXY_LIT("all")
+ dsl::parenthesized(dsl::integer<uint16_t>)
;
static constexpr auto value = lexy::callback<property_value_type>(
[](uint16_t width) -> property_value_type {
return CLAY_BORDER_ALL(width);
}
);
};
static constexpr auto property_name_rule = LEXY_LIT("border-width");
static constexpr auto property_value_rule
= dsl::peek(dsl::p<outside_value>) >> dsl::p<outside_value>
| dsl::peek(dsl::p<all_value>) >> dsl::p<all_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_border_width = as_property<border_width>;
struct border_width_left {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("border-width-left");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_border_width_left = as_property<border_width_left>;
struct border_width_right {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("border-width-right");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_border_width_right = as_property<border_width_right>;
struct border_width_top {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("border-width-top");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_border_width_top = as_property<border_width_top>;
struct border_width_bottom {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("border-width-bottom");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_border_width_bottom = as_property<border_width_bottom>;
struct border_width_between_children {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("border-width-between-children");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_border_width_between_children = as_property<border_width_between_children>;
static constexpr auto rule = dsl::partial_combination(
dsl::p<prop_layout_sizing_width>,
dsl::p<prop_layout_sizing_height>,
dsl::p<prop_layout_padding>,
dsl::p<prop_layout_padding_left>,
dsl::p<prop_layout_padding_right>,
dsl::p<prop_layout_padding_top>,
dsl::p<prop_layout_padding_bottom>,
dsl::p<prop_layout_child_gap>,
dsl::p<prop_layout_child_alignment_x>,
dsl::p<prop_layout_child_alignment_y>,
dsl::p<prop_layout_direction>,
dsl::p<prop_background_color>,
dsl::p<prop_corner_radius>,
dsl::p<prop_corner_radius_top_left>,
dsl::p<prop_corner_radius_top_right>,
dsl::p<prop_corner_radius_bottom_left>,
dsl::p<prop_corner_radius_bottom_right>,
dsl::p<prop_aspect_ratio>,
dsl::p<prop_image>,
dsl::p<prop_floating_offset>,
dsl::p<prop_floating_expand>,
dsl::p<prop_floating_zindex>,
dsl::p<prop_floating_attach_point_element>,
dsl::p<prop_floating_attach_point_parent>,
dsl::p<prop_floating_pointer_capture_mode>,
dsl::p<prop_floating_attach_to>,
dsl::p<prop_floating_clip_to>,
dsl::p<prop_clip_horizontal>,
dsl::p<prop_clip_vertical>,
dsl::p<prop_clip_child_offset>,
dsl::p<prop_border_color>,
dsl::p<prop_border_width>,
dsl::p<prop_border_width_left>,
dsl::p<prop_border_width_right>,
dsl::p<prop_border_width_top>,
dsl::p<prop_border_width_bottom>,
dsl::p<prop_border_width_between_children>
);
using property_setter = std::function<void(manager&, element_style&)>;
using property_setters = std::vector<property_setter>;
static constexpr auto value = lexy::fold_inplace<property_setters>(
property_setters{},
[](property_setters& setters, prop_layout_sizing_width::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.sizing.width = value;
});
},
[](property_setters& setters, prop_layout_sizing_height::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.sizing.height = value;
});
},
[](property_setters& setters, prop_layout_padding::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.padding = value;
});
},
[](property_setters& setters, prop_layout_padding_left::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.padding.left = value;
});
},
[](property_setters& setters, prop_layout_padding_right::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.padding.right = value;
});
},
[](property_setters& setters, prop_layout_padding_top::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.padding.top = value;
});
},
[](property_setters& setters, prop_layout_padding_bottom::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.padding.bottom = value;
});
},
[](property_setters& setters, prop_layout_child_gap::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.childGap = value;
});
},
[](property_setters& setters, prop_layout_child_alignment_x::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.childAlignment.x = value;
});
},
[](property_setters& setters, prop_layout_child_alignment_y::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.childAlignment.y = value;
});
},
[](property_setters& setters, prop_layout_direction::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.layout.layoutDirection = value;
});
},
[](property_setters& setters, prop_background_color::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.backgroundColor = value;
});
},
[](property_setters& setters, prop_corner_radius::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.cornerRadius = value;
});
},
[](property_setters& setters, prop_corner_radius_top_left::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.cornerRadius.topLeft = value;
});
},
[](property_setters& setters, prop_corner_radius_top_right::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.cornerRadius.topRight = value;
});
},
[](property_setters& setters, prop_corner_radius_bottom_left::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.cornerRadius.bottomLeft = value;
});
},
[](property_setters& setters, prop_corner_radius_bottom_right::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.cornerRadius.bottomRight = value;
});
},
[](property_setters& setters, prop_aspect_ratio::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.aspectRatio = value;
});
},
[](property_setters& setters, prop_image::property_value_type property) {
setters.push_back([property](manager& ui_manager, element_style& decl) {
auto [_, value] = property;
auto texture_id = ui_manager.add_texture_to_atlas(value);
decl.image.imageData = reinterpret_cast<void*>(static_cast<intptr_t>(texture_id));
});
},
[](property_setters& setters, prop_floating_offset::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.offset = value;
});
},
[](property_setters& setters, prop_floating_expand::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.expand = value;
});
},
[](property_setters& setters, prop_floating_zindex::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.zIndex = value;
});
},
[](property_setters& setters, prop_floating_attach_point_element::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.attachPoints.element = value;
});
},
[](property_setters& setters, prop_floating_attach_point_parent::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.attachPoints.parent = value;
});
},
[](property_setters& setters, prop_floating_pointer_capture_mode::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.pointerCaptureMode = value;
});
},
[](property_setters& setters, prop_floating_attach_to::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.attachTo = value;
});
},
[](property_setters& setters, prop_floating_clip_to::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.floating.clipTo = value;
});
},
[](property_setters& setters, prop_clip_horizontal::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.clip.horizontal = value;
});
},
[](property_setters& setters, prop_clip_vertical::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.clip.vertical = value;
});
},
[](property_setters& setters, prop_clip_child_offset::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.clip.childOffset = value;
});
},
[](property_setters& setters, prop_border_color::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.border.color = value;
});
},
[](property_setters& setters, prop_border_width::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.border.width = value;
});
},
[](property_setters& setters, prop_border_width_left::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.border.width.left = value;
});
},
[](property_setters& setters, prop_border_width_right::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.border.width.right = value;
});
},
[](property_setters& setters, prop_border_width_top::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.border.width.top = value;
});
},
[](property_setters& setters, prop_border_width_bottom::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.border.width.bottom = value;
});
},
[](property_setters& setters, prop_border_width_between_children::property_value_type property) {
setters.push_back([property](manager&, element_style& decl) {
auto [_, value] = property;
decl.border.width.betweenChildren = value;
});
}
);
};
// MARK: txt props
struct text_properties {
struct color {
using property_value_type = Clay_Color;
static constexpr auto property_name_rule = LEXY_LIT("color");
static constexpr auto property_value_rule = dsl::p<basic::color>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_color = as_property<color>;
struct font_face {
using property_value_type = std::filesystem::path;
static constexpr auto property_name_rule = LEXY_LIT("font-face");
static constexpr auto property_value_rule = dsl::p<basic::str>;
static constexpr auto property_value_eval = lexy::construct<property_value_type>;
};
using prop_font_face = as_property<font_face>;
struct font_size {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("font-size");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_font_size = as_property<font_size>;
struct letter_spacing {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("letter-spacing");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_letter_spacing = as_property<letter_spacing>;
struct line_height {
using property_value_type = uint16_t;
static constexpr auto property_name_rule = LEXY_LIT("line-height");
static constexpr auto property_value_rule = dsl::integer<property_value_type>;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_line_height = as_property<line_height>;
struct wrap_mode {
using property_value_type = Clay_TextElementConfigWrapMode;
struct words_value {
static constexpr auto rule = LEXY_LIT("words");
static constexpr auto value = lexy::constant(CLAY_TEXT_WRAP_WORDS);
};
struct newlines_value {
static constexpr auto rule = LEXY_LIT("newlines");
static constexpr auto value = lexy::constant(CLAY_TEXT_WRAP_NEWLINES);
};
struct none_value {
static constexpr auto rule = LEXY_LIT("none");
static constexpr auto value = lexy::constant(CLAY_TEXT_WRAP_NONE);
};
static constexpr auto property_name_rule = LEXY_LIT("wrap-mode");
static constexpr auto property_value_rule
= dsl::p<words_value>
| dsl::p<newlines_value>
| dsl::p<none_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_wrap_mode = as_property<wrap_mode>;
struct alignment {
using property_value_type = Clay_TextAlignment;
struct left_value {
static constexpr auto rule = LEXY_LIT("left");
static constexpr auto value = lexy::constant(CLAY_TEXT_ALIGN_LEFT);
};
struct center_value {
static constexpr auto rule = LEXY_LIT("center");
static constexpr auto value = lexy::constant(CLAY_TEXT_ALIGN_CENTER);
};
struct right_value {
static constexpr auto rule = LEXY_LIT("right");
static constexpr auto value = lexy::constant(CLAY_TEXT_ALIGN_RIGHT);
};
static constexpr auto property_name_rule = LEXY_LIT("alignment");
static constexpr auto property_value_rule
= dsl::p<left_value>
| dsl::p<center_value>
| dsl::p<right_value>
;
static constexpr auto property_value_eval = lexy::forward<property_value_type>;
};
using prop_alignment = as_property<alignment>;
static constexpr auto rule = dsl::partial_combination(
dsl::p<prop_color>,
dsl::p<prop_font_face>,
dsl::p<prop_font_size>,
dsl::p<prop_letter_spacing>,
dsl::p<prop_line_height>,
dsl::p<prop_wrap_mode>,
dsl::p<prop_alignment>
);
using property_setter = std::function<void(manager&, text_style&)>;
using property_setters = std::vector<property_setter>;
static constexpr auto value = lexy::fold_inplace<property_setters>(
property_setters{},
[](property_setters& setters, prop_color::property_value_type property) {
setters.push_back([property](manager&, text_style& config) {
auto [_, value] = property;
config.textColor = value;
});
},
[](property_setters& setters, prop_font_face::property_value_type property) {
setters.push_back([property](manager& manager, text_style& config) {
auto [_, value] = property;
auto font_id = manager.add_font_to_atlas(value);
config.fontId = font_id;
});
},
[](property_setters& setters, prop_font_size::property_value_type property) {
setters.push_back([property](manager&, text_style& config) {
auto [_, value] = property;
config.fontSize = value;
});
},
[](property_setters& setters, prop_letter_spacing::property_value_type property) {
setters.push_back([property](manager&, text_style& config) {
auto [_, value] = property;
config.letterSpacing = value;
});
},
[](property_setters& setters, prop_line_height::property_value_type property) {
setters.push_back([property](manager&, text_style& config) {
auto [_, value] = property;
config.lineHeight = value;
});
},
[](property_setters& setters, prop_wrap_mode::property_value_type property) {
setters.push_back([property](manager&, text_style& config) {
auto [_, value] = property;
config.wrapMode = value;
});
},
[](property_setters& setters, prop_alignment::property_value_type property) {
setters.push_back([property](manager&, text_style& config) {
auto [_, value] = property;
config.textAlignment = value;
});
}
) >> lexy::forward<property_setters>;
};
// MARK: elt props state
struct container_properties_with_state {
static constexpr auto rule
= dsl::p<property_set::element_properties>
+ dsl::opt(dsl::lit_c<'&'> >> dsl::lit_c<':'> >> LEXY_LIT("hover") >> dsl::curly_bracketed(dsl::p<property_set::element_properties>))
+ dsl::opt(dsl::lit_c<'&'> >> dsl::lit_c<':'> >> LEXY_LIT("active") >> dsl::curly_bracketed(dsl::p<property_set::element_properties>))
;
static constexpr auto value = lexy::callback_with_state<container_style_with_state>(
[](
manager& ui_manager,
property_set::element_properties::property_setters normal_setters,
lexy::nullopt,
lexy::nullopt
) {
auto style = container_style_with_state{};
for (auto& setter : normal_setters) {
setter(ui_manager, style.normal);
}
style.hovered = style.normal;
style.active = style.normal;
return style;
},
[](
manager& ui_manager,
property_set::element_properties::property_setters normal_setters,
property_set::element_properties::property_setters hovered_setters,
lexy::nullopt
) {
auto style = container_style_with_state{};
for (auto& setter : normal_setters) {
setter(ui_manager, style.normal);
}
style.hovered = style.normal;
style.active = style.normal;
for (auto& setter : hovered_setters) {
setter(ui_manager, style.hovered);
}
return style;
},
[](
manager& ui_manager,
property_set::element_properties::property_setters normal_setters,
lexy::nullopt,
property_set::element_properties::property_setters active_setters
) {
auto style = container_style_with_state{};
for (auto& setter : normal_setters) {
setter(ui_manager, style.normal);
}
style.hovered = style.normal;
style.active = style.normal;
for (auto& setter : active_setters) {
setter(ui_manager, style.active);
}
return style;
},
[](
manager& ui_manager,
property_set::element_properties::property_setters normal_setters,
property_set::element_properties::property_setters hovered_setters,
property_set::element_properties::property_setters active_setters
) {
auto style = container_style_with_state{};
for (auto& setter : normal_setters) {
setter(ui_manager, style.normal);
}
style.hovered = style.normal;
style.active = style.normal;
for (auto& setter : hovered_setters) {
setter(ui_manager, style.hovered);
}
for (auto& setter : active_setters) {
setter(ui_manager, style.active);
}
return style;
}
);
};
// MARK: txt props state
struct text_properties_with_state {
static constexpr auto rule
= dsl::p<property_set::text_properties>
+ dsl::opt(dsl::lit_c<'&'> >> dsl::lit_c<':'> >> LEXY_LIT("hover") >> dsl::curly_bracketed(dsl::p<property_set::text_properties>))
+ dsl::opt(dsl::lit_c<'&'> >> dsl::lit_c<':'> >> LEXY_LIT("active") >> dsl::curly_bracketed(dsl::p<property_set::text_properties>))
;
static constexpr auto value = lexy::callback_with_state<text_style_with_state>(
[](
manager& ui_manager,
property_set::text_properties::property_setters normal_setters,
std::optional<property_set::text_properties::property_setters> hovered_setters,
std::optional<property_set::text_properties::property_setters> active_setters
) {
auto style = text_style_with_state{};
for (auto& setter : normal_setters) {
setter(ui_manager, style.normal);
}
style.hovered = style.normal;
style.active = style.normal;
if (hovered_setters.has_value()) {
for (auto& setter : hovered_setters.value()) {
setter(ui_manager, style.hovered);
}
}
if (active_setters.has_value()) {
for (auto& setter : active_setters.value()) {
setter(ui_manager, style.active);
}
}
return style;
}
);
};
}
namespace block {
// MARK: elt block
struct element_block {
using block_type = std::pair<std::string, element_style>;
static constexpr auto rule
= LEXY_LIT("element")
>> dsl::hash_sign
+ dsl::p<basic::identifier>
+ dsl::curly_bracketed(dsl::p<property_set::element_properties>)
;
static constexpr auto value = lexy::callback_with_state<block_type>(
[](manager& ui_manager, std::string id, property_set::element_properties::property_setters setters) {
auto style = element_style{};
for (auto& setter : setters) {
setter(ui_manager, style);
}
return block_type{id, style};
}
);
};
// MARK: txt block
struct text_block {
using block_type = std::pair<std::string, text_style>;
static constexpr auto rule
= LEXY_LIT("text")
>> dsl::hash_sign
+ dsl::p<basic::identifier>
+ dsl::curly_bracketed(dsl::p<property_set::text_properties>)
;
static constexpr auto value = lexy::callback_with_state<block_type>(
[](manager& ui_manager, std::string id, property_set::text_properties::property_setters setters) {
auto style = text_style{};
for (auto& setter : setters) {
setter(ui_manager, style);
}
return block_type{id, style};
}
);
};
// MARK: button block
struct button_block {
using block_type = std::pair<std::string, button_style>;
struct container_subblock {
static constexpr auto rule
= dsl::lit_c<'&'>
>> dsl::lit_c<'.'>
>> LEXY_LIT("container")
>> dsl::curly_bracketed(dsl::p<property_set::container_properties_with_state>)
;
static constexpr auto value = lexy::forward<container_style_with_state>;
};
struct label_subblock {
static constexpr auto rule
= dsl::lit_c<'&'>
>> dsl::lit_c<'.'>
>> LEXY_LIT("label")
>> dsl::curly_bracketed(dsl::p<property_set::text_properties_with_state>)
;
static constexpr auto value = lexy::forward<text_style_with_state>;
};
static constexpr auto rule
= LEXY_LIT("button")
>> dsl::hash_sign
+ dsl::p<basic::identifier>
+ dsl::curly_bracketed(dsl::p<container_subblock> + dsl::p<label_subblock>)
;
static constexpr auto value = lexy::callback<block_type>(
[](
std::string id,
container_style_with_state container,
text_style_with_state label
) {
return block_type{id, button_style{container, label}};
}
);
};
// MARK: input block
struct input_block {
using block_type = std::pair<std::string, input_style>;
struct container_subblock {
static constexpr auto rule
= dsl::lit_c<'&'>
>> dsl::lit_c<'.'>
>> LEXY_LIT("container")
>> dsl::curly_bracketed(dsl::p<property_set::container_properties_with_state>)
;
static constexpr auto value = lexy::forward<container_style_with_state>;
};
struct content_subblock {
static constexpr auto rule
= dsl::lit_c<'&'>
>> dsl::lit_c<'.'>
>> LEXY_LIT("content")
>> dsl::curly_bracketed(dsl::p<property_set::text_properties_with_state>)
;
static constexpr auto value = lexy::forward<text_style_with_state>;
};
static constexpr auto rule
= LEXY_LIT("input")
>> dsl::hash_sign
+ dsl::p<basic::identifier>
+ dsl::curly_bracketed(dsl::p<container_subblock> + dsl::p<content_subblock>)
;
static constexpr auto value = lexy::callback<block_type>(
[](
std::string id,
container_style_with_state container,
text_style_with_state content
) {
return block_type{id, input_style{container, content}};
}
);
};
}
// MARK: document
struct document {
using block_type = std::variant<
block::element_block::block_type,
block::text_block::block_type,
block::button_block::block_type,
block::input_block::block_type
>;
static constexpr auto whitespace = dsl::ascii::space;
static constexpr auto rule =
dsl::list(
dsl::p<block::element_block>
| dsl::p<block::text_block>
| dsl::p<block::button_block>
| dsl::p<block::input_block>
);
static constexpr auto value
= lexy::as_list<std::vector<block_type>>
>> lexy::callback<stylesheet>(
[](const std::vector<block_type>& blocks) {
auto sheet = stylesheet{};
for (auto& block : blocks) {
if (std::holds_alternative<block::element_block::block_type>(block)) {
auto [id, style] = std::get<block::element_block::block_type>(block);
sheet.elements[id] = style;
}
else if (std::holds_alternative<block::text_block::block_type>(block)) {
auto [id, style] = std::get<block::text_block::block_type>(block);
sheet.texts[id] = style;
}
else if (std::holds_alternative<block::button_block::block_type>(block)) {
auto [id, style] = std::get<block::button_block::block_type>(block);
sheet.buttons[id] = style;
}
else if (std::holds_alternative<block::input_block::block_type>(block)) {
auto [id, style] = std::get<block::input_block::block_type>(block);
sheet.inputs[id] = style;
}
}
return sheet;
}
);
};
stylesheet eval(manager& ui_manager, const std::string& source);
}
#pragma once
#include <string>
#include <unordered_map>
#include <clay.h>
namespace engine::ui {
using element_style = Clay_ElementDeclaration;
using text_style = Clay_TextElementConfig;
struct container_style_with_state {
element_style normal;
element_style hovered;
element_style active;
};
struct text_style_with_state {
text_style normal;
text_style hovered;
text_style active;
};
struct button_style {
container_style_with_state container;
text_style_with_state label;
};
struct input_style {
container_style_with_state container;
text_style_with_state content;
};
struct stylesheet {
std::unordered_map<std::string, element_style> elements;
std::unordered_map<std::string, text_style> texts;
std::unordered_map<std::string, button_style> buttons;
std::unordered_map<std::string, input_style> inputs;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment