|
#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); |
|
} |