use std::sync::Mutex;
use rosace_render::Picture;
use rosace_state::Atom;
use super::{Widget, Children, PaintCtx};
pub struct RepaintBoundary<W: Widget + Send + Sync + 'static> {
pub child: W,
repaint_when: Vec<Atom<u64>>,
cache: Mutex<Option<(rosace_core::types::Rect, Picture, Vec<u64>)>>,
}
impl<W: Widget + Send + Sync + 'static> RepaintBoundary<W> {
pub fn new(child: W) -> Self {
Self { child, repaint_when: Vec::new(), cache: Mutex::new(None) }
}
pub fn repaint_when(mut self, atom: Atom<u64>) -> Self {
self.repaint_when.push(atom);
self
}
}
impl<W: Widget + Send + Sync + 'static> Widget for RepaintBoundary<W> {
fn children(&self) -> Children<'_> { Children::One(&self.child) }
fn paint(&self, ctx: &mut PaintCtx) {
let rect = ctx.rect;
let keys: Vec<u64> = self.repaint_when.iter().map(|a| a.get()).collect();
let stale = {
let cache = self.cache.lock().unwrap();
match &*cache {
Some((r, _, k)) => *r != rect || *k != keys,
None => true,
}
};
if stale {
let child = &self.child;
let pic = ctx.capture(rect, |cctx| child.paint(cctx));
*self.cache.lock().unwrap() = Some((rect, pic, keys));
} else {
ctx.keep_child_slot();
}
let cache = self.cache.lock().unwrap();
if let Some((_, pic, _)) = &*cache {
ctx.replay_offset(pic, 0.0, 0.0);
}
}
}