ply-engine 1.1.1

The most powerful app engine made entirely in Rust
Documentation
use crate::align::{AlignX, AlignY};
use crate::id::Id;
use crate::{color::Color, Vector2, engine};

/// Specifies how pointer capture should behave for floating elements.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum PointerCaptureMode {
    /// Captures all pointer input.
    #[default]
    Capture,
    /// Allows pointer input to pass through.
    Passthrough,
}

/// Defines how a floating element is attached to other elements.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum FloatingAttachToElement {
    /// The floating element is not attached to any other element.
    #[default]
    None,
    /// The floating element is attached to its parent element.
    Parent,
    /// The floating element is attached to a specific element identified by an ID.
    ElementWithId,
    /// The floating element is attached to the root of the layout.
    Root,
}

/// Defines how a floating element is clipped.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum FloatingClipToElement {
    /// The floating element is not clipped.
    #[default]
    None,
    /// The floating element is clipped to the attached parent.
    AttachedParent,
}

/// Builder for configuring floating element properties using a closure.
pub struct FloatingBuilder {
    pub(crate) config: engine::FloatingConfig,
}

impl FloatingBuilder {
    /// Sets the floating element's offset.
    #[inline]
    pub fn offset(&mut self, offset: impl Into<Vector2>) -> &mut Self {
        self.config.offset = offset.into();
        self
    }

    /// Sets the floating element's Z-index.
    #[inline]
    pub fn z_index(&mut self, z_index: i16) -> &mut Self {
        self.config.z_index = z_index;
        self
    }

    /// Sets the attachment points of the floating element and its parent.
    ///
    /// Each tuple is `(AlignX, AlignY)` — the first for the element, the second for the parent.
    /// ```ignore
    /// .floating(|f| f.anchor((CenterX, Bottom), (CenterX, Top)))
    /// ```
    #[inline]
    pub fn anchor(
        &mut self,
        element: (AlignX, AlignY),
        parent: (AlignX, AlignY),
    ) -> &mut Self {
        self.config.attach_points.element_x = element.0;
        self.config.attach_points.element_y = element.1;
        self.config.attach_points.parent_x = parent.0;
        self.config.attach_points.parent_y = parent.1;
        self
    }

    /// Attaches this floating element to its parent element (default behavior).
    #[inline]
    pub fn attach_parent(&mut self) -> &mut Self {
        self.config.attach_to = FloatingAttachToElement::Parent;
        self
    }

    /// Attaches this floating element to the root of the layout.
    #[inline]
    pub fn attach_root(&mut self) -> &mut Self {
        self.config.attach_to = FloatingAttachToElement::Root;
        self
    }

    /// Attaches this floating element to a specific element by ID.
    #[inline]
    pub fn attach_id(&mut self, id: impl Into<Id>) -> &mut Self {
        self.config.attach_to = FloatingAttachToElement::ElementWithId;
        self.config.parent_id = id.into().id;
        self
    }

    /// Clips this floating element to its parent's bounds.
    #[inline]
    pub fn clip_by_parent(&mut self) -> &mut Self {
        self.config.clip_to = FloatingClipToElement::AttachedParent;
        self
    }

    /// Sets pointer capture mode to Passthrough.
    #[inline]
    pub fn passthrough(&mut self) -> &mut Self {
        self.config.pointer_capture_mode = PointerCaptureMode::Passthrough;
        self
    }
}

/// Builder for configuring overflow (clip/scroll) properties using a closure.
pub struct OverflowBuilder {
    pub(crate) config: engine::ClipConfig,
}

/// Builder for configuring scrollbars on overflow and text inputs.
pub struct ScrollbarBuilder {
    pub(crate) config: engine::ScrollbarConfig,
}

impl ScrollbarBuilder {
    /// Thumb thickness in pixels.
    #[inline]
    pub fn width(&mut self, width: f32) -> &mut Self {
        self.config.width = width.max(1.0);
        self
    }

    /// Corner radius for the scrollbar thumb.
    #[inline]
    pub fn corner_radius(&mut self, radius: f32) -> &mut Self {
        self.config.corner_radius = radius.max(0.0);
        self
    }

    /// Scrollbar thumb color.
    #[inline]
    pub fn thumb_color(&mut self, color: impl Into<Color>) -> &mut Self {
        self.config.thumb_color = color.into();
        self
    }

    /// Optional track color rendered behind the thumb.
    #[inline]
    pub fn track_color(&mut self, color: impl Into<Color>) -> &mut Self {
        self.config.track_color = Some(color.into());
        self
    }

    /// Minimum thumb size in pixels.
    #[inline]
    pub fn min_thumb_size(&mut self, size: f32) -> &mut Self {
        self.config.min_thumb_size = size.max(1.0);
        self
    }

    /// Frames before auto-hide starts fading.
    #[inline]
    pub fn hide_after_frames(&mut self, frames: u32) -> &mut Self {
        self.config.hide_after_frames = Some(frames);
        self
    }
}

impl OverflowBuilder {
    /// Clips horizontal overflow without enabling scrolling.
    #[inline]
    pub fn clip_x(&mut self) -> &mut Self {
        self.config.horizontal = true;
        self
    }

    /// Clips vertical overflow without enabling scrolling.
    #[inline]
    pub fn clip_y(&mut self) -> &mut Self {
        self.config.vertical = true;
        self
    }

    /// Clips both axes without enabling scrolling.
    #[inline]
    pub fn clip(&mut self) -> &mut Self {
        self.config.horizontal = true;
        self.config.vertical = true;
        self
    }

    /// Enables horizontal scrolling (implies clip on this axis).
    #[inline]
    pub fn scroll_x(&mut self) -> &mut Self {
        self.config.horizontal = true;
        self.config.scroll_x = true;
        self
    }

    /// Enables vertical scrolling (implies clip on this axis).
    #[inline]
    pub fn scroll_y(&mut self) -> &mut Self {
        self.config.vertical = true;
        self.config.scroll_y = true;
        self
    }

    /// Enables scrolling on both axes (implies clip on both axes).
    #[inline]
    pub fn scroll(&mut self) -> &mut Self {
        self.config.horizontal = true;
        self.config.vertical = true;
        self.config.scroll_x = true;
        self.config.scroll_y = true;
        self
    }

    /// Disables mouse drag scrolling for this overflow container.
    ///
    /// Touch drag and scroll wheel input remain enabled.
    #[inline]
    pub fn no_drag_scroll(&mut self) -> &mut Self {
        self.config.no_drag_scroll = true;
        self
    }

    /// Enables and configures the overflow scrollbar.
    #[inline]
    pub fn scrollbar(
        &mut self,
        f: impl for<'a> FnOnce(&'a mut ScrollbarBuilder) -> &'a mut ScrollbarBuilder,
    ) -> &mut Self {
        let mut builder = ScrollbarBuilder {
            config: self.config.scrollbar.unwrap_or_default(),
        };
        f(&mut builder);
        self.config.scrollbar = Some(builder.config);
        self
    }
}

/// Builder for configuring border properties using a closure.
pub struct BorderBuilder {
    pub(crate) config: engine::BorderConfig,
}

/// Defines the position of the border relative to the bounding box.
#[derive(Debug, Clone, Copy, Default)]
pub enum BorderPosition {
    /// Fully outside the bounding box.
    #[default]
    Outside,
    /// Half inside, half outside the bounding box.
    Middle,
    /// Fully inside the bounding box.
    Inside,
}

impl BorderBuilder {
    /// Sets the border color.
    #[inline]
    pub fn color(&mut self, color: impl Into<Color>) -> &mut Self {
        self.config.color = color.into();
        self
    }

    /// Set the same border width for all sides.
    #[inline]
    pub fn all(&mut self, width: u16) -> &mut Self {
        self.config.width.left = width;
        self.config.width.right = width;
        self.config.width.top = width;
        self.config.width.bottom = width;
        self
    }

    /// Sets the left border width.
    #[inline]
    pub fn left(&mut self, width: u16) -> &mut Self {
        self.config.width.left = width;
        self
    }

    /// Sets the right border width.
    #[inline]
    pub fn right(&mut self, width: u16) -> &mut Self {
        self.config.width.right = width;
        self
    }

    /// Sets the top border width.
    #[inline]
    pub fn top(&mut self, width: u16) -> &mut Self {
        self.config.width.top = width;
        self
    }

    /// Sets the bottom border width.
    #[inline]
    pub fn bottom(&mut self, width: u16) -> &mut Self {
        self.config.width.bottom = width;
        self
    }

    /// Sets the spacing between child elements.
    #[inline]
    pub fn between_children(&mut self, width: u16) -> &mut Self {
        self.config.width.between_children = width;
        self
    }

    /// Sets the position of the border relative to the bounding box.
    #[inline]
    pub fn position(&mut self, position: BorderPosition) -> &mut Self {
        self.config.position = position;
        self
    }
}

/// Builder for configuring visual rotation (render-target based).
pub struct VisualRotationBuilder {
    pub(crate) config: engine::VisualRotationConfig,
}

impl VisualRotationBuilder {
    /// Sets the rotation angle in degrees.
    #[inline]
    pub fn degrees(&mut self, degrees: f32) -> &mut Self {
        self.config.rotation_radians = degrees.to_radians();
        self
    }

    /// Sets the rotation angle in radians.
    #[inline]
    pub fn radians(&mut self, radians: f32) -> &mut Self {
        self.config.rotation_radians = radians;
        self
    }

    /// Sets the rotation pivot as normalized coordinates (0.0–1.0).
    /// Default is (0.5, 0.5) = center of the element.
    /// (0.0, 0.0) = top-left corner.
    #[inline]
    pub fn pivot(&mut self, pivot: impl Into<Vector2>) -> &mut Self {
        let pivot = pivot.into();
        self.config.pivot_x = pivot.x;
        self.config.pivot_y = pivot.y;
        self
    }

    /// Flips the element horizontally (mirror across the vertical axis).
    #[inline]
    pub fn flip_x(&mut self) -> &mut Self {
        self.config.flip_x = true;
        self
    }

    /// Flips the element vertically (mirror across the horizontal axis).
    #[inline]
    pub fn flip_y(&mut self) -> &mut Self {
        self.config.flip_y = true;
        self
    }
}

/// Builder for configuring shape rotation (vertex-level).
pub struct ShapeRotationBuilder {
    pub(crate) config: engine::ShapeRotationConfig,
}

impl ShapeRotationBuilder {
    /// Sets the rotation angle in degrees.
    #[inline]
    pub fn degrees(&mut self, degrees: f32) -> &mut Self {
        self.config.rotation_radians = degrees.to_radians();
        self
    }

    /// Sets the rotation angle in radians.
    #[inline]
    pub fn radians(&mut self, radians: f32) -> &mut Self {
        self.config.rotation_radians = radians;
        self
    }

    /// Flips the shape horizontally (applied before rotation).
    #[inline]
    pub fn flip_x(&mut self) -> &mut Self {
        self.config.flip_x = true;
        self
    }

    /// Flips the shape vertically (applied before rotation).
    #[inline]
    pub fn flip_y(&mut self) -> &mut Self {
        self.config.flip_y = true;
        self
    }
}