aura-gui 0.3.5

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
//! Primitivas geométricas en píxeles lógicos.

use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub};

/// Longitud en píxeles lógicos (independiente del factor de escala).
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
pub struct Pixels(pub f32);

/// Atajo para construir un [`Pixels`]: `px(16.)`.
pub const fn px(value: f32) -> Pixels {
    Pixels(value)
}

impl Pixels {
    pub const ZERO: Pixels = Pixels(0.0);

    pub fn max(self, other: Pixels) -> Pixels {
        Pixels(self.0.max(other.0))
    }

    pub fn min(self, other: Pixels) -> Pixels {
        Pixels(self.0.min(other.0))
    }
}

impl Add for Pixels {
    type Output = Pixels;
    fn add(self, rhs: Pixels) -> Pixels {
        Pixels(self.0 + rhs.0)
    }
}

impl AddAssign for Pixels {
    fn add_assign(&mut self, rhs: Pixels) {
        self.0 += rhs.0;
    }
}

impl Sub for Pixels {
    type Output = Pixels;
    fn sub(self, rhs: Pixels) -> Pixels {
        Pixels(self.0 - rhs.0)
    }
}

impl Mul<f32> for Pixels {
    type Output = Pixels;
    fn mul(self, rhs: f32) -> Pixels {
        Pixels(self.0 * rhs)
    }
}

impl Div<f32> for Pixels {
    type Output = Pixels;
    fn div(self, rhs: f32) -> Pixels {
        Pixels(self.0 / rhs)
    }
}

impl Neg for Pixels {
    type Output = Pixels;
    fn neg(self) -> Pixels {
        Pixels(-self.0)
    }
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Point {
    pub x: Pixels,
    pub y: Pixels,
}

impl Point {
    pub const fn new(x: Pixels, y: Pixels) -> Self {
        Self { x, y }
    }
}

impl Add for Point {
    type Output = Point;
    fn add(self, rhs: Point) -> Point {
        Point::new(self.x + rhs.x, self.y + rhs.y)
    }
}

impl Sub for Point {
    type Output = Point;
    fn sub(self, rhs: Point) -> Point {
        Point::new(self.x - rhs.x, self.y - rhs.y)
    }
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Size {
    pub width: Pixels,
    pub height: Pixels,
}

impl Size {
    pub const fn new(width: Pixels, height: Pixels) -> Self {
        Self { width, height }
    }
}

/// Rectángulo definido por su esquina superior izquierda y su tamaño.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Bounds {
    pub origin: Point,
    pub size: Size,
}

impl Bounds {
    pub const fn new(origin: Point, size: Size) -> Self {
        Self { origin, size }
    }

    pub fn right(&self) -> Pixels {
        self.origin.x + self.size.width
    }

    pub fn bottom(&self) -> Pixels {
        self.origin.y + self.size.height
    }

    pub fn contains(&self, point: Point) -> bool {
        point.x >= self.origin.x && point.x < self.right() && point.y >= self.origin.y && point.y < self.bottom()
    }

    /// Intersección con otro rectángulo; es el recorte (`ContentMask`) de GPUI.
    pub fn intersect(&self, other: &Bounds) -> Bounds {
        let left = self.origin.x.max(other.origin.x);
        let top = self.origin.y.max(other.origin.y);
        let right = self.right().min(other.right());
        let bottom = self.bottom().min(other.bottom());
        Bounds::new(
            Point::new(left, top),
            Size::new((right - left).max(Pixels::ZERO), (bottom - top).max(Pixels::ZERO)),
        )
    }
}

/// Valor por lado: padding, margen, grosor de borde.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Edges {
    pub top: Pixels,
    pub right: Pixels,
    pub bottom: Pixels,
    pub left: Pixels,
}

impl Edges {
    pub const fn all(value: Pixels) -> Self {
        Self { top: value, right: value, bottom: value, left: value }
    }
}

/// Valor por esquina: radios de borde.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Corners {
    pub top_left: Pixels,
    pub top_right: Pixels,
    pub bottom_right: Pixels,
    pub bottom_left: Pixels,
}

impl Corners {
    pub const fn all(value: Pixels) -> Self {
        Self { top_left: value, top_right: value, bottom_right: value, bottom_left: value }
    }
}