use lyon_algorithms::path::{BuilderImpl, builder::WithSvg, traits::Build};
use lyon_tessellation::path::path::Builder;
use crate::{
draw::{Fill, Stroke},
entity::Shape,
};
pub trait Geometry<GenericBuilder> {
fn add_geometry(&self, b: &mut GenericBuilder);
}
pub trait ShapeBuilderBase<GenericBuilder> {
#[must_use]
fn add(self, shape: &impl Geometry<GenericBuilder>) -> Self;
#[must_use]
fn fill(self, fill: impl Into<Fill>) -> ReadyShapeBuilder<GenericBuilder>;
#[must_use]
fn stroke(self, stroke: impl Into<Stroke>) -> ReadyShapeBuilder<GenericBuilder>;
}
#[derive(Default, Clone)]
pub struct ShapeBuilder<GenericBuilder>(GenericBuilder);
impl<GenericBuilder> ShapeBuilderBase<GenericBuilder> for ShapeBuilder<GenericBuilder> {
fn add(mut self, shape: &impl Geometry<GenericBuilder>) -> Self {
shape.add_geometry(&mut self.0);
self
}
fn fill(self, fill: impl Into<Fill>) -> ReadyShapeBuilder<GenericBuilder> {
ReadyShapeBuilder {
builder: self.0,
fill: Some(fill.into()),
stroke: None,
}
}
fn stroke(self, stroke: impl Into<Stroke>) -> ReadyShapeBuilder<GenericBuilder> {
ReadyShapeBuilder {
builder: self.0,
fill: None,
stroke: Some(stroke.into()),
}
}
}
impl<GenericBuilder> ShapeBuilder<GenericBuilder>
where
GenericBuilder: LyonPathBuilderExt,
{
#[must_use]
pub fn new() -> Self {
Self(GenericBuilder::new())
}
#[must_use]
pub fn with(geometry: &impl Geometry<GenericBuilder>) -> Self {
Self::new().add(geometry)
}
}
#[derive(Clone)]
pub struct ReadyShapeBuilder<GenericBuilder> {
pub(crate) builder: GenericBuilder,
pub(crate) fill: Option<Fill>,
pub(crate) stroke: Option<Stroke>,
}
impl<GenericBuilder> ShapeBuilderBase<GenericBuilder> for ReadyShapeBuilder<GenericBuilder> {
fn add(mut self, shape: &impl Geometry<GenericBuilder>) -> Self {
shape.add_geometry(&mut self.builder);
self
}
fn fill(self, fill: impl Into<Fill>) -> Self {
Self {
fill: Some(fill.into()),
..self
}
}
fn stroke(self, stroke: impl Into<Stroke>) -> Self {
Self {
stroke: Some(stroke.into()),
..self
}
}
}
impl<GenericBuilder> ReadyShapeBuilder<GenericBuilder>
where
GenericBuilder: Build<PathType = lyon_tessellation::path::Path>,
{
pub fn build(self) -> Shape {
Shape::new(self.builder.build(), self.fill, self.stroke)
}
}
pub trait LyonPathBuilderExt {
fn new() -> Self;
}
impl LyonPathBuilderExt for Builder {
fn new() -> Self {
Self::new()
}
}
impl LyonPathBuilderExt for WithSvg<BuilderImpl> {
fn new() -> Self {
Builder::new().with_svg()
}
}