use std::hash::Hash;
use crate::geometry::{Anchor, Transform, Vec2};
use crate::layout::{raster::Flexible as RasterFlexible, Flexible};
use crate::placement::{raster::Positioned as RasterPositioned, Positioned, SnapTarget};
use crate::raster::{Opacity, RasterComponent, RasterTransform};
use crate::vector::{Transformed, VectorComponent, VectorTransform};
pub trait VectorBuilder: Sized {
type Output: VectorComponent + PartialEq + Hash + 'static;
fn build_component(self) -> Self::Output;
}
pub trait RasterBuilder: Sized {
type Output: RasterComponent + PartialEq + Hash + 'static;
fn build_component(self) -> Self::Output;
}
pub trait VectorBuilderPlacement: VectorBuilder {
fn place_at(self, position: Vec2) -> Positioned {
Positioned::new(self.build_component().boxed(), Anchor::TOP_LEFT, position)
}
fn anchored(self, anchor: Anchor) -> AnchoredVectorBuilder<Self::Output> {
AnchoredVectorBuilder {
component: self.build_component(),
anchor,
}
}
}
impl<B: VectorBuilder> VectorBuilderPlacement for B {}
pub trait VectorBuilderTransform: VectorBuilder {
fn transform(self, transform: Transform) -> Transformed {
self.build_component().transform(transform)
}
fn transform_around(self, anchor: Anchor, transform: Transform) -> Transformed {
self.build_component().transform_around(anchor, transform)
}
fn opacity(self, opacity: f32) -> Transformed {
self.build_component().opacity(opacity)
}
}
impl<B: VectorBuilder> VectorBuilderTransform for B {}
pub trait VectorBuilderFlex: VectorBuilder {
fn grow(self, grow: f32) -> Flexible {
Flexible {
grow,
child: Box::new(self.build_component()),
}
}
}
impl<B: VectorBuilder> VectorBuilderFlex for B {}
pub trait RasterBuilderPlacement: RasterBuilder {
fn place_at(self, position: Vec2) -> RasterPositioned {
RasterPositioned::new(self.build_component().boxed(), Anchor::TOP_LEFT, position)
}
fn anchored(self, anchor: Anchor) -> AnchoredRasterBuilder<Self::Output> {
AnchoredRasterBuilder {
component: self.build_component(),
anchor,
}
}
}
impl<B: RasterBuilder> RasterBuilderPlacement for B {}
pub trait RasterBuilderTransform: RasterBuilder {
fn opacity(self, opacity: f32) -> Opacity {
self.build_component().opacity(opacity)
}
}
impl<B: RasterBuilder> RasterBuilderTransform for B {}
pub trait RasterBuilderFlex: RasterBuilder {
fn grow(self, grow: f32) -> RasterFlexible {
RasterFlexible {
grow,
child: Box::new(self.build_component()),
}
}
}
impl<B: RasterBuilder> RasterBuilderFlex for B {}
pub struct AnchoredVectorBuilder<C: VectorComponent> {
component: C,
anchor: Anchor,
}
impl<C: VectorComponent + 'static> AnchoredVectorBuilder<C> {
pub fn snap_to(self, target: impl Into<SnapTarget>) -> Positioned {
Positioned::new(self.component.boxed(), self.anchor, target)
}
}
pub struct AnchoredRasterBuilder<C: RasterComponent> {
component: C,
anchor: Anchor,
}
impl<C: RasterComponent + 'static> AnchoredRasterBuilder<C> {
pub fn snap_to(self, target: impl Into<SnapTarget>) -> RasterPositioned {
RasterPositioned::new(self.component.boxed(), self.anchor, target)
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a ready-to-apply raster effect",
note = "an effect builder must have every parameter set and its `#[effect]` child slot still empty"
)]
pub trait Effect {
type Output: RasterComponent + 'static;
fn apply(self, child: Box<dyn RasterComponent>) -> Self::Output;
}
pub trait RasterEffect: RasterComponent + Sized + 'static {
fn effect<E: Effect>(self, effect: E) -> E::Output {
effect.apply(Box::new(self))
}
fn effect_with<C, F>(self, wrap: F) -> C
where
F: FnOnce(Box<dyn RasterComponent>) -> C,
C: RasterComponent + 'static,
{
wrap(Box::new(self))
}
}
impl<T: RasterComponent + 'static> RasterEffect for T {}