yuno 0.1.0

A declarative UI layout and rendering framework powered by Skia.
use crate::drawing::{Drawable, Plan};
use crate::layouts::{HasPlanner, Layout};
use skia_safe::{Canvas, Color, Color4f, Font, Paint, PaintCap, PaintStyle, Point, Rect};
use std::cell::RefCell;
use std::rc::Rc;

pub struct RingProgressChart {
    pub pct: RefCell<f32>,
    label: String,
    color: Color,
    font: Font,
    planner: RefCell<Option<Rc<dyn Layout>>>,
}

impl HasPlanner for RingProgressChart {
    fn planner(&self) -> &RefCell<Option<Rc<dyn Layout>>> {
        &self.planner
    }
    fn set_planner(&self, p: Option<Rc<dyn Layout>>) {
        *self.planner.borrow_mut() = p;
    }
}

impl Drawable for RingProgressChart {
    fn draw(&self, canvas: &Canvas) -> anyhow::Result<()> {
        let area = self.get_planned_drawing_area(canvas);
        // Make it a perfect square based on the smaller dimension
        let size = area.width().min(area.height());
        let radius = size / 2.0;

        let cx = area.left + area.width() / 2.0;
        let cy = area.top + area.height() / 2.0;
        let arc_rect = Rect::from_xywh(cx - radius, cy - radius, size, size);

        let mut p = Paint::default();
        p.set_anti_alias(true)
            .set_style(PaintStyle::Stroke)
            .set_stroke_width(4.0);

        // Background ring
        p.set_color4f(Color4f::new(1.0, 1.0, 1.0, 0.1), None);
        canvas.draw_arc(arc_rect, 0.0, 360.0, false, &p);

        // Foreground ring
        p.set_color(self.color).set_stroke_cap(PaintCap::Round);
        let sweep = (self.pct.borrow().clamp(0.0, 100.0) / 100.0) * 360.0;
        if sweep > 0.0 {
            canvas.draw_arc(arc_rect, -90.0, sweep, false, &p);
        }

        // Center Label
        let mut lbl_paint = Paint::default();
        lbl_paint.set_anti_alias(true).set_color(Color::WHITE);
        let text_w = self.font.measure_str(&self.label, Some(&lbl_paint)).0;
        // Adjust Y for basic visual vertical centering
        canvas.draw_str(
            &self.label,
            Point::new(cx - text_w / 2.0, cy + 3.5),
            &self.font,
            &lbl_paint,
        );

        Ok(())
    }

    fn get_horizontal_plan(&self) -> Plan {
        Plan::Fill
    }
    fn get_vertical_plan(&self) -> Plan {
        Plan::Fill
    }
}

impl RingProgressChart {
    pub fn new(pct: f32, label: &str, color: Color, font: Font) -> Rc<Self> {
        let mut small_font = font;
        small_font.set_size(10.0);
        Rc::new(Self {
            pct: RefCell::new(pct),
            label: label.to_string(),
            color,
            font: small_font,
            planner: RefCell::new(None),
        })
    }
}