1use refineable::Refineable as _;
2
3use crate::{
4 Bounds, Element, ElementId, GlobalElementId, IntoElement, Pixels, Style, StyleRefinement,
5 Styled, WindowContext,
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 WindowContext) -> T,
12 paint: impl 'static + FnOnce(Bounds<Pixels>, T, &mut WindowContext),
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 WindowContext) -> T>>,
25 paint: Option<Box<dyn FnOnce(Bounds<Pixels>, T, &mut WindowContext)>>,
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 request_layout(
46 &mut self,
47 _id: Option<&GlobalElementId>,
48 cx: &mut WindowContext,
49 ) -> (crate::LayoutId, Self::RequestLayoutState) {
50 let mut style = Style::default();
51 style.refine(&self.style);
52 let layout_id = cx.request_layout(style.clone(), []);
53 (layout_id, style)
54 }
55
56 fn prepaint(
57 &mut self,
58 _id: Option<&GlobalElementId>,
59 bounds: Bounds<Pixels>,
60 _request_layout: &mut Style,
61 cx: &mut WindowContext,
62 ) -> Option<T> {
63 Some(self.prepaint.take().unwrap()(bounds, cx))
64 }
65
66 fn paint(
67 &mut self,
68 _id: Option<&GlobalElementId>,
69 bounds: Bounds<Pixels>,
70 style: &mut Style,
71 prepaint: &mut Self::PrepaintState,
72 cx: &mut WindowContext,
73 ) {
74 let prepaint = prepaint.take().unwrap();
75 style.paint(bounds, cx, |cx| {
76 (self.paint.take().unwrap())(bounds, prepaint, cx)
77 });
78 }
79}
80
81impl<T> Styled for Canvas<T> {
82 fn style(&mut self) -> &mut crate::StyleRefinement {
83 &mut self.style
84 }
85}