Skip to main content

rosace_widgets/tree/
rect_reader.rs

1use rosace_core::types::Rect;
2use rosace_state::Atom;
3use super::{Widget, PaintCtx, BoxedWidget};
4
5/// Fires `atom.set(Some(ctx.rect))` after paint, surfacing the widget's
6/// window-pixel coordinates to user code without any widget modification.
7///
8/// ```rust,ignore
9/// let anchor: Atom<Option<Rect>> = ctx.state(None);
10/// RectReader::new(anchor.clone(), Button::new("Open"))
11/// // After first paint: anchor.get() == Some(Rect { ... })
12/// ```
13pub struct RectReader {
14    atom:  Atom<Option<Rect>>,
15    child: BoxedWidget,
16}
17
18impl RectReader {
19    pub fn new(atom: Atom<Option<Rect>>, child: impl Widget + 'static) -> Self {
20        Self { atom, child: Box::new(child) }
21    }
22}
23
24impl Widget for RectReader {
25    fn children(&self) -> super::Children<'_> {
26        super::Children::One(&*self.child)
27    }
28
29    fn paint(&self, ctx: &mut PaintCtx) {
30        let r = ctx.rect;
31        self.child.paint(&mut ctx.child(r));
32        self.atom.set(Some(r));
33    }
34    // layout, flex_factor: protocol defaults delegate to the child.
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use rosace_core::types::{Point, Rect, Size};
41    
42    use rosace_render::{FontCache, PictureRecorder};
43    use rosace_state::use_atom;
44    use rosace_theme::built_in;
45    use std::rc::Rc;
46    use std::cell::RefCell;
47    use crate::tree::{RenderTree, Text};
48
49    fn make_paint_ctx<'a>(
50        recorder: &'a mut PictureRecorder,
51        font: &'a FontCache,
52    ) -> PaintCtx<'a> {
53        let theme = built_in::dark_theme();
54        let mut ctx = PaintCtx::root(
55            recorder,
56            Rect {
57                origin: Point { x: 10.0, y: 20.0 },
58                size: Size { width: 100.0, height: 50.0 },
59            },
60            font,
61            theme,
62            Rc::new(RefCell::new(RenderTree::new())),
63        );
64        ctx.clip_rect = None;
65        ctx
66    }
67
68    #[test]
69    fn fires_atom_with_paint_rect() {
70        let atom: Atom<Option<Rect>> = use_atom(None);
71        let font = FontCache::system_ui()
72            .or_else(FontCache::system_mono)
73            .expect("no system font");
74        let widget = RectReader::new(atom.clone(), Text::new("hi"));
75        let mut recorder = PictureRecorder::new();
76        let mut ctx = make_paint_ctx(&mut recorder, &font);
77        widget.paint(&mut ctx);
78        let rect = atom.get().expect("atom should be Some after paint");
79        assert_eq!(rect.origin.x, 10.0);
80        assert_eq!(rect.origin.y, 20.0);
81        assert_eq!(rect.size.width, 100.0);
82        assert_eq!(rect.size.height, 50.0);
83    }
84}