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, offset: impl Into<Vector2>) -> &mut Self {
51        self.config.offset = offset.into();
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
123/// Builder for configuring scrollbars on overflow and text inputs.
124pub struct ScrollbarBuilder {
125    pub(crate) config: engine::ScrollbarConfig,
126}
127
128impl ScrollbarBuilder {
129    /// Thumb thickness in pixels.
130    #[inline]
131    pub fn width(&mut self, width: f32) -> &mut Self {
132        self.config.width = width.max(1.0);
133        self
134    }
135
136    /// Corner radius for the scrollbar thumb.
137    #[inline]
138    pub fn corner_radius(&mut self, radius: f32) -> &mut Self {
139        self.config.corner_radius = radius.max(0.0);
140        self
141    }
142
143    /// Scrollbar thumb color.
144    #[inline]
145    pub fn thumb_color(&mut self, color: impl Into<Color>) -> &mut Self {
146        self.config.thumb_color = color.into();
147        self
148    }
149
150    /// Optional track color rendered behind the thumb.
151    #[inline]
152    pub fn track_color(&mut self, color: impl Into<Color>) -> &mut Self {
153        self.config.track_color = Some(color.into());
154        self
155    }
156
157    /// Minimum thumb size in pixels.
158    #[inline]
159    pub fn min_thumb_size(&mut self, size: f32) -> &mut Self {
160        self.config.min_thumb_size = size.max(1.0);
161        self
162    }
163
164    /// Frames before auto-hide starts fading.
165    #[inline]
166    pub fn hide_after_frames(&mut self, frames: u32) -> &mut Self {
167        self.config.hide_after_frames = Some(frames);
168        self
169    }
170}
171
172impl OverflowBuilder {
173    /// Clips horizontal overflow without enabling scrolling.
174    #[inline]
175    pub fn clip_x(&mut self) -> &mut Self {
176        self.config.horizontal = true;
177        self
178    }
179
180    /// Clips vertical overflow without enabling scrolling.
181    #[inline]
182    pub fn clip_y(&mut self) -> &mut Self {
183        self.config.vertical = true;
184        self
185    }
186
187    /// Clips both axes without enabling scrolling.
188    #[inline]
189    pub fn clip(&mut self) -> &mut Self {
190        self.config.horizontal = true;
191        self.config.vertical = true;
192        self
193    }
194
195    /// Enables horizontal scrolling (implies clip on this axis).
196    #[inline]
197    pub fn scroll_x(&mut self) -> &mut Self {
198        self.config.horizontal = true;
199        self.config.scroll_x = true;
200        self
201    }
202
203    /// Enables vertical scrolling (implies clip on this axis).
204    #[inline]
205    pub fn scroll_y(&mut self) -> &mut Self {
206        self.config.vertical = true;
207        self.config.scroll_y = true;
208        self
209    }
210
211    /// Enables scrolling on both axes (implies clip on both axes).
212    #[inline]
213    pub fn scroll(&mut self) -> &mut Self {
214        self.config.horizontal = true;
215        self.config.vertical = true;
216        self.config.scroll_x = true;
217        self.config.scroll_y = true;
218        self
219    }
220
221    /// Disables mouse drag scrolling for this overflow container.
222    ///
223    /// Touch drag and scroll wheel input remain enabled.
224    #[inline]
225    pub fn no_drag_scroll(&mut self) -> &mut Self {
226        self.config.no_drag_scroll = true;
227        self
228    }
229
230    /// Enables and configures the overflow scrollbar.
231    #[inline]
232    pub fn scrollbar(
233        &mut self,
234        f: impl for<'a> FnOnce(&'a mut ScrollbarBuilder) -> &'a mut ScrollbarBuilder,
235    ) -> &mut Self {
236        let mut builder = ScrollbarBuilder {
237            config: self.config.scrollbar.unwrap_or_default(),
238        };
239        f(&mut builder);
240        self.config.scrollbar = Some(builder.config);
241        self
242    }
243}
244
245/// Builder for configuring border properties using a closure.
246pub struct BorderBuilder {
247    pub(crate) config: engine::BorderConfig,
248}
249
250/// Defines the position of the border relative to the bounding box.
251#[derive(Debug, Clone, Copy, Default)]
252pub enum BorderPosition {
253    /// Fully outside the bounding box.
254    #[default]
255    Outside,
256    /// Half inside, half outside the bounding box.
257    Middle,
258    /// Fully inside the bounding box.
259    Inside,
260}
261
262impl BorderBuilder {
263    /// Sets the border color.
264    #[inline]
265    pub fn color(&mut self, color: impl Into<Color>) -> &mut Self {
266        self.config.color = color.into();
267        self
268    }
269
270    /// Set the same border width for all sides.
271    #[inline]
272    pub fn all(&mut self, width: u16) -> &mut Self {
273        self.config.width.left = width;
274        self.config.width.right = width;
275        self.config.width.top = width;
276        self.config.width.bottom = width;
277        self
278    }
279
280    /// Sets the left border width.
281    #[inline]
282    pub fn left(&mut self, width: u16) -> &mut Self {
283        self.config.width.left = width;
284        self
285    }
286
287    /// Sets the right border width.
288    #[inline]
289    pub fn right(&mut self, width: u16) -> &mut Self {
290        self.config.width.right = width;
291        self
292    }
293
294    /// Sets the top border width.
295    #[inline]
296    pub fn top(&mut self, width: u16) -> &mut Self {
297        self.config.width.top = width;
298        self
299    }
300
301    /// Sets the bottom border width.
302    #[inline]
303    pub fn bottom(&mut self, width: u16) -> &mut Self {
304        self.config.width.bottom = width;
305        self
306    }
307
308    /// Sets the spacing between child elements.
309    #[inline]
310    pub fn between_children(&mut self, width: u16) -> &mut Self {
311        self.config.width.between_children = width;
312        self
313    }
314
315    /// Sets the position of the border relative to the bounding box.
316    #[inline]
317    pub fn position(&mut self, position: BorderPosition) -> &mut Self {
318        self.config.position = position;
319        self
320    }
321}
322
323/// Builder for configuring visual rotation (render-target based).
324pub struct VisualRotationBuilder {
325    pub(crate) config: engine::VisualRotationConfig,
326}
327
328impl VisualRotationBuilder {
329    /// Sets the rotation angle in degrees.
330    #[inline]
331    pub fn degrees(&mut self, degrees: f32) -> &mut Self {
332        self.config.rotation_radians = degrees.to_radians();
333        self
334    }
335
336    /// Sets the rotation angle in radians.
337    #[inline]
338    pub fn radians(&mut self, radians: f32) -> &mut Self {
339        self.config.rotation_radians = radians;
340        self
341    }
342
343    /// Sets the rotation pivot as normalized coordinates (0.0–1.0).
344    /// Default is (0.5, 0.5) = center of the element.
345    /// (0.0, 0.0) = top-left corner.
346    #[inline]
347    pub fn pivot(&mut self, pivot: impl Into<Vector2>) -> &mut Self {
348        let pivot = pivot.into();
349        self.config.pivot_x = pivot.x;
350        self.config.pivot_y = pivot.y;
351        self
352    }
353
354    /// Flips the element horizontally (mirror across the vertical axis).
355    #[inline]
356    pub fn flip_x(&mut self) -> &mut Self {
357        self.config.flip_x = true;
358        self
359    }
360
361    /// Flips the element vertically (mirror across the horizontal axis).
362    #[inline]
363    pub fn flip_y(&mut self) -> &mut Self {
364        self.config.flip_y = true;
365        self
366    }
367}
368
369/// Builder for configuring shape rotation (vertex-level).
370pub struct ShapeRotationBuilder {
371    pub(crate) config: engine::ShapeRotationConfig,
372}
373
374impl ShapeRotationBuilder {
375    /// Sets the rotation angle in degrees.
376    #[inline]
377    pub fn degrees(&mut self, degrees: f32) -> &mut Self {
378        self.config.rotation_radians = degrees.to_radians();
379        self
380    }
381
382    /// Sets the rotation angle in radians.
383    #[inline]
384    pub fn radians(&mut self, radians: f32) -> &mut Self {
385        self.config.rotation_radians = radians;
386        self
387    }
388
389    /// Flips the shape horizontally (applied before rotation).
390    #[inline]
391    pub fn flip_x(&mut self) -> &mut Self {
392        self.config.flip_x = true;
393        self
394    }
395
396    /// Flips the shape vertically (applied before rotation).
397    #[inline]
398    pub fn flip_y(&mut self) -> &mut Self {
399        self.config.flip_y = true;
400        self
401    }
402}