rosace_widgets/tree/
repaint_boundary.rs1use std::sync::Mutex;
2
3use rosace_render::Picture;
4use rosace_state::Atom;
5use super::{Widget, Children, PaintCtx};
6
7pub struct RepaintBoundary<W: Widget + Send + Sync + 'static> {
15 pub child: W,
16 repaint_when: Vec<Atom<u64>>,
17 cache: Mutex<Option<(rosace_core::types::Rect, Picture, Vec<u64>)>>,
18}
19
20impl<W: Widget + Send + Sync + 'static> RepaintBoundary<W> {
21 pub fn new(child: W) -> Self {
22 Self { child, repaint_when: Vec::new(), cache: Mutex::new(None) }
23 }
24
25 pub fn repaint_when(mut self, atom: Atom<u64>) -> Self {
27 self.repaint_when.push(atom);
28 self
29 }
30}
31
32impl<W: Widget + Send + Sync + 'static> Widget for RepaintBoundary<W> {
33 fn children(&self) -> Children<'_> { Children::One(&self.child) }
34
35 fn paint(&self, ctx: &mut PaintCtx) {
36 let rect = ctx.rect;
37 let keys: Vec<u64> = self.repaint_when.iter().map(|a| a.get()).collect();
38
39 let stale = {
40 let cache = self.cache.lock().unwrap();
41 match &*cache {
42 Some((r, _, k)) => *r != rect || *k != keys,
43 None => true,
44 }
45 };
46
47 if stale {
48 let child = &self.child;
50 let pic = ctx.capture(rect, |cctx| child.paint(cctx));
51 *self.cache.lock().unwrap() = Some((rect, pic, keys));
52 } else {
53 ctx.keep_child_slot();
55 }
56
57 let cache = self.cache.lock().unwrap();
58 if let Some((_, pic, _)) = &*cache {
59 ctx.replay_offset(pic, 0.0, 0.0);
60 }
61 }
62 }