Skip to main content

ply_engine/
elements.rs

1use crate::align::{AlignX, AlignY};
2use crate::id::Id;
3use crate::{color::Color, Vector2, engine};
4
5/// Specifies how pointer capture should behave for floating elements.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7#[repr(u8)]
8pub enum PointerCaptureMode {
9    /// Captures all pointer input.
10    #[default]
11    Capture,
12    /// Allows pointer input to pass through.
13    Passthrough,
14}
15
16/// Defines how a floating element is attached to other elements.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
18#[repr(u8)]
19pub enum FloatingAttachToElement {
20    /// The floating element is not attached to any other element.
21    #[default]
22    None,
23    /// The floating element is attached to its parent element.
24    Parent,
25    /// The floating element is attached to a specific element identified by an ID.
26    ElementWithId,
27    /// The floating element is attached to the root of the layout.
28    Root,
29}
30
31/// Defines how a floating element is clipped.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
33#[repr(u8)]
34pub enum FloatingClipToElement {
35    /// The floating element is not clipped.
36    #[default]
37    None,
38    /// The floating element is clipped to the attached parent.
39    AttachedParent,
40}
41
42/// Builder for configuring floating element properties using a closure.
43pub struct FloatingBuilder {
44    pub(crate) config: engine::FloatingConfig,
45}
46
47impl FloatingBuilder {
48    /// Sets the floating element's offset.
49    #[inline]
50    pub fn offset(&mut self, x: f32, y: f32) -> &mut Self {
51        self.config.offset = Vector2::new(x, y);
52        self
53    }
54
55    /// Sets the floating element's Z-index.
56    #[inline]
57    pub fn z_index(&mut self, z_index: i16) -> &mut Self {
58        self.config.z_index = z_index;
59        self
60    }
61
62    /// Sets the attachment points of the floating element and its parent.
63    ///
64    /// Each tuple is `(AlignX, AlignY)` — the first for the element, the second for the parent.
65    /// ```ignore
66    /// .floating(|f| f.anchor((CenterX, Bottom), (CenterX, Top)))
67    /// ```
68    #[inline]
69    pub fn anchor(
70        &mut self,
71        element: (AlignX, AlignY),
72        parent: (AlignX, AlignY),
73    ) -> &mut Self {
74        self.config.attach_points.element_x = element.0;
75        self.config.attach_points.element_y = element.1;
76        self.config.attach_points.parent_x = parent.0;
77        self.config.attach_points.parent_y = parent.1;
78        self
79    }
80
81    /// Attaches this floating element to its parent element (default behavior).
82    #[inline]
83    pub fn attach_parent(&mut self) -> &mut Self {
84        self.config.attach_to = FloatingAttachToElement::Parent;
85        self
86    }
87
88    /// Attaches this floating element to the root of the layout.
89    #[inline]
90    pub fn attach_root(&mut self) -> &mut Self {
91        self.config.attach_to = FloatingAttachToElement::Root;
92        self
93    }
94
95    /// Attaches this floating element to a specific element by ID.
96    #[inline]
97    pub fn attach_id(&mut self, id: impl Into<Id>) -> &mut Self {
98        self.config.attach_to = FloatingAttachToElement::ElementWithId;
99        self.config.parent_id = id.into().id;
100        self
101    }
102
103    /// Clips this floating element to its parent's bounds.
104    #[inline]
105    pub fn clip_by_parent(&mut self) -> &mut Self {
106        self.config.clip_to = FloatingClipToElement::AttachedParent;
107        self
108    }
109
110    /// Sets pointer capture mode to Passthrough.
111    #[inline]
112    pub fn passthrough(&mut self) -> &mut Self {
113        self.config.pointer_capture_mode = PointerCaptureMode::Passthrough;
114        self
115    }
116}
117
118/// Builder for configuring overflow (clip/scroll) properties using a closure.
119pub struct OverflowBuilder {
120    pub(crate) config: engine::ClipConfig,
121}
122
123impl OverflowBuilder {
124    /// Clips horizontal overflow without enabling scrolling.
125    #[inline]
126    pub fn clip_x(&mut self) -> &mut Self {
127        self.config.horizontal = true;
128        self
129    }
130
131    /// Clips vertical overflow without enabling scrolling.
132    #[inline]
133    pub fn clip_y(&mut self) -> &mut Self {
134        self.config.vertical = true;
135        self
136    }
137
138    /// Clips both axes without enabling scrolling.
139    #[inline]
140    pub fn clip(&mut self) -> &mut Self {
141        self.config.horizontal = true;
142        self.config.vertical = true;
143        self
144    }
145
146    /// Enables horizontal scrolling (implies clip on this axis).
147    #[inline]
148    pub fn scroll_x(&mut self) -> &mut Self {
149        self.config.horizontal = true;
150        self.config.scroll_x = true;
151        self
152    }
153
154    /// Enables vertical scrolling (implies clip on this axis).
155    #[inline]
156    pub fn scroll_y(&mut self) -> &mut Self {
157        self.config.vertical = true;
158        self.config.scroll_y = true;
159        self
160    }
161
162    /// Enables scrolling on both axes (implies clip on both axes).
163    #[inline]
164    pub fn scroll(&mut self) -> &mut Self {
165        self.config.horizontal = true;
166        self.config.vertical = true;
167        self.config.scroll_x = true;
168        self.config.scroll_y = true;
169        self
170    }
171}
172
173/// Builder for configuring border properties using a closure.
174pub struct BorderBuilder {
175    pub(crate) config: engine::BorderConfig,
176}
177
178/// Defines the position of the border relative to the bounding box.
179#[derive(Debug, Clone, Copy, Default)]
180pub enum BorderPosition {
181    /// Fully outside the bounding box.
182    #[default]
183    Outside,
184    /// Half inside, half outside the bounding box.
185    Middle,
186    /// Fully inside the bounding box.
187    Inside,
188}
189
190impl BorderBuilder {
191    /// Sets the border color.
192    #[inline]
193    pub fn color(&mut self, color: impl Into<Color>) -> &mut Self {
194        self.config.color = color.into();
195        self
196    }
197
198    /// Set the same border width for all sides.
199    #[inline]
200    pub fn all(&mut self, width: u16) -> &mut Self {
201        self.config.width.left = width;
202        self.config.width.right = width;
203        self.config.width.top = width;
204        self.config.width.bottom = width;
205        self
206    }
207
208    /// Sets the left border width.
209    #[inline]
210    pub fn left(&mut self, width: u16) -> &mut Self {
211        self.config.width.left = width;
212        self
213    }
214
215    /// Sets the right border width.
216    #[inline]
217    pub fn right(&mut self, width: u16) -> &mut Self {
218        self.config.width.right = width;
219        self
220    }
221
222    /// Sets the top border width.
223    #[inline]
224    pub fn top(&mut self, width: u16) -> &mut Self {
225        self.config.width.top = width;
226        self
227    }
228
229    /// Sets the bottom border width.
230    #[inline]
231    pub fn bottom(&mut self, width: u16) -> &mut Self {
232        self.config.width.bottom = width;
233        self
234    }
235
236    /// Sets the spacing between child elements.
237    #[inline]
238    pub fn between_children(&mut self, width: u16) -> &mut Self {
239        self.config.width.between_children = width;
240        self
241    }
242
243    /// Sets the position of the border relative to the bounding box.
244    #[inline]
245    pub fn position(&mut self, position: BorderPosition) -> &mut Self {
246        self.config.position = position;
247        self
248    }
249}
250
251/// Builder for configuring visual rotation (render-target based).
252pub struct VisualRotationBuilder {
253    pub(crate) config: engine::VisualRotationConfig,
254}
255
256impl VisualRotationBuilder {
257    /// Sets the rotation angle in degrees.
258    #[inline]
259    pub fn degrees(&mut self, degrees: f32) -> &mut Self {
260        self.config.rotation_radians = degrees.to_radians();
261        self
262    }
263
264    /// Sets the rotation angle in radians.
265    #[inline]
266    pub fn radians(&mut self, radians: f32) -> &mut Self {
267        self.config.rotation_radians = radians;
268        self
269    }
270
271    /// Sets the rotation pivot as normalized coordinates (0.0–1.0).
272    /// Default is (0.5, 0.5) = center of the element.
273    /// (0.0, 0.0) = top-left corner.
274    #[inline]
275    pub fn pivot(&mut self, x: f32, y: f32) -> &mut Self {
276        self.config.pivot_x = x;
277        self.config.pivot_y = y;
278        self
279    }
280
281    /// Flips the element horizontally (mirror across the vertical axis).
282    #[inline]
283    pub fn flip_x(&mut self) -> &mut Self {
284        self.config.flip_x = true;
285        self
286    }
287
288    /// Flips the element vertically (mirror across the horizontal axis).
289    #[inline]
290    pub fn flip_y(&mut self) -> &mut Self {
291        self.config.flip_y = true;
292        self
293    }
294}
295
296/// Builder for configuring shape rotation (vertex-level).
297pub struct ShapeRotationBuilder {
298    pub(crate) config: engine::ShapeRotationConfig,
299}
300
301impl ShapeRotationBuilder {
302    /// Sets the rotation angle in degrees.
303    #[inline]
304    pub fn degrees(&mut self, degrees: f32) -> &mut Self {
305        self.config.rotation_radians = degrees.to_radians();
306        self
307    }
308
309    /// Sets the rotation angle in radians.
310    #[inline]
311    pub fn radians(&mut self, radians: f32) -> &mut Self {
312        self.config.rotation_radians = radians;
313        self
314    }
315
316    /// Flips the shape horizontally (applied before rotation).
317    #[inline]
318    pub fn flip_x(&mut self) -> &mut Self {
319        self.config.flip_x = true;
320        self
321    }
322
323    /// Flips the shape vertically (applied before rotation).
324    #[inline]
325    pub fn flip_y(&mut self) -> &mut Self {
326        self.config.flip_y = true;
327        self
328    }
329}