mod capsule;
mod circle;
mod rectangle;
mod rounded_rectangle;
pub use capsule::Capsule;
pub use circle::Circle;
pub use rectangle::Rectangle;
pub use rounded_rectangle::RoundedRectangle;
use crate::{
environment::LayoutEnvironment,
layout::ResolvedLayout,
primitives::{Point, ProposedDimensions},
render::{
AnimatedJoin, StrokedShape,
shape::{AsShapePrimitive, Inset},
},
transition::Opacity,
view::{ViewLayout, ViewMarker},
};
pub trait Shape:
ViewMarker<Renderables: Inset + AsShapePrimitive> + ViewLayout<(), State = ()>
{
#[must_use]
fn stroked(self, line_width: u32) -> Stroked<Self> {
Stroked::new(self, StrokeOffset::Inner, line_width)
}
#[must_use]
fn stroked_offset(self, line_width: u32, offset: StrokeOffset) -> Stroked<Self> {
Stroked::new(self, offset, line_width)
}
}
impl<T: ViewMarker<Renderables: Inset + AsShapePrimitive> + ViewLayout<(), State = ()>> Shape
for T
{
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum StrokeOffset {
Outer,
Center,
#[default]
Inner,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Stroked<T> {
shape: T,
style: StrokeOffset,
line_width: u32,
}
impl<T: ViewMarker<Renderables: Inset + AsShapePrimitive>> Stroked<T> {
const fn new(shape: T, style: StrokeOffset, line_width: u32) -> Self {
Self {
shape,
style,
line_width,
}
}
}
impl<T: ViewMarker> ViewMarker for Stroked<T> {
type Renderables = StrokedShape<T::Renderables>;
type Transition = Opacity;
}
impl<T, Captures: ?Sized> ViewLayout<Captures> for Stroked<T>
where
T: ViewLayout<Captures>,
T::Renderables: Inset + AnimatedJoin + Clone + AsShapePrimitive,
{
type Sublayout = T::Sublayout;
type State = T::State;
fn transition(&self) -> Self::Transition {
Opacity
}
fn build_state(&self, captures: &mut Captures) -> Self::State {
self.shape.build_state(captures)
}
fn layout(
&self,
offer: &ProposedDimensions,
env: &impl LayoutEnvironment,
captures: &mut Captures,
state: &mut Self::State,
) -> ResolvedLayout<Self::Sublayout> {
self.shape.layout(offer, env, captures, state)
}
fn render_tree(
&self,
layout: &Self::Sublayout,
origin: Point,
env: &impl LayoutEnvironment,
captures: &mut Captures,
state: &mut Self::State,
) -> Self::Renderables {
let inset = match self.style {
StrokeOffset::Outer => -(self.line_width as i32 / 2),
StrokeOffset::Inner => self.line_width as i32 / 2,
StrokeOffset::Center => 0,
};
StrokedShape::new(
self.shape
.render_tree(layout, origin, env, captures, state)
.inset(inset),
self.line_width,
)
}
}