clay_layout/
render_commands.rs

1use crate::{bindings::*, color::Color, math::BoundingBox};
2
3/// Represents a rectangle with a specified color and corner radii.
4#[derive(Debug, Clone)]
5pub struct Rectangle {
6    /// The fill color of the rectangle.
7    pub color: Color,
8    /// The corner radii for rounded edges.
9    pub corner_radii: CornerRadii,
10}
11
12/// Represents a text element with styling attributes.
13#[derive(Debug, Clone)]
14pub struct Text<'a> {
15    /// The text content.
16    pub text: &'a str,
17    /// The color of the text.
18    pub color: Color,
19    /// The ID of the font used.
20    pub font_id: u16,
21    /// The font size.
22    pub font_size: u16,
23    /// The spacing between letters.
24    pub letter_spacing: u16,
25    /// The line height.
26    pub line_height: u16,
27}
28
29/// Defines individual corner radii for an element.
30#[derive(Debug, Clone)]
31pub struct CornerRadii {
32    /// The radius for the top-left corner.
33    pub top_left: f32,
34    /// The radius for the top-right corner.
35    pub top_right: f32,
36    /// The radius for the bottom-left corner.
37    pub bottom_left: f32,
38    /// The radius for the bottom-right corner.
39    pub bottom_right: f32,
40}
41
42/// Defines the border width for each side of an element.
43#[derive(Debug, Clone)]
44pub struct BorderWidth {
45    /// Border width on the left side.
46    pub left: u16,
47    /// Border width on the right side.
48    pub right: u16,
49    /// Border width on the top side.
50    pub top: u16,
51    /// Border width on the bottom side.
52    pub bottom: u16,
53    /// Border width between child elements.
54    pub between_children: u16,
55}
56
57/// Represents a border with a specified color, width, and corner radii.
58#[derive(Debug, Clone)]
59pub struct Border {
60    /// The border color.
61    pub color: Color,
62    /// The corner radii for rounded border edges.
63    pub corner_radii: CornerRadii,
64    /// The width of the border on each side.
65    pub width: BorderWidth,
66}
67
68/// Represents an image with defined dimensions and data.
69#[derive(Debug, Clone)]
70pub struct Image<'a, ImageElementData> {
71    /// Background color
72    pub background_color: Color,
73    /// The corner radii for rounded border edges.
74    pub corner_radii: CornerRadii,
75    /// A pointer to the image data.
76    pub data: &'a ImageElementData,
77}
78
79/// Represents a custom element with a background color, corner radii, and associated data.
80#[derive(Debug, Clone)]
81pub struct Custom<'a, CustomElementData> {
82    /// The background color of the custom element.
83    pub background_color: Color,
84    /// The corner radii for rounded edges.
85    pub corner_radii: CornerRadii,
86    /// A pointer to additional custom data.
87    pub data: &'a CustomElementData,
88}
89
90impl From<Clay_RectangleRenderData> for Rectangle {
91    fn from(value: Clay_RectangleRenderData) -> Self {
92        Self {
93            color: value.backgroundColor.into(),
94            corner_radii: value.cornerRadius.into(),
95        }
96    }
97}
98
99impl From<Clay_TextRenderData> for Text<'_> {
100    fn from(value: Clay_TextRenderData) -> Self {
101        let text = unsafe {
102            core::str::from_utf8_unchecked(core::slice::from_raw_parts(
103                value.stringContents.chars as *const u8,
104                value.stringContents.length as _,
105            ))
106        };
107
108        Self {
109            text,
110            color: value.textColor.into(),
111            font_id: value.fontId,
112            font_size: value.fontSize,
113            letter_spacing: value.letterSpacing,
114            line_height: value.lineHeight,
115        }
116    }
117}
118
119impl<ImageElementData> Image<'_, ImageElementData> {
120    pub(crate) unsafe fn from_clay_image_render_data(value: Clay_ImageRenderData) -> Self {
121        Self {
122            data: unsafe { &*value.imageData.cast() },
123            corner_radii: value.cornerRadius.into(),
124            background_color: value.backgroundColor.into(),
125        }
126    }
127}
128
129impl From<Clay_CornerRadius> for CornerRadii {
130    fn from(value: Clay_CornerRadius) -> Self {
131        Self {
132            top_left: value.topLeft,
133            top_right: value.topRight,
134            bottom_left: value.bottomLeft,
135            bottom_right: value.bottomRight,
136        }
137    }
138}
139
140impl From<Clay_BorderRenderData> for Border {
141    fn from(value: Clay_BorderRenderData) -> Self {
142        Self {
143            color: value.color.into(),
144            corner_radii: value.cornerRadius.into(),
145
146            width: BorderWidth {
147                left: value.width.left,
148                right: value.width.right,
149                top: value.width.top,
150                bottom: value.width.bottom,
151                between_children: value.width.betweenChildren,
152            },
153        }
154    }
155}
156
157impl<CustomElementData> Custom<'_, CustomElementData> {
158    pub(crate) unsafe fn from_clay_custom_element_data(value: Clay_CustomRenderData) -> Self {
159        Self {
160            background_color: value.backgroundColor.into(),
161            corner_radii: value.cornerRadius.into(),
162            data: unsafe { &*value.customData.cast() },
163        }
164    }
165}
166
167#[derive(Debug, Clone)]
168pub enum RenderCommandConfig<'a, ImageElementData, CustomElementData> {
169    None(),
170    Rectangle(Rectangle),
171    Border(Border),
172    Text(Text<'a>),
173    Image(Image<'a, ImageElementData>),
174    ScissorStart(),
175    ScissorEnd(),
176    Custom(Custom<'a, CustomElementData>),
177}
178
179impl<ImageElementData, CustomElementData>
180    RenderCommandConfig<'_, ImageElementData, CustomElementData>
181{
182    #[allow(non_upper_case_globals)]
183    pub(crate) unsafe fn from_clay_render_command(value: &Clay_RenderCommand) -> Self {
184        match value.commandType {
185            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_NONE => Self::None(),
186            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_RECTANGLE => {
187                Self::Rectangle(Rectangle::from(*unsafe { &value.renderData.rectangle }))
188            }
189            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_TEXT => {
190                Self::Text(Text::from(*unsafe { &value.renderData.text }))
191            }
192            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_BORDER => {
193                Self::Border(Border::from(*unsafe { &value.renderData.border }))
194            }
195            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_IMAGE => {
196                Self::Image(unsafe { Image::from_clay_image_render_data(value.renderData.image) })
197            }
198            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_SCISSOR_START => Self::ScissorStart(),
199            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_SCISSOR_END => Self::ScissorEnd(),
200            Clay_RenderCommandType_CLAY_RENDER_COMMAND_TYPE_CUSTOM => Self::Custom(unsafe {
201                Custom::from_clay_custom_element_data(value.renderData.custom)
202            }),
203            _ => unreachable!(),
204        }
205    }
206}
207
208/// Represents a render command for drawing an element on the screen.
209#[derive(Debug, Clone)]
210pub struct RenderCommand<'a, ImageElementData, CustomElementData> {
211    /// The bounding box defining the area occupied by the element.
212    pub bounding_box: BoundingBox,
213    /// The specific configuration for rendering this command.
214    pub config: RenderCommandConfig<'a, ImageElementData, CustomElementData>,
215    /// A unique identifier for the render command.
216    pub id: u32,
217    /// The z-index determines the stacking order of elements.
218    /// Higher values are drawn above lower values.
219    pub z_index: i16,
220}
221
222impl<ImageElementData, CustomElementData> RenderCommand<'_, ImageElementData, CustomElementData> {
223    pub(crate) unsafe fn from_clay_render_command(value: Clay_RenderCommand) -> Self {
224        Self {
225            id: value.id,
226            z_index: value.zIndex,
227            bounding_box: value.boundingBox.into(),
228            config: unsafe { RenderCommandConfig::from_clay_render_command(&value) },
229        }
230    }
231}