freya_components/
canvas.rs1use std::{
2 any::Any,
3 borrow::Cow,
4 cell::RefCell,
5 collections::HashMap,
6 rc::Rc,
7};
8
9use freya_core::{
10 integration::*,
11 prelude::*,
12};
13use freya_engine::prelude::{
14 ClipOp,
15 Paint,
16 PaintStyle,
17 SkRect,
18};
19
20type Callback = Rc<RefCell<dyn FnMut(&mut RenderContext)>>;
21
22pub struct RenderCallback(Callback);
23
24impl RenderCallback {
25 pub fn new(callback: impl FnMut(&mut RenderContext) + 'static) -> Self {
26 Self(Rc::new(RefCell::new(callback)))
27 }
28
29 pub fn call(&self, data: &mut RenderContext) {
30 (self.0.borrow_mut())(data)
31 }
32}
33
34impl Clone for RenderCallback {
35 fn clone(&self) -> Self {
36 Self(self.0.clone())
37 }
38}
39
40impl PartialEq for RenderCallback {
41 fn eq(&self, _other: &Self) -> bool {
42 true
43 }
44}
45
46impl<H: FnMut(&mut RenderContext) + 'static> From<H> for RenderCallback {
47 fn from(value: H) -> Self {
48 RenderCallback::new(value)
49 }
50}
51
52#[derive(PartialEq, Clone)]
53pub struct CanvasElement {
54 pub layout: LayoutData,
55 pub event_handlers: FxHashMap<EventName, EventHandlerType>,
56 pub effect: Option<EffectData>,
57 pub on_render: RenderCallback,
58}
59
60impl CanvasElement {}
61
62impl ElementExt for CanvasElement {
63 fn changed(&self, other: &Rc<dyn ElementExt>) -> bool {
64 let Some(rect) = (other.as_ref() as &dyn Any).downcast_ref::<Self>() else {
65 return false;
66 };
67
68 self != rect
69 }
70
71 fn diff(&self, other: &Rc<dyn ElementExt>) -> DiffModifies {
72 let Some(rect) = (other.as_ref() as &dyn Any).downcast_ref::<Self>() else {
73 return DiffModifies::all();
74 };
75
76 let mut diff = DiffModifies::empty();
77
78 if self.effect != rect.effect {
79 diff.insert(DiffModifies::EFFECT);
80 }
81
82 if !self.layout.self_layout_eq(&rect.layout.layout) {
83 diff.insert(DiffModifies::STYLE);
84 diff.insert(DiffModifies::LAYOUT);
85 }
86
87 if !self.layout.inner_layout_eq(&rect.layout.layout) {
88 diff.insert(DiffModifies::STYLE);
89 diff.insert(DiffModifies::INNER_LAYOUT);
90 }
91
92 if self.event_handlers != rect.event_handlers {
93 diff.insert(DiffModifies::EVENT_HANDLERS);
94 }
95
96 if self.on_render != rect.on_render {
97 diff.insert(DiffModifies::STYLE);
98 }
99
100 diff
101 }
102
103 fn layout(&'_ self) -> Cow<'_, LayoutData> {
104 Cow::Borrowed(&self.layout)
105 }
106
107 fn effect(&'_ self) -> Option<Cow<'_, EffectData>> {
108 self.effect.as_ref().map(Cow::Borrowed)
109 }
110
111 fn style(&'_ self) -> Cow<'_, StyleState> {
112 Cow::Owned(StyleState::default())
113 }
114
115 fn text_style(&'_ self) -> Cow<'_, TextStyleData> {
116 Cow::Owned(TextStyleData::default())
117 }
118
119 fn accessibility(&'_ self) -> Cow<'_, AccessibilityData> {
120 Cow::Owned(AccessibilityData::default())
121 }
122
123 fn events_handlers(&'_ self) -> Option<Cow<'_, FxHashMap<EventName, EventHandlerType>>> {
124 Some(Cow::Borrowed(&self.event_handlers))
125 }
126
127 fn clip(&self, context: ClipContext) {
128 let area = context.visible_area;
129
130 context.canvas.clip_rect(
131 SkRect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y()),
132 ClipOp::Intersect,
133 true,
134 );
135 }
136
137 fn render(&self, mut context: RenderContext) {
138 let style = self.style();
139 let area = context.layout_node.visible_area();
140
141 let mut paint = Paint::default();
142 paint.set_anti_alias(true);
143 paint.set_style(PaintStyle::Fill);
144 style.background.apply_to_paint(&mut paint, area);
145
146 context.canvas.draw_rect(
147 SkRect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y()),
148 &paint,
149 );
150
151 context
152 .canvas
153 .scale((context.scale_factor as f32, context.scale_factor as f32));
154 context.canvas.translate((area.min_x(), area.min_y()));
155 self.on_render.call(&mut context);
156 context.canvas.restore();
157 }
158}
159
160pub struct Canvas {
161 element: CanvasElement,
162 elements: Vec<Element>,
163 key: DiffKey,
164}
165
166impl ChildrenExt for Canvas {
167 fn get_children(&mut self) -> &mut Vec<Element> {
168 &mut self.elements
169 }
170}
171
172impl KeyExt for Canvas {
173 fn write_key(&mut self) -> &mut DiffKey {
174 &mut self.key
175 }
176}
177
178impl EventHandlersExt for Canvas {
179 fn get_event_handlers(&mut self) -> &mut FxHashMap<EventName, EventHandlerType> {
180 &mut self.element.event_handlers
181 }
182}
183
184impl MaybeExt for Canvas {}
185
186impl From<Canvas> for Element {
187 fn from(value: Canvas) -> Self {
188 Element::Element {
189 key: value.key,
190 element: Rc::new(value.element),
191 elements: value.elements,
192 }
193 }
194}
195
196pub fn canvas(on_render: RenderCallback) -> Canvas {
200 Canvas::new(on_render)
201}
202
203impl Canvas {
204 pub fn new(on_render: RenderCallback) -> Self {
205 Self {
206 element: CanvasElement {
207 on_render,
208 layout: LayoutData::default(),
209 event_handlers: HashMap::default(),
210 effect: None,
211 },
212 elements: Vec::default(),
213 key: DiffKey::None,
214 }
215 }
216
217 pub fn try_downcast(element: &dyn ElementExt) -> Option<CanvasElement> {
218 (element as &dyn Any)
219 .downcast_ref::<CanvasElement>()
220 .cloned()
221 }
222}
223
224impl LayoutExt for Canvas {
225 fn get_layout(&mut self) -> &mut LayoutData {
226 &mut self.element.layout
227 }
228}
229
230impl ContainerExt for Canvas {}
231
232impl ContainerWithContentExt for Canvas {}