zsui 0.3.0-alpha.2

Rust-first feature-gated native UI framework for Win32, AppKit, and Linux.
Documentation
use super::*;
use crate::symbolic_icons::{draw_normalized_icon, SymbolicIconCanvas};

pub(super) fn draw(command: &NativeDrawIconCommand, color: crate::Color) {
    let Some(context) = NSGraphicsContext::currentContext() else {
        return;
    };
    let bounds = command.fitted_bounds(crate::Size {
        width: 16,
        height: 16,
    });
    if bounds.width <= 0 || bounds.height <= 0 {
        return;
    }
    context.saveGraphicsState();
    NSBezierPath::bezierPathWithRect(appkit_rect(bounds)).addClip();
    appkit_color(color).set();
    let path = NSBezierPath::bezierPath();
    let scale = f64::from(bounds.width) / 16.0;
    path.setLineWidth(1.35 * scale);
    path.setLineCapStyle(objc2_app_kit::NSLineCapStyle::Round);
    path.setLineJoinStyle(objc2_app_kit::NSLineJoinStyle::Round);
    let mut canvas = Canvas {
        path,
        bounds,
        scale,
        has_current: false,
    };
    draw_normalized_icon(&mut canvas, command.icon);
    context.restoreGraphicsState();
}

struct Canvas {
    path: Retained<NSBezierPath>,
    bounds: Rect,
    scale: f64,
    has_current: bool,
}
impl Canvas {
    fn point(&self, x: f64, y: f64) -> objc2_foundation::NSPoint {
        objc2_foundation::NSPoint::new(
            f64::from(self.bounds.x) + x * self.scale,
            f64::from(self.bounds.y) + y * self.scale,
        )
    }
    fn reset(&mut self) {
        self.path.removeAllPoints();
        self.has_current = false;
    }
}

impl SymbolicIconCanvas for Canvas {
    fn new_sub_path(&mut self) {
        self.has_current = false;
    }
    fn move_to(&mut self, x: f64, y: f64) {
        self.path.moveToPoint(self.point(x, y));
        self.has_current = true;
    }
    fn line_to(&mut self, x: f64, y: f64) {
        if self.has_current {
            self.path.lineToPoint(self.point(x, y));
        } else {
            self.move_to(x, y);
        }
    }
    fn curve_to(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, x: f64, y: f64) {
        self.path.curveToPoint_controlPoint1_controlPoint2(
            self.point(x, y),
            self.point(x1, y1),
            self.point(x2, y2),
        );
        self.has_current = true;
    }
    fn arc(&mut self, x: f64, y: f64, radius: f64, start: f64, end: f64) {
        crate::symbolic_icons::trace_arc(self, x, y, radius, start, end);
    }
    fn rectangle(&mut self, x: f64, y: f64, width: f64, height: f64) {
        self.move_to(x, y);
        self.line_to(x + width, y);
        self.line_to(x + width, y + height);
        self.line_to(x, y + height);
        self.close_path();
    }
    fn set_line_width(&mut self, width: f64) {
        self.path.setLineWidth(width * self.scale);
    }
    fn close_path(&mut self) {
        self.path.closePath();
    }
    fn stroke(&mut self) {
        self.path.stroke();
        self.reset();
    }
    fn fill(&mut self) {
        self.path.fill();
        self.reset();
    }
}