use crate::geometry::{Insets, Rect};
use crate::Color;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Padding(pub Insets);
impl Padding {
pub const ZERO: Padding = Padding(Insets::ZERO);
pub const fn new(top: f32, right: f32, bottom: f32, left: f32) -> Self {
Self(Insets::new(top, right, bottom, left))
}
pub const fn all(v: f32) -> Self {
Self(Insets::all(v))
}
pub const fn symmetric(vertical: f32, horizontal: f32) -> Self {
Self(Insets::symmetric(vertical, horizontal))
}
pub const fn insets(self) -> Insets {
self.0
}
pub fn shrink(self, rect: Rect) -> Rect {
rect.deflate(self.0)
}
}
impl From<Insets> for Padding {
fn from(insets: Insets) -> Self {
Self(insets)
}
}
impl From<Padding> for Insets {
fn from(padding: Padding) -> Self {
padding.0
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Margin(pub Insets);
impl Margin {
pub const ZERO: Margin = Margin(Insets::ZERO);
pub const fn new(top: f32, right: f32, bottom: f32, left: f32) -> Self {
Self(Insets::new(top, right, bottom, left))
}
pub const fn all(v: f32) -> Self {
Self(Insets::all(v))
}
pub const fn symmetric(vertical: f32, horizontal: f32) -> Self {
Self(Insets::symmetric(vertical, horizontal))
}
pub const fn insets(self) -> Insets {
self.0
}
pub fn grow(self, rect: Rect) -> Rect {
rect.inflate(self.0)
}
}
impl From<Insets> for Margin {
fn from(insets: Insets) -> Self {
Self(insets)
}
}
impl From<Margin> for Insets {
fn from(margin: Margin) -> Self {
margin.0
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum BorderStyle {
#[default]
Solid,
Dashed,
Dotted,
Double,
None,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Border {
pub insets: Insets,
pub color: Color,
pub style: BorderStyle,
}
impl Border {
pub fn solid(width: f32, color: Color) -> Self {
Self {
insets: Insets::all(width),
color,
style: BorderStyle::Solid,
}
}
pub fn new(insets: Insets, color: Color, style: BorderStyle) -> Self {
Self {
insets,
color,
style,
}
}
pub fn with_style(mut self, style: BorderStyle) -> Self {
self.style = style;
self
}
pub fn with_color(mut self, color: Color) -> Self {
self.color = color;
self
}
pub fn is_none(&self) -> bool {
self.style == BorderStyle::None
|| (self.insets.top <= 0.0
&& self.insets.right <= 0.0
&& self.insets.bottom <= 0.0
&& self.insets.left <= 0.0)
}
pub fn content_rect(&self, rect: Rect) -> Rect {
rect.deflate(self.insets)
}
}
impl Default for Border {
fn default() -> Self {
Self {
insets: Insets::ZERO,
color: Color(0, 0, 0, 0),
style: BorderStyle::None,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum CursorShape {
#[default]
Default,
Pointer,
Text,
Crosshair,
Move,
NotAllowed,
Wait,
Progress,
Grab,
Grabbing,
ResizeEw,
ResizeNs,
ResizeNesw,
ResizeNwse,
None,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn padding_shrink_matches_deflate() {
let r = Rect::new(0.0, 0.0, 100.0, 100.0);
let p = Padding::all(10.0);
assert_eq!(p.shrink(r), r.deflate(Insets::all(10.0)));
assert_eq!(p.insets(), Insets::all(10.0));
}
#[test]
fn margin_grow_matches_inflate() {
let r = Rect::new(10.0, 10.0, 50.0, 50.0);
let m = Margin::symmetric(4.0, 8.0);
assert_eq!(m.grow(r), r.inflate(Insets::symmetric(4.0, 8.0)));
}
#[test]
fn padding_margin_conversions() {
let i = Insets::new(1.0, 2.0, 3.0, 4.0);
let p: Padding = i.into();
let back: Insets = p.into();
assert_eq!(back, i);
let m: Margin = i.into();
assert_eq!(Insets::from(m), i);
}
#[test]
fn border_solid_and_content_rect() {
let b = Border::solid(2.0, Color(255, 0, 0, 255));
assert_eq!(b.style, BorderStyle::Solid);
assert_eq!(b.insets, Insets::all(2.0));
let content = b.content_rect(Rect::new(0.0, 0.0, 20.0, 20.0));
assert_eq!(content, Rect::new(2.0, 2.0, 16.0, 16.0));
assert!(!b.is_none());
}
#[test]
fn border_default_is_none() {
let b = Border::default();
assert!(b.is_none());
assert_eq!(b.style, BorderStyle::None);
let styled = Border::solid(3.0, Color(0, 0, 0, 255)).with_style(BorderStyle::None);
assert!(styled.is_none());
}
#[test]
fn cursor_shape_default() {
assert_eq!(CursorShape::default(), CursorShape::Default);
}
}