mod error;
mod gradient;
mod parser;
mod solid;
use parser::parse_color_mapping;
use parser::parse_color_string;
use serde::Deserialize;
use windows::core::Result as WinResult;
use windows::Foundation::Numerics::Matrix3x2;
use windows::Win32::Foundation::RECT;
use windows::Win32::Graphics::Direct2D::Common::D2D1_COLOR_F;
use windows::Win32::Graphics::Direct2D::Common::D2D_POINT_2F;
use windows::Win32::Graphics::Direct2D::ID2D1Brush;
use windows::Win32::Graphics::Direct2D::ID2D1HwndRenderTarget;
use windows::Win32::Graphics::Direct2D::D2D1_BRUSH_PROPERTIES;
use windows::Win32::Graphics::Direct2D::D2D1_EXTEND_MODE_CLAMP;
use windows::Win32::Graphics::Direct2D::D2D1_GAMMA_2_2;
use windows::Win32::Graphics::Direct2D::D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES;
pub use colorparser_css::GradientCoordinates;
pub use error::Error;
pub use error::ErrorKind;
pub use error::Result;
pub use gradient::ColorMapping;
pub use gradient::ColorMappingImpl;
pub use gradient::Gradient;
pub use gradient::GradientDirection;
pub use gradient::GradientImpl;
pub use solid::Solid;
#[derive(Debug, Clone, PartialEq)]
pub enum Color {
Solid(Solid),
Gradient(Gradient),
}
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum GlobalColor {
String(String),
Mapping(ColorMapping),
}
impl Default for GlobalColor {
fn default() -> Self {
Self::String("#000000".to_string())
}
}
pub trait ColorImpl {
fn from_global_color(color: &GlobalColor) -> Result<Color>;
fn set_opacity(&self, opacity: f32);
fn get_opacity(&self) -> Option<f32>;
fn get_brush(&self) -> Option<&ID2D1Brush>;
fn set_transform(&self, transform: &Matrix3x2);
fn to_d2d1_brush(
&mut self,
render_target: &ID2D1HwndRenderTarget,
window_rect: &RECT,
brush_properties: &D2D1_BRUSH_PROPERTIES,
) -> WinResult<()>;
}
pub trait GlobalColorImpl {
fn to_color(&self) -> Result<Color>;
}
impl GlobalColorImpl for GlobalColor {
fn to_color(&self) -> Result<Color> {
match self {
GlobalColor::String(s) => parse_color_string(s.as_str()),
GlobalColor::Mapping(gradient_def) => parse_color_mapping(gradient_def.clone()),
}
}
}
impl ColorImpl for Color {
fn from_global_color(global_color: &GlobalColor) -> Result<Self> {
global_color.to_color()
}
fn set_opacity(&self, opacity: f32) {
match self {
Color::Gradient(gradient) => {
if let Some(ref id2d1_brush) = gradient.brush {
unsafe { id2d1_brush.SetOpacity(opacity) }
}
}
Color::Solid(solid) => {
if let Some(ref id2d1_brush) = solid.brush {
unsafe { id2d1_brush.SetOpacity(opacity) }
}
}
}
}
fn get_opacity(&self) -> Option<f32> {
match self {
Color::Solid(solid) => solid
.brush
.as_ref()
.map(|id2d1_brush| unsafe { id2d1_brush.GetOpacity() }),
Color::Gradient(gradient) => gradient
.brush
.as_ref()
.map(|id2d1_brush| unsafe { id2d1_brush.GetOpacity() }),
}
}
fn set_transform(&self, transform: &Matrix3x2) {
match self {
Color::Solid(solid) => {
if let Some(ref id2d1_brush) = solid.brush {
unsafe {
id2d1_brush.SetTransform(transform);
}
}
}
Color::Gradient(gradient) => {
if let Some(ref id2d1_brush) = gradient.brush {
unsafe {
id2d1_brush.SetTransform(transform);
}
}
}
}
}
fn get_brush(&self) -> Option<&ID2D1Brush> {
match self {
Color::Solid(solid) => solid.brush.as_ref().map(|id2d1_brush| id2d1_brush.into()),
Color::Gradient(gradient) => gradient
.brush
.as_ref()
.map(|id2d1_brush| id2d1_brush.into()),
}
}
fn to_d2d1_brush(
&mut self,
render_target: &ID2D1HwndRenderTarget,
window_rect: &RECT,
brush_properties: &D2D1_BRUSH_PROPERTIES,
) -> WinResult<()> {
match self {
Color::Solid(solid) => unsafe {
let id2d1_brush =
render_target.CreateSolidColorBrush(&solid.color, Some(brush_properties))?;
id2d1_brush.SetOpacity(0.0);
solid.brush = Some(id2d1_brush);
Ok(())
},
Color::Gradient(gradient) => unsafe {
let width = (window_rect.right - window_rect.left) as f32;
let height = (window_rect.bottom - window_rect.top) as f32;
let gradient_properties = D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES {
startPoint: D2D_POINT_2F {
x: gradient.direction.start[0] * width,
y: gradient.direction.start[1] * height,
},
endPoint: D2D_POINT_2F {
x: gradient.direction.end[0] * width,
y: gradient.direction.end[1] * height,
},
};
let gradient_stop_collection = render_target.CreateGradientStopCollection(
&gradient.gradient_stops,
D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE_CLAMP,
)?;
let id2d1_brush = render_target.CreateLinearGradientBrush(
&gradient_properties,
Some(brush_properties),
&gradient_stop_collection,
)?;
id2d1_brush.SetOpacity(0.0);
gradient.brush = Some(id2d1_brush);
Ok(())
},
}
}
}
impl Default for Color {
fn default() -> Self {
Color::Solid(Solid {
color: D2D1_COLOR_F::default(),
brush: None,
})
}
}