use crate::orbs::engine::{Frame, Line};
use gpui::{
BorderStyle, Bounds, PathBuilder, Pixels, Point, Window, opaque_grey, point, px, quad, size,
transparent_black,
};
fn ink_color(white: f32, alpha: f32, dark: bool) -> gpui::Hsla {
let w = white.clamp(0.0, 1.0);
let lightness = if dark { 1.0 - w } else { w };
opaque_grey(lightness, alpha.clamp(0.0, 1.0))
}
fn paint_lines(window: &mut Window, origin: Point<Pixels>, lines: &[Line], dark: bool) {
for l in lines {
if l.a < 0.02 {
continue;
}
let mut b = PathBuilder::stroke(px(l.w));
b.move_to(point(origin.x + px(l.x1), origin.y + px(l.y1)));
b.line_to(point(origin.x + px(l.x2), origin.y + px(l.y2)));
if let Ok(path) = b.build() {
window.paint_path(path, ink_color(l.white, l.a, dark));
}
}
}
fn paint_dots(window: &mut Window, origin: Point<Pixels>, frame: &Frame, dark: bool, r_min: f32) {
for d in &frame.dots {
if d.a < 0.02 {
continue;
}
let r = d.r.max(r_min);
let diameter = r * 2.0;
let bounds = Bounds {
origin: point(origin.x + px(d.x - r), origin.y + px(d.y - r)),
size: size(px(diameter), px(diameter)),
};
window.paint_quad(quad(
bounds,
px(r),
ink_color(d.white, d.a, dark),
px(0.),
transparent_black(),
BorderStyle::default(),
));
}
}
fn no_layer() -> bool {
static N: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*N.get_or_init(|| std::env::var("ORB_NO_LAYER").as_deref() == Ok("1"))
}
pub fn paint_frame(
window: &mut Window,
bounds: Bounds<Pixels>,
frame: &Frame,
dark: bool,
r_min: f32,
) {
if no_layer() {
paint_lines(window, bounds.origin, &frame.lines, dark);
paint_dots(window, bounds.origin, frame, dark, r_min);
return;
}
window.paint_layer(bounds, |window| {
paint_lines(window, bounds.origin, &frame.lines, dark);
paint_dots(window, bounds.origin, frame, dark, r_min);
});
}