use crate::utility::*;
use crate::*;
use windows::core::CanInto;
use windows::Win32::Graphics::Direct2D::*;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct SolidColorBrush(ID2D1SolidColorBrush);
#[derive(Clone, Copy, Debug)]
pub struct GradientStop {
pub position: f32,
pub color: Rgba<f32>,
}
impl GradientStop {
#[inline]
pub fn new(position: f32, color: impl Into<Rgba<f32>>) -> Self {
Self {
position,
color: color.into(),
}
}
}
impl From<GradientStop> for D2D1_GRADIENT_STOP {
#[inline]
fn from(src: GradientStop) -> Self {
Self {
position: src.position,
color: Wrapper(src.color).into(),
}
}
}
impl<T> From<(f32, T)> for GradientStop
where
T: Into<Rgba<f32>>,
{
#[inline]
fn from(src: (f32, T)) -> Self {
Self {
position: src.0,
color: src.1.into(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum GradientMode {
Clamp = D2D1_EXTEND_MODE_CLAMP.0,
Mirror = D2D1_EXTEND_MODE_MIRROR.0,
Wrap = D2D1_EXTEND_MODE_WRAP.0,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct GradientStopCollection(ID2D1GradientStopCollection);
impl GradientStopCollection {
pub(crate) fn new<T>(dc: &ID2D1DeviceContext5, mode: GradientMode, stops: &[T]) -> Result<Self>
where
T: Into<GradientStop> + Clone,
{
let stops = stops
.iter()
.cloned()
.map(|stop| stop.into().into())
.collect::<Vec<_>>();
let collection = unsafe {
dc.CreateGradientStopCollection(&stops, D2D1_GAMMA_2_2, D2D1_EXTEND_MODE(mode as u32))?
};
Ok(Self(collection))
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LinearGradientBrush(ID2D1LinearGradientBrush);
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct RadialGradientBrush(ID2D1RadialGradientBrush);
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Brush {
SolidColor(SolidColorBrush),
LinearGradient(LinearGradientBrush),
RadialGradient(RadialGradientBrush),
}
impl Brush {
pub(crate) fn solid_color(
dc: &ID2D1DeviceContext5,
color: impl Into<Rgba<f32>>,
) -> Result<Self> {
let color = Wrapper(color.into()).into();
let brush = unsafe { dc.CreateSolidColorBrush(&color, None)? };
Ok(Self::SolidColor(SolidColorBrush(brush)))
}
pub(crate) fn linear_gradient(
dc: &ID2D1DeviceContext5,
start: impl Into<Point<f32>>,
end: impl Into<Point<f32>>,
stops: &GradientStopCollection,
) -> Result<Self> {
let start = start.into();
let end = end.into();
let brush = unsafe {
dc.CreateLinearGradientBrush(
&D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES {
startPoint: Wrapper(start).into(),
endPoint: Wrapper(end).into(),
},
None,
&stops.0,
)?
};
Ok(Self::LinearGradient(LinearGradientBrush(brush)))
}
pub(crate) fn radial_gradient(
dc: &ID2D1DeviceContext5,
ellipse: impl Into<Ellipse>,
offset: impl Into<Point<f32>>,
stops: &GradientStopCollection,
) -> Result<Self> {
let ellipse = ellipse.into();
let offset = offset.into();
let brush = unsafe {
dc.CreateRadialGradientBrush(
&D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES {
center: Wrapper(ellipse.center).into(),
radiusX: ellipse.radius.x,
radiusY: ellipse.radius.y,
gradientOriginOffset: Wrapper(offset).into(),
},
None,
&stops.0,
)?
};
Ok(Self::RadialGradient(RadialGradientBrush(brush)))
}
#[inline]
pub(crate) fn handle(&self) -> ID2D1Brush {
match self {
Self::SolidColor(b) => b.0.can_clone_into(),
Self::LinearGradient(b) => b.0.can_clone_into(),
Self::RadialGradient(b) => b.0.can_clone_into(),
}
}
}