use super::composition_brush::{CompositionBrush, CompositionBrushKind};
use super::{CompositionGradientBrush, CompositionLinearGradientBrush, CompositionRadialGradientBrush};
use crate::collections::FerroList;
use crate::media::immutable::ImmutableTransform;
use crate::media::{GradientSpreadMethod, IGradientStop, ITransform};
use crate::rendering::composition::animations::CompositionColorSpace;
use crate::rendering::composition::{CompositionGradientExtendMode, CompositionMappingMode};
use crate::{Matrix, RelativePoint, RelativeScalar, RelativeUnit, Vector};
use std::rc::Rc;
fn unit_of(mode: CompositionMappingMode) -> RelativeUnit {
match mode {
CompositionMappingMode::Absolute => RelativeUnit::Absolute,
CompositionMappingMode::Relative => RelativeUnit::Relative,
}
}
fn point_of(value: Vector, unit: RelativeUnit) -> RelativePoint {
RelativePoint::new(value.x, value.y, unit)
}
fn vector_of(point: RelativePoint) -> Vector {
Vector::new(point.point.x, point.point.y)
}
macro_rules! with_gradient_props {
($brush:expr, |$props:ident| $body:expr) => {
match &$brush.kind {
CompositionBrushKind::LinearGradient(_, $props) => $body,
CompositionBrushKind::RadialGradient(_, $props) => $body,
CompositionBrushKind::ConicGradient(_, $props) => $body,
_ => unreachable!("a gradient brush handle wraps a gradient brush"),
}
};
}
macro_rules! gradient_transform_members {
($($(#[$meta:meta])* $get:ident / $set:ident : $ty:ty;)*) => {
impl CompositionGradientBrush {$(
$(#[$meta])*
pub fn $get(&self) -> $ty {
let brush: &CompositionBrush = self;
with_gradient_props!(brush, |props| props.$get())
}
pub fn $set(&self, value: $ty) {
let brush: &CompositionBrush = self;
with_gradient_props!(brush, |props| props.$set(brush, value))
}
)*}
};
}
gradient_transform_members! {
anchor_point / set_anchor_point: Vector;
center_point / set_center_point: Vector;
offset / set_offset: Vector;
rotation_angle / set_rotation_angle: f32;
scale / set_scale: Vector;
transform_matrix / set_transform_matrix: Matrix;
}
impl CompositionGradientBrush {
fn gradient_brush(&self) -> &CompositionBrush {
self
}
fn mapping_cell(&self) -> &std::cell::Cell<CompositionMappingMode> {
match &self.gradient_brush().kind {
CompositionBrushKind::LinearGradient(data, _)
| CompositionBrushKind::RadialGradient(data, _)
| CompositionBrushKind::ConicGradient(data, _) => &data.mapping_mode,
_ => unreachable!("a gradient brush handle wraps a gradient brush"),
}
}
fn interpolation_cell(&self) -> &std::cell::Cell<CompositionColorSpace> {
match &self.gradient_brush().kind {
CompositionBrushKind::LinearGradient(data, _)
| CompositionBrushKind::RadialGradient(data, _)
| CompositionBrushKind::ConicGradient(data, _) => &data.interpolation_space,
_ => unreachable!("a gradient brush handle wraps a gradient brush"),
}
}
pub fn rotation_angle_in_degrees(&self) -> f32 {
self.rotation_angle().to_degrees()
}
pub fn set_rotation_angle_in_degrees(&self, value: f32) {
self.set_rotation_angle(value.to_radians())
}
pub fn extend_mode(&self) -> CompositionGradientExtendMode {
match self.spread_method() {
GradientSpreadMethod::Pad => CompositionGradientExtendMode::Clamp,
GradientSpreadMethod::Repeat => CompositionGradientExtendMode::Wrap,
GradientSpreadMethod::Reflect => CompositionGradientExtendMode::Mirror,
}
}
pub fn set_extend_mode(&self, value: CompositionGradientExtendMode) {
self.set_spread_method(match value {
CompositionGradientExtendMode::Clamp => GradientSpreadMethod::Pad,
CompositionGradientExtendMode::Wrap => GradientSpreadMethod::Repeat,
CompositionGradientExtendMode::Mirror => GradientSpreadMethod::Reflect,
})
}
pub fn interpolation_space(&self) -> CompositionColorSpace {
self.interpolation_cell().get()
}
pub fn set_interpolation_space(&self, value: CompositionColorSpace) {
self.interpolation_cell().set(value)
}
pub fn mapping_mode(&self) -> CompositionMappingMode {
self.mapping_cell().get()
}
pub fn set_mapping_mode(&self, value: CompositionMappingMode) {
if self.mapping_cell().replace(value) == value {
return;
}
let unit = unit_of(value);
let brush = self.gradient_brush();
match &brush.kind {
CompositionBrushKind::LinearGradient(_, props) => {
props.set_start_point(brush, point_of(vector_of(props.start_point()), unit));
props.set_end_point(brush, point_of(vector_of(props.end_point()), unit));
}
CompositionBrushKind::RadialGradient(_, props) => {
props.set_center(brush, point_of(vector_of(props.center()), unit));
props.set_gradient_origin(brush, point_of(vector_of(props.gradient_origin()), unit));
props.set_radius_x(brush, RelativeScalar::new(props.radius_x().scalar, unit));
props.set_radius_y(brush, RelativeScalar::new(props.radius_y().scalar, unit));
}
CompositionBrushKind::ConicGradient(_, props) => {
props.set_center(brush, point_of(vector_of(props.center()), unit));
}
_ => {}
}
}
pub fn color_stops(&self) -> FerroList<Rc<dyn IGradientStop>> {
self.gradient_stops()
}
pub fn set_color_stops(&self, value: FerroList<Rc<dyn IGradientStop>>) {
self.set_gradient_stops(value)
}
}
impl CompositionLinearGradientBrush {
pub fn start_point_vector(&self) -> Vector {
vector_of(self.start_point())
}
pub fn set_start_point_vector(&self, value: Vector) {
self.set_start_point(point_of(value, unit_of(self.mapping_mode())))
}
pub fn end_point_vector(&self) -> Vector {
vector_of(self.end_point())
}
pub fn set_end_point_vector(&self, value: Vector) {
self.set_end_point(point_of(value, unit_of(self.mapping_mode())))
}
}
impl CompositionRadialGradientBrush {
pub fn ellipse_center(&self) -> Vector {
vector_of(self.center())
}
pub fn set_ellipse_center(&self, value: Vector) {
let offset = self.gradient_origin_offset();
let unit = unit_of(self.mapping_mode());
self.set_center(point_of(value, unit));
self.set_gradient_origin(point_of(value + offset, unit));
}
pub fn ellipse_radius(&self) -> Vector {
Vector::new(self.radius_x().scalar, self.radius_y().scalar)
}
pub fn set_ellipse_radius(&self, value: Vector) {
let unit = unit_of(self.mapping_mode());
self.set_radius_x(RelativeScalar::new(value.x, unit));
self.set_radius_y(RelativeScalar::new(value.y, unit));
}
pub fn gradient_origin_offset(&self) -> Vector {
vector_of(self.gradient_origin()) - vector_of(self.center())
}
pub fn set_gradient_origin_offset(&self, value: Vector) {
let unit = unit_of(self.mapping_mode());
self.set_gradient_origin(point_of(self.ellipse_center() + value, unit));
}
}
pub trait IServerBrushWinUiTransform {
fn winui_transform(&self) -> Option<Matrix> {
None
}
fn winui_anchor_point(&self) -> Vector {
Vector::default()
}
}
pub(crate) fn with_winui_transform(
upstream: Option<Rc<dyn ITransform>>,
winui: Option<Matrix>,
) -> Option<Rc<dyn ITransform>> {
match (upstream, winui) {
(upstream, None) => upstream,
(None, Some(winui)) => Some(Rc::new(ImmutableTransform::new(winui))),
(Some(upstream), Some(winui)) => Some(Rc::new(ImmutableTransform::new(upstream.value() * winui))),
}
}
pub(crate) fn with_winui_anchor(upstream: Option<Rc<dyn ITransform>>, anchor: Vector) -> Option<Rc<dyn ITransform>> {
if anchor == Vector::default() {
return upstream;
}
let translation = Matrix::create_translation(-anchor.x, -anchor.y);
match upstream {
None => Some(Rc::new(ImmutableTransform::new(translation))),
Some(upstream) => Some(Rc::new(ImmutableTransform::new(upstream.value() * translation))),
}
}