use bevy::{
color::Color,
prelude::{Rect, Vec2},
utils::default,
};
use crate::{
canvas::{QuarterPiePrimitive, RectPrimitive},
render_context::Brush,
Canvas, Primitive,
};
pub struct ShapeRef<'c> {
pub(crate) prim: &'c mut Primitive,
}
pub trait ShapeExt {
fn border(&mut self, brush: &Brush, thickness: f32) -> &mut Self;
fn glow(&mut self, brush: &Brush, spread: f32) -> &mut Self;
}
impl<'a> ShapeExt for ShapeRef<'a> {
fn border(&mut self, brush: &Brush, thickness: f32) -> &mut Self {
match self.prim {
Primitive::Rect(r) => {
r.border_color = brush.color();
r.border_width = thickness.max(0.);
}
Primitive::Line(l) => {
l.border_color = brush.color();
l.border_width = thickness.max(0.);
}
Primitive::Text(_t) => todo!(),
Primitive::QuarterPie(_q) => todo!(),
};
self
}
fn glow(&mut self, _brush: &Brush, _spread: f32) -> &mut Self {
todo!()
}
}
pub trait Shape {
fn fill<'c>(&self, canvas: &'c mut Canvas, brush: &Brush) -> ShapeRef<'c>;
fn stroke<'c>(&self, canvas: &'c mut Canvas, brush: &Brush, thickness: f32) -> ShapeRef<'c>;
}
impl Shape for Rect {
fn fill<'c>(&self, canvas: &'c mut Canvas, brush: &Brush) -> ShapeRef<'c> {
canvas.draw(RectPrimitive {
rect: *self,
color: brush.color(),
..Default::default()
})
}
fn stroke<'c>(&self, canvas: &'c mut Canvas, brush: &Brush, thickness: f32) -> ShapeRef<'c> {
let eps = thickness / 2.;
let mut prim = RectPrimitive {
rect: Rect {
min: Vec2::new(self.min.x - eps, self.max.y - eps),
max: Vec2::new(self.max.x + eps, self.max.y + eps),
},
radius: 0.,
color: brush.color(),
flip_x: false,
flip_y: false,
image: None,
image_size: Vec2::ZERO,
image_scaling: default(),
border_width: 0.,
border_color: Color::NONE,
};
canvas.draw(prim);
prim.rect = Rect {
min: Vec2::new(self.min.x - eps, self.min.y - eps),
max: Vec2::new(self.max.x + eps, self.min.y + eps),
};
canvas.draw(prim);
prim.rect = Rect {
min: Vec2::new(self.min.x - eps, self.min.y + eps),
max: Vec2::new(self.min.x + eps, self.max.y - eps),
};
canvas.draw(prim);
prim.rect = Rect {
min: Vec2::new(self.max.x - eps, self.min.y + eps),
max: Vec2::new(self.max.x + eps, self.max.y - eps),
};
canvas.draw(prim)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct RoundedRect {
pub rect: Rect,
pub radius: f32,
}
impl RoundedRect {
pub fn circle(center: Vec2, radius: f32) -> Self {
Self {
rect: Rect::from_center_half_size(center, Vec2::splat(radius)),
radius,
}
}
}
impl Shape for RoundedRect {
fn fill<'c>(&self, canvas: &'c mut Canvas, brush: &Brush) -> ShapeRef<'c> {
canvas.draw(RectPrimitive {
rect: self.rect,
radius: self.radius,
color: brush.color(),
..Default::default()
})
}
fn stroke<'c>(&self, canvas: &'c mut Canvas, brush: &Brush, thickness: f32) -> ShapeRef<'c> {
let eps = thickness / 2.;
let color = brush.color();
let half_size = self.rect.half_size();
let radii = Vec2::splat(self.radius).min(half_size);
let mut prim = RectPrimitive {
rect: Rect {
min: Vec2::new(self.rect.min.x + radii.x, self.rect.max.y - eps),
max: Vec2::new(self.rect.max.x - radii.x, self.rect.max.y + eps),
},
radius: 0.,
color,
..Default::default()
};
canvas.draw(prim);
prim.rect = Rect {
min: Vec2::new(self.rect.min.x + radii.x, self.rect.min.y - eps),
max: Vec2::new(self.rect.max.x - radii.x, self.rect.min.y + eps),
};
canvas.draw(prim);
prim.rect = Rect {
min: Vec2::new(self.rect.min.x - eps, self.rect.min.y + radii.y),
max: Vec2::new(self.rect.min.x + eps, self.rect.max.y - radii.y),
};
canvas.draw(prim);
prim.rect = Rect {
min: Vec2::new(self.rect.max.x - eps, self.rect.min.y + radii.y),
max: Vec2::new(self.rect.max.x + eps, self.rect.max.y - radii.y),
};
canvas.draw(prim);
canvas.draw(QuarterPiePrimitive {
origin: Vec2::new(self.rect.min.x + radii.x, self.rect.max.y - radii.y),
radii,
color,
flip_x: true,
flip_y: false,
});
canvas.draw(QuarterPiePrimitive {
origin: self.rect.max - radii,
radii,
color,
flip_x: false,
flip_y: false,
});
canvas.draw(QuarterPiePrimitive {
origin: self.rect.min + radii,
radii,
color,
flip_x: true,
flip_y: true,
});
canvas.draw(QuarterPiePrimitive {
origin: Vec2::new(self.rect.max.x - radii.x, self.rect.min.y + radii.y),
radii,
color,
flip_x: false,
flip_y: true,
})
}
}