use crate::effects::{BlendMode, ColorFilter};
use crate::geometry::CornerRadii;
use crate::gradients::{Brush, Shader};
use incular_core::finite_non_negative;
use incular_core::{Color, Lerp, Offset};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Border {
pub width: f32,
pub color: Color,
}
impl Border {
#[must_use]
pub fn new(width: f32, color: Color) -> Self {
Self {
width: width.max(0.),
color,
}
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Decoration {
pub background: Option<Brush>,
pub border: Option<Border>,
pub border_radius: CornerRadii,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FillRule {
NonZero,
EvenOdd,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum LineCap {
Butt,
Round,
Square,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum LineJoin {
Miter,
Round,
Bevel,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Stroke {
pub width: f32,
pub cap: LineCap,
pub join: LineJoin,
pub miter_limit: f32,
}
impl Default for Stroke {
fn default() -> Self {
Self {
width: 1.,
cap: LineCap::Butt,
join: LineJoin::Miter,
miter_limit: 4.,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum PaintStyle {
#[default]
Fill,
Stroke,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Paint {
brush: Brush,
style: PaintStyle,
stroke: Stroke,
blend_mode: BlendMode,
color_filter: Option<ColorFilter>,
}
impl Default for Paint {
fn default() -> Self {
Self {
brush: Brush::Solid(Color::BLACK),
style: PaintStyle::Fill,
stroke: Stroke::default(),
blend_mode: BlendMode::SrcOver,
color_filter: None,
}
}
}
impl Paint {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn brush(mut self, brush: impl Into<Brush>) -> Self {
self.brush = brush.into();
self
}
#[must_use]
pub fn shader(self, shader: impl Into<Shader>) -> Self {
self.brush(shader)
}
#[must_use]
pub fn color(self, color: Color) -> Self {
self.brush(color)
}
#[must_use]
pub fn style(mut self, style: PaintStyle) -> Self {
self.style = style;
self
}
#[must_use]
pub fn fill(self) -> Self {
self.style(PaintStyle::Fill)
}
#[must_use]
pub fn stroke(self) -> Self {
self.style(PaintStyle::Stroke)
}
#[must_use]
pub fn stroke_settings(mut self, stroke: Stroke) -> Self {
self.stroke = Stroke {
width: finite_non_negative(stroke.width),
cap: stroke.cap,
join: stroke.join,
miter_limit: finite_non_negative(stroke.miter_limit),
};
self
}
#[must_use]
pub fn stroke_width(mut self, width: f32) -> Self {
self.stroke.width = finite_non_negative(width);
self
}
#[must_use]
pub fn blend_mode(mut self, blend_mode: BlendMode) -> Self {
self.blend_mode = blend_mode;
self
}
#[must_use]
pub fn color_filter(mut self, color_filter: Option<ColorFilter>) -> Self {
self.color_filter = color_filter;
self
}
#[must_use]
pub fn brush_value(&self) -> &Brush {
&self.brush
}
#[must_use]
pub const fn style_value(&self) -> PaintStyle {
self.style
}
#[must_use]
pub const fn stroke_value(&self) -> Stroke {
self.stroke
}
#[must_use]
pub const fn blend_mode_value(&self) -> BlendMode {
self.blend_mode
}
#[must_use]
pub fn color_filter_value(&self) -> Option<ColorFilter> {
self.color_filter
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Shadow {
pub color: Color,
pub offset: Offset,
pub blur_radius: f32,
}
impl Shadow {
#[must_use]
pub const fn new(color: Color, offset: Offset, blur_radius: f32) -> Self {
Self {
color,
offset,
blur_radius: if blur_radius.is_finite() && blur_radius > 0. {
blur_radius
} else {
0.
},
}
}
}
impl Lerp for Shadow {
fn lerp(&self, other: &Self, t: f32) -> Self {
Self::new(
self.color.lerp(&other.color, t),
self.offset.lerp(&other.offset, t),
self.blur_radius.lerp(&other.blur_radius, t),
)
}
}