use crate::color::sRGB;
use crate::layout::{Layout, leaf};
use crate::{DAbsPoint, SourceID};
use std::rc::Rc;
use std::sync::Arc;
#[repr(u8)]
pub enum ShapeKind {
RoundRect,
Triangle,
Circle,
Arc,
}
pub struct Shape<T, const KIND: u8> {
id: std::sync::Arc<SourceID>,
props: Rc<T>,
border: f32,
blur: f32,
size: crate::DAbsPoint,
corners: [f32; 4],
fill: sRGB,
outline: sRGB,
}
pub fn round_rect<T: leaf::Padded + 'static>(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
corners: wide::f32x4,
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Shape<T, { ShapeKind::RoundRect as u8 }> {
Shape {
id,
props: props.into(),
border,
blur,
corners: corners.to_array(),
fill,
outline,
size,
}
}
pub fn triangle<T: leaf::Padded + 'static>(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
corners: [f32; 3],
offset: f32,
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Shape<T, { ShapeKind::Triangle as u8 }> {
Shape {
id,
props: props.into(),
border,
blur,
corners: [corners[0], corners[1], corners[2], offset],
fill,
outline,
size,
}
}
pub fn circle<T: leaf::Padded + 'static>(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
radii: [f32; 2],
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Shape<T, { ShapeKind::Circle as u8 }> {
Shape {
id,
props: props.into(),
border,
blur,
corners: [radii[0], radii[1], 0.0, 0.0],
fill,
outline,
size,
}
}
pub fn arcs<T: leaf::Padded + 'static>(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
inner_radius: f32,
arcs: [f32; 2],
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Shape<T, { ShapeKind::Arc as u8 }> {
Shape {
id,
props: props.into(),
border,
blur,
corners: [arcs[0] + arcs[1] * 0.5, arcs[1] * 0.5, inner_radius, 0.0],
fill,
outline,
size,
}
}
impl<T: leaf::Padded + 'static, const KIND: u8> Clone for Shape<T, KIND> {
fn clone(&self) -> Self {
Self {
id: self.id.duplicate(),
props: self.props.clone(),
border: self.border,
blur: self.blur,
corners: self.corners,
fill: self.fill,
outline: self.outline,
size: self.size,
}
}
}
impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::RoundRect as u8 }> {
pub fn new(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
corners: wide::f32x4,
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Self {
Self {
id,
props: props.into(),
border,
blur,
corners: corners.to_array(),
fill,
outline,
size,
}
}
}
impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::Triangle as u8 }> {
pub fn new(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
corners: [f32; 3],
offset: f32,
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Self {
Self {
id,
props: props.into(),
border,
blur,
corners: [corners[0], corners[1], corners[2], offset],
fill,
outline,
size,
}
}
}
impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::Circle as u8 }> {
pub fn new(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
radii: [f32; 2],
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Self {
Self {
id,
props: props.into(),
border,
blur,
corners: [radii[0], radii[1], 0.0, 0.0],
fill,
outline,
size,
}
}
}
impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::Arc as u8 }> {
pub fn new(
id: std::sync::Arc<SourceID>,
props: T,
border: f32,
blur: f32,
inner_radius: f32,
arcs: [f32; 2],
fill: sRGB,
outline: sRGB,
size: DAbsPoint,
) -> Self {
Self {
id,
props: props.into(),
border,
blur,
corners: [arcs[0] + arcs[1] * 0.5, arcs[1] * 0.5, inner_radius, 0.0],
fill,
outline,
size,
}
}
}
impl<T: leaf::Padded + 'static, const KIND: u8> crate::StateMachineChild for Shape<T, KIND> {
fn id(&self) -> std::sync::Arc<SourceID> {
self.id.clone()
}
}
impl<T: leaf::Padded + 'static, const KIND: u8> super::Component for Shape<T, KIND>
where
for<'a> &'a T: Into<&'a (dyn leaf::Padded + 'static)>,
{
type Props = T;
fn layout(
&self,
manager: &mut crate::StateManager,
_: &crate::graphics::Driver,
window: &Arc<SourceID>,
) -> Box<dyn Layout<T>> {
let dpi = manager
.get::<super::window::WindowStateMachine>(window)
.map(|x| x.state.dpi)
.unwrap_or(crate::BASE_DPI);
let mut corners = self.corners;
if KIND == ShapeKind::RoundRect as u8 {
corners[0] *= dpi.width;
corners[1] *= dpi.height;
corners[2] *= dpi.width;
corners[3] *= dpi.height;
}
Box::new(leaf::Sized::<T> {
props: self.props.clone(),
id: Arc::downgrade(&self.id),
size: self.size.resolve(dpi).to_vector().to_size().cast_unit(),
renderable: Some(Rc::new(crate::render::shape::Instance::<KIND> {
padding: self.props.padding().as_perimeter(dpi),
border: self.border,
blur: self.blur,
fill: self.fill,
outline: self.outline,
corners,
id: self.id.clone(),
})),
})
}
}