x-graphics 0.2.1

Graphics framework for X
Documentation
use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};

use crate::Float;

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

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

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Rect<T> {
    pub point: Point<T>,
    pub size: Size<T>,
}

pub type FPoint = Point<Float>;
pub type FSize = Size<Float>;
pub type FRect = Rect<Float>;

pub type IPoint = Point<i32>;
pub type ISize = Size<i32>;
pub type IRect = Rect<i32>;

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

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

impl<T> Rect<T>
where
    T: Add<Output = T> + AddAssign + Sub<Output = T> + SubAssign + Neg<Output = T> + Copy + Default + PartialOrd + PartialEq,
{
    pub fn new(x: T, y: T, width: T, height: T) -> Self {
        Self {
            point: Point {
                x,
                y,
            },
            size: Size {
                width,
                height,
            },
        }
    }

    pub fn from_bounds(left: T, top: T, right: T, bottom: T) -> Self {
        Self {
            point: Point {
                x: left,
                y: top,
            },
            size: Size {
                width: right - left,
                height: bottom - top,
            },
        }
    }

    pub fn standardize(&self) {
        let mut rect = *self;
        if rect.size.width < T::default() {
            rect.point.x += rect.size.width;
            rect.size.width = -rect.size.width;
        }
        if rect.size.height < T::default() {
            rect.point.y += rect.size.height;
            rect.size.height = -rect.size.height;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.size.width <= T::default() || self.size.height <= T::default()
    }

    pub fn is_null(&self) -> bool {
        self.point.x == T::default() && self.point.y == T::default() && self.size.width == T::default() && self.size.height == T::default()
    }

    pub fn offset(&self, dx: T, dy: T) -> Rect<T> {
        let mut rect = *self;
        rect.point.x += dx;
        rect.point.y += dy;
        rect
    }

    pub fn inflate(&self, dx: T, dy: T) -> Rect<T> {
        let mut rect = *self;
        rect.point.x -= dx;
        rect.point.y -= dy;
        rect.size.width += dx + dx;
        rect.size.height += dy + dy;
        rect
    }

    pub fn deflate(&self, dx: T, dy: T) -> Rect<T> {
        let mut rect = *self;
        rect.point.x += dx;
        rect.point.y += dy;
        rect.size.width -= dx + dx;
        rect.size.height -= dy + dy;
        rect
    }

    pub fn contains_point(&self, point: Point<T>) -> bool {
        point.x >= self.point.x && point.x < self.point.x + self.size.width && point.y >= self.point.y && point.y < self.point.y + self.size.height
    }

    pub fn contains_rect(&self, rect: Rect<T>) -> bool {
        self.point.x <= rect.point.x &&
            self.point.y <= rect.point.y &&
            self.point.x + self.size.width >= rect.point.x + rect.size.width &&
            self.point.y + self.size.height >= rect.point.y + rect.size.height
    }

    pub fn intersects(&self, rect: Rect<T>) -> bool {
        self.point.x < rect.point.x + rect.size.width &&
            rect.point.x < self.point.x + self.size.width &&
            self.point.y < rect.point.y + rect.size.height &&
            rect.point.y < self.point.y + self.size.height
    }

    pub fn union(&self, rect: Rect<T>) -> Option<Rect<T>> {
        let left = if self.point.x < rect.point.x {
            self.point.x
        } else {
            rect.point.x
        };
        let top = if self.point.y < rect.point.y {
            self.point.y
        } else {
            rect.point.y
        };
        let right = if self.point.x + self.size.width > rect.point.x + rect.size.width {
            self.point.x + self.size.width
        } else {
            rect.point.x + rect.size.width
        };
        let bottom = if self.point.y + self.size.height > rect.point.y + rect.size.height {
            self.point.y + self.size.height
        } else {
            rect.point.y + rect.size.height
        };
        if left > right || top > bottom {
            None
        } else {
            Some(Rect::from_bounds(left, top, right, bottom))
        }
    }

    pub fn intersection(&self, rect: Rect<T>) -> Option<Rect<T>> {
        let left = if self.point.x > rect.point.x {
            self.point.x
        } else {
            rect.point.x
        };
        let top = if self.point.y > rect.point.y {
            self.point.y
        } else {
            rect.point.y
        };
        let right = if self.point.x + self.size.width < rect.point.x + rect.size.width {
            self.point.x + self.size.width
        } else {
            rect.point.x + rect.size.width
        };
        let bottom = if self.point.y + self.size.height < rect.point.y + rect.size.height {
            self.point.y + self.size.height
        } else {
            rect.point.y + rect.size.height
        };
        if left > right || top > bottom {
            None
        } else {
            Some(Rect::from_bounds(left, top, right, bottom))
        }
    }
}

impl From<IPoint> for (i32, i32) {
    fn from(point: IPoint) -> Self {
        (point.x, point.y)
    }
}

impl From<FPoint> for (Float, Float) {
    fn from(point: FPoint) -> Self {
        (point.x, point.y)
    }
}

impl From<IPoint> for FPoint {
    fn from(point: IPoint) -> Self {
        Self {
            x: point.x as Float,
            y: point.y as Float,
        }
    }
}

impl From<FPoint> for IPoint {
    fn from(point: FPoint) -> Self {
        Self {
            x: point.x as i32,
            y: point.y as i32,
        }
    }
}

impl From<ISize> for (i32, i32) {
    fn from(size: ISize) -> Self {
        (size.width, size.height)
    }
}

impl From<FSize> for (Float, Float) {
    fn from(size: FSize) -> Self {
        (size.width, size.height)
    }
}

impl From<ISize> for FSize {
    fn from(size: ISize) -> Self {
        Self {
            width: size.width as Float,
            height: size.height as Float,
        }
    }
}

impl From<FSize> for ISize {
    fn from(size: FSize) -> Self {
        Self {
            width: size.width as i32,
            height: size.height as i32,
        }
    }
}

impl From<IRect> for (i32, i32, i32, i32) {
    fn from(rect: IRect) -> Self {
        (rect.point.x, rect.point.y, rect.size.width, rect.size.height)
    }
}

impl From<FRect> for (Float, Float, Float, Float) {
    fn from(rect: FRect) -> Self {
        (rect.point.x, rect.point.y, rect.size.width, rect.size.height)
    }
}

impl From<IRect> for FRect {
    fn from(rect: IRect) -> Self {
        Self {
            point: FPoint {
                x: rect.point.x as Float,
                y: rect.point.y as Float,
            },
            size: FSize {
                width: rect.size.width as Float,
                height: rect.size.height as Float,
            },
        }
    }
}

impl From<FRect> for IRect {
    fn from(rect: FRect) -> Self {
        Self {
            point: IPoint {
                x: rect.point.x as i32,
                y: rect.point.y as i32,
            },
            size: ISize {
                width: rect.size.width as i32,
                height: rect.size.height as i32,
            },
        }
    }
}