use crate::prelude::*;
use nalgebra::{Rotation2, Scale2, Transform2, Translation2, Vector2};
use palette::{IntoColor, Srgba};
use std::{
f32::consts::FRAC_1_SQRT_2,
ops::{Deref, DerefMut, Mul},
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StylePosition {
pub stroke: Option<Stroke>,
pub fill: Option<Fill>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Stroke {
Solid {
color: Srgba,
width: f32,
},
Dashed {
color: Srgba,
width: f32,
on: f32,
off: f32,
},
}
impl Stroke {
pub fn new_solid<F: IntoColor<Srgba>>(color: F, width: f32) -> Self {
let color = color.into_color();
Self::Solid { color, width }
}
pub fn new_dashed<F: IntoColor<Srgba>>(color: F, width: f32, on: f32, off: f32) -> Self {
let color = color.into_color();
Self::Dashed {
color,
width,
on,
off,
}
}
}
impl<C: IntoColor<Srgba>> From<(C, f32)> for Stroke {
fn from((color, width): (C, f32)) -> Self {
Stroke::new_solid(color, width)
}
}
impl Mul<Stroke> for Transform2<f32> {
type Output = Stroke;
fn mul(self, rhs: Stroke) -> Self::Output {
match rhs {
Stroke::Solid { color, width } => Stroke::Solid {
color,
width: (self * Vector2::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2)).magnitude() * width,
},
Stroke::Dashed {
color,
width,
on,
off,
} => {
let factor = (self * Vector2::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2)).magnitude();
Stroke::Dashed {
color,
width: width * factor,
on: on * factor,
off: off * factor,
}
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Fill {
Solid {
color: Srgba,
},
}
impl Stroke {}
impl<C: IntoColor<Srgba>> From<C> for Fill {
fn from(color: C) -> Self {
Fill::Solid {
color: color.into_color(),
}
}
}
impl Mul<Fill> for Transform2<f32> {
type Output = Fill;
fn mul(self, rhs: Fill) -> Self::Output {
match rhs {
Fill::Solid { color } => Fill::Solid { color },
}
}
}
#[derive(Default, Debug, Clone, PartialEq, Shape)]
pub struct Style<T> {
pub shape: T,
#[shape(into_some)]
pub fill: Option<Fill>,
#[shape(into_some)]
pub stroke: Option<Stroke>,
}
impl<T> Style<T> {
#[inline]
pub fn new(shape: T) -> Self {
Style {
shape,
fill: None,
stroke: None,
}
}
}
impl<T> Deref for Style<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.shape
}
}
impl<T> DerefMut for Style<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.shape
}
}
impl<T: Into<Shape>> From<Style<T>> for Shape {
#[inline]
fn from(
Style {
shape,
fill,
stroke,
}: Style<T>,
) -> Self {
if fill.is_none() && stroke.is_none() {
shape.into()
} else {
Shape::Style {
fill,
stroke,
shape: Box::new(shape.into()),
}
}
}
}
impl<T: ShapeOp> ShapeOp for Style<T> {
#[inline]
fn transform(&mut self, transform_matrix: Transform2<f32>) -> &mut Self {
self.shape.transform(transform_matrix);
self
}
#[inline]
fn translate<U: Into<Translation2<f32>>>(&mut self, translation: U) -> &mut Self {
self.shape.translate(translation);
self
}
#[inline]
fn scale<S: Into<Scale2<f32>>>(&mut self, scale: S) -> &mut Self {
self.shape.scale(scale);
self
}
#[inline]
fn rotate<R: Into<Rotation2<f32>>>(&mut self, rotation: R) -> &mut Self {
self.shape.rotate(rotation);
self
}
#[inline]
fn local_transform(&self) -> &Transform2<f32> {
self.shape.local_transform()
}
#[inline]
fn global_transform(&self, parent_transform: &Transform2<f32>) -> Transform2<f32> {
self.shape.global_transform(parent_transform)
}
}
impl<T: ShapeBoundingBox> ShapeBoundingBox for Style<T> {
#[inline]
fn local_bounding_box(&self) -> BoundingBox<UnParticular> {
self.shape.local_bounding_box()
}
}