x-graphics 0.2.1

Graphics framework for X
Documentation
use core_graphics::{base::CGFloat, color_space::CGColorSpace, gradient::CGGradient};

use crate::{
    geometry::FPoint,
    gradient::{GradientBackend, GradientData},
    paint::Color,
    Float,
};

#[derive(Clone, Debug)]
pub struct CoreGraphicsGradient {
    data: GradientData,
    color_stops: Vec<(Float, Color)>,
    gradient: Option<CGGradient>,
}

impl GradientBackend for CoreGraphicsGradient {
    fn new_linear(x1: Float, y1: Float, x2: Float, y2: Float) -> Self {
        Self {
            gradient: None,
            data: GradientData::Linear((FPoint::new(x1, y1), FPoint::new(x2, y2))),
            color_stops: Vec::new(),
        }
    }

    fn new_radial(x1: Float, y1: Float, x2: Float, y2: Float, r: Float) -> Self {
        Self {
            gradient: None,
            data: GradientData::Radial((FPoint::new(x1, y1), FPoint::new(x2, y2), r)),
            color_stops: Vec::new(),
        }
    }

    fn add_color_stop(&mut self, offset: Float, color: Color) -> bool {
        if offset.is_nan() || !(0.0..=1.0).contains(&offset) {
            return false;
        }

        self.color_stops.push((offset, color));
        self.gradient = None;
        true
    }
}

impl CoreGraphicsGradient {
    pub(super) fn cg_gradient(&mut self) -> Option<CGGradient> {
        if self.gradient.is_none() {
            let len = self.color_stops.len();
            let mut locations: Vec<CGFloat> = vec![0.0; len];
            let mut colors: Vec<CGFloat> = vec![0.0; len * 4];

            for i in 0..len {
                locations[i] = self.color_stops[i].0 as CGFloat;
                let (r, g, b, a) = self.color_stops[i].1.get_float_value();
                colors[i * 4..i * 4 + 4].copy_from_slice(&[r, g, b, a]);
            }

            let cs = CGColorSpace::new_device_rgb();
            self.gradient = CGGradient::from_color_components(cs.as_ref(), Some(&colors), Some(&locations));
        }
        self.gradient.clone()
    }

    pub(super) fn data(&self) -> GradientData {
        self.data.clone()
    }
}