use super::{Dimensions, Padding, Point, Range, Scalar};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Rect {
pub x: Range,
pub y: Range,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Corner {
TopLeft,
TopRight,
BottomLeft,
BottomRight,
}
impl Rect {
pub fn from_xy_dim(xy: Point, dim: Dimensions) -> Self {
Rect {
x: Range::from_pos_and_len(xy[0], dim[0]),
y: Range::from_pos_and_len(xy[1], dim[1]),
}
}
pub fn from_corners(a: Point, b: Point) -> Self {
let (left, right) = if a[0] < b[0] { (a[0], b[0]) } else { (b[0], a[0]) };
let (bottom, top) = if a[1] < b[1] { (a[1], b[1]) } else { (b[1], a[1]) };
Rect {
x: Range { start: left, end: right },
y: Range { start: bottom, end: top },
}
}
pub fn overlap(self, other: Self) -> Option<Self> {
self.x.overlap(other.x).and_then(|x| self.y.overlap(other.y).map(|y| Rect { x: x, y: y }))
}
pub fn max(self, other: Self) -> Self {
Rect {
x: self.x.max(other.x),
y: self.y.max(other.y),
}
}
pub fn x(&self) -> Scalar {
self.x.middle()
}
pub fn y(&self) -> Scalar {
self.y.middle()
}
pub fn xy(&self) -> Point {
[self.x(), self.y()]
}
pub fn x_y(&self) -> (Scalar, Scalar) {
(self.x(), self.y())
}
pub fn w(&self) -> Scalar {
self.x.len()
}
pub fn h(&self) -> Scalar {
self.y.len()
}
pub fn dim(&self) -> Dimensions {
[self.w(), self.h()]
}
pub fn w_h(&self) -> (Scalar, Scalar) {
(self.w(), self.h())
}
pub fn xy_dim(&self) -> (Point, Dimensions) {
(self.xy(), self.dim())
}
pub fn x_y_w_h(&self) -> (Scalar, Scalar, Scalar, Scalar) {
let (xy, dim) = self.xy_dim();
(xy[0], xy[1], dim[0], dim[1])
}
pub fn len(&self) -> Scalar {
::utils::partial_max(self.w(), self.h())
}
pub fn bottom(&self) -> Scalar {
self.y.undirected().start
}
pub fn top(&self) -> Scalar {
self.y.undirected().end
}
pub fn left(&self) -> Scalar {
self.x.undirected().start
}
pub fn right(&self) -> Scalar {
self.x.undirected().end
}
pub fn top_left(&self) -> Point {
[self.left(), self.top()]
}
pub fn bottom_left(&self) -> Point {
[self.left(), self.bottom()]
}
pub fn top_right(&self) -> Point {
[self.right(), self.top()]
}
pub fn bottom_right(&self) -> Point {
[self.right(), self.bottom()]
}
pub fn l_r_b_t(&self) -> (Scalar, Scalar, Scalar, Scalar) {
(self.left(), self.right(), self.bottom(), self.top())
}
pub fn l_t_w_h(&self) -> (Scalar, Scalar, Scalar, Scalar) {
let (w, h) = self.w_h();
(self.left(), self.top(), w, h)
}
pub fn l_b_w_h(&self) -> (Scalar, Scalar, Scalar, Scalar) {
let (w, h) = self.w_h();
(self.left(), self.bottom(), w, h)
}
pub fn shift_x(self, x: Scalar) -> Self {
Rect { x: self.x.shift(x), ..self }
}
pub fn shift_y(self, y: Scalar) -> Self {
Rect { y: self.y.shift(y), ..self }
}
pub fn shift(self, xy: Point) -> Self {
self.shift_x(xy[0]).shift_y(xy[1])
}
pub fn relative_to_x(self, x: Scalar) -> Self {
Rect { x: self.x.shift(-x), ..self }
}
pub fn relative_to_y(self, y: Scalar) -> Self {
Rect { y: self.y.shift(-y), ..self }
}
pub fn relative_to(self, xy: Point) -> Self {
self.relative_to_x(xy[0]).relative_to_y(xy[1])
}
pub fn is_over(&self, xy: Point) -> bool {
self.x.is_over(xy[0]) && self.y.is_over(xy[1])
}
pub fn pad_left(self, pad: Scalar) -> Self {
Rect { x: self.x.pad_start(pad), ..self }
}
pub fn pad_right(self, pad: Scalar) -> Self {
Rect { x: self.x.pad_end(pad), ..self }
}
pub fn pad_bottom(self, pad: Scalar) -> Self {
Rect { y: self.y.pad_start(pad), ..self }
}
pub fn pad_top(self, pad: Scalar) -> Self {
Rect { y: self.y.pad_end(pad), ..self }
}
pub fn pad(self, pad: Scalar) -> Self {
let Rect { x, y } = self;
Rect { x: x.pad(pad), y: y.pad(pad) }
}
pub fn padding(self, padding: Padding) -> Self {
Rect {
x: self.x.pad_ends(padding.x.start, padding.x.end),
y: self.y.pad_ends(padding.y.start, padding.y.end),
}
}
pub fn stretch_to_point(self, point: Point) -> Self {
let Rect { x, y } = self;
Rect {
x: x.stretch_to_value(point[0]),
y: y.stretch_to_value(point[1]),
}
}
pub fn left_of(self, other: Self) -> Self {
Rect {
x: self.x.align_before(other.x),
y: self.y,
}
}
pub fn right_of(self, other: Self) -> Self {
Rect {
x: self.x.align_after(other.x),
y: self.y,
}
}
pub fn below(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_before(other.x),
}
}
pub fn above(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_after(other.x),
}
}
pub fn align_x_of(self, align: super::Align, other: Self) -> Self {
Rect {
x: self.x.align_to(align, other.x),
y: self.y,
}
}
pub fn align_y_of(self, align: super::Align, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_to(align, other.y),
}
}
pub fn align_left_of(self, other: Self) -> Self {
Rect {
x: self.x.align_start_of(other.x),
y: self.y,
}
}
pub fn align_middle_x_of(self, other: Self) -> Self {
Rect {
x: self.x.align_middle_of(other.x),
y: self.y,
}
}
pub fn align_right_of(self, other: Self) -> Self {
Rect {
x: self.x.align_end_of(other.x),
y: self.y,
}
}
pub fn align_bottom_of(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_start_of(other.y),
}
}
pub fn align_middle_y_of(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_middle_of(other.y),
}
}
pub fn align_top_of(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_end_of(other.y),
}
}
pub fn top_left_of(self, other: Self) -> Self {
self.align_left_of(other).align_top_of(other)
}
pub fn top_right_of(self, other: Self) -> Self {
self.align_right_of(other).align_top_of(other)
}
pub fn bottom_left_of(self, other: Self) -> Self {
self.align_left_of(other).align_bottom_of(other)
}
pub fn bottom_right_of(self, other: Self) -> Self {
self.align_right_of(other).align_bottom_of(other)
}
pub fn mid_top_of(self, other: Self) -> Self {
self.align_middle_x_of(other).align_top_of(other)
}
pub fn mid_bottom_of(self, other: Self) -> Self {
self.align_middle_x_of(other).align_bottom_of(other)
}
pub fn mid_left_of(self, other: Self) -> Self {
self.align_left_of(other).align_middle_y_of(other)
}
pub fn mid_right_of(self, other: Self) -> Self {
self.align_right_of(other).align_middle_y_of(other)
}
pub fn middle_of(self, other: Self) -> Self {
self.align_middle_x_of(other).align_middle_y_of(other)
}
pub fn closest_corner(&self, xy: Point) -> Corner {
use super::Edge;
let x_edge = self.x.closest_edge(xy[0]);
let y_edge = self.y.closest_edge(xy[1]);
match (x_edge, y_edge) {
(Edge::Start, Edge::Start) => Corner::BottomLeft,
(Edge::Start, Edge::End) => Corner::TopLeft,
(Edge::End, Edge::Start) => Corner::BottomRight,
(Edge::End, Edge::End) => Corner::TopRight,
}
}
}