canvas.rs

 1use refineable::Refineable as _;
 2
 3use crate::{
 4    App, Bounds, Element, ElementId, GlobalElementId, InspectorElementId, IntoElement, Pixels,
 5    Style, StyleRefinement, Styled, Window,
 6};
 7
 8/// Construct a canvas element with the given paint callback.
 9/// Useful for adding short term custom drawing to a view.
10pub fn canvas<T>(
11    prepaint: impl 'static + FnOnce(Bounds<Pixels>, &mut Window, &mut App) -> T,
12    paint: impl 'static + FnOnce(Bounds<Pixels>, T, &mut Window, &mut App),
13) -> Canvas<T> {
14    Canvas {
15        prepaint: Some(Box::new(prepaint)),
16        paint: Some(Box::new(paint)),
17        style: StyleRefinement::default(),
18    }
19}
20
21/// A canvas element, meant for accessing the low level paint API without defining a whole
22/// custom element
23pub struct Canvas<T> {
24    prepaint: Option<Box<dyn FnOnce(Bounds<Pixels>, &mut Window, &mut App) -> T>>,
25    paint: Option<Box<dyn FnOnce(Bounds<Pixels>, T, &mut Window, &mut App)>>,
26    style: StyleRefinement,
27}
28
29impl<T: 'static> IntoElement for Canvas<T> {
30    type Element = Self;
31
32    fn into_element(self) -> Self::Element {
33        self
34    }
35}
36
37impl<T: 'static> Element for Canvas<T> {
38    type RequestLayoutState = Style;
39    type PrepaintState = Option<T>;
40
41    fn id(&self) -> Option<ElementId> {
42        None
43    }
44
45    fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
46        None
47    }
48
49    fn request_layout(
50        &mut self,
51        _id: Option<&GlobalElementId>,
52        _inspector_id: Option<&InspectorElementId>,
53        window: &mut Window,
54        cx: &mut App,
55    ) -> (crate::LayoutId, Self::RequestLayoutState) {
56        let mut style = Style::default();
57        style.refine(&self.style);
58        let layout_id = window.request_layout(style.clone(), [], cx);
59        (layout_id, style)
60    }
61
62    fn prepaint(
63        &mut self,
64        _id: Option<&GlobalElementId>,
65        _inspector_id: Option<&InspectorElementId>,
66        bounds: Bounds<Pixels>,
67        _request_layout: &mut Style,
68        window: &mut Window,
69        cx: &mut App,
70    ) -> Option<T> {
71        Some(self.prepaint.take().unwrap()(bounds, window, cx))
72    }
73
74    fn paint(
75        &mut self,
76        _id: Option<&GlobalElementId>,
77        _inspector_id: Option<&InspectorElementId>,
78        bounds: Bounds<Pixels>,
79        style: &mut Style,
80        prepaint: &mut Self::PrepaintState,
81        window: &mut Window,
82        cx: &mut App,
83    ) {
84        let prepaint = prepaint.take().unwrap();
85        style.paint(bounds, window, cx, |window, cx| {
86            (self.paint.take().unwrap())(bounds, prepaint, window, cx)
87        });
88    }
89}
90
91impl<T> Styled for Canvas<T> {
92    fn style(&mut self) -> &mut crate::StyleRefinement {
93        &mut self.style
94    }
95}