1use freya_engine::prelude::{
2 Canvas,
3 FontCollection,
4 FontMgr,
5};
6use freya_native_core::{
7 tags::TagName,
8 NodeId,
9};
10use torin::{
11 prelude::{
12 Area,
13 AreaModel,
14 CursorPoint,
15 LayoutNode,
16 },
17 torin::Torin,
18};
19
20use super::*;
21use crate::{
22 dom::{
23 DioxusNode,
24 ImagesCache,
25 },
26 states::{
27 StyleState,
28 TransformState,
29 ViewportState,
30 },
31};
32
33pub trait ElementUtils {
34 fn is_point_inside_area(
35 &self,
36 point: &CursorPoint,
37 _node_ref: &DioxusNode,
38 layout_node: &LayoutNode,
39 _scale_factor: f32,
40 ) -> bool {
41 layout_node.area.contains(point.to_f32())
42 }
43
44 fn clip(
45 &self,
46 _layout_node: &LayoutNode,
47 _node_ref: &DioxusNode,
48 _canvas: &Canvas,
49 _scale_factor: f32,
50 ) {
51 }
52
53 #[allow(clippy::too_many_arguments)]
54 fn render(
55 self,
56 layout_node: &LayoutNode,
57 node_ref: &DioxusNode,
58 canvas: &Canvas,
59 font_collection: &mut FontCollection,
60 font_manager: &FontMgr,
61 default_fonts: &[String],
62 images_cache: &mut ImagesCache,
63 scale_factor: f32,
64 );
65
66 fn element_drawing_area(
67 &self,
68 layout_node: &LayoutNode,
69 _node_ref: &DioxusNode,
70 _scale_factor: f32,
71 _node_style: &StyleState,
72 ) -> Area {
73 layout_node.visible_area()
75 }
76
77 #[allow(clippy::too_many_arguments)]
78 fn drawing_area_with_viewports(
79 &self,
80 layout_node: &LayoutNode,
81 node_ref: &DioxusNode,
82 layout: &Torin<NodeId>,
83 scale_factor: f32,
84 node_style: &StyleState,
85 node_viewports: &ViewportState,
86 transform_state: &TransformState,
87 ) -> Option<Area> {
88 let mut drawing_area = self.drawing_area(
89 layout_node,
90 node_ref,
91 layout,
92 scale_factor,
93 node_style,
94 transform_state,
95 );
96
97 for viewport_id in &node_viewports.viewports {
98 let viewport = layout.get(*viewport_id).unwrap().visible_area();
99 drawing_area.clip(&viewport);
100 if !viewport.intersects(&drawing_area) {
101 return None;
102 }
103 }
104
105 Some(drawing_area.inflate(1.0, 1.0))
107 }
108
109 fn drawing_area(
112 &self,
113 layout_node: &LayoutNode,
114 node_ref: &DioxusNode,
115 layout: &Torin<NodeId>,
116 scale_factor: f32,
117 node_style: &StyleState,
118 transform_state: &TransformState,
119 ) -> Area {
120 let mut drawing_area =
121 self.element_drawing_area(layout_node, node_ref, scale_factor, node_style);
122
123 for (id, scale_x, scale_y) in &transform_state.scales {
124 let layout_node = layout.get(*id).unwrap();
125 let center = layout_node.area.center();
126 drawing_area = drawing_area.translate(-center.to_vector());
127 drawing_area = drawing_area.scale(*scale_x, *scale_y);
128 drawing_area = drawing_area.translate(center.to_vector());
129 drawing_area = drawing_area.inflate(1.0, 1.0);
130 }
131
132 if !transform_state.rotations.is_empty() {
133 let area = layout_node.visible_area();
134 drawing_area.max_area_when_rotated(area.center())
135 } else {
136 drawing_area
137 }
138 }
139
140 #[inline]
145 fn element_needs_cached_area(&self, _node_ref: &DioxusNode, _style_state: &StyleState) -> bool {
146 false
147 }
148
149 #[inline]
150 fn needs_cached_area(
151 &self,
152 node_ref: &DioxusNode,
153 transform_state: &TransformState,
154 style_state: &StyleState,
155 ) -> bool {
156 let element_check = self.element_needs_cached_area(node_ref, style_state);
157
158 let rotate_effect = !transform_state.rotations.is_empty();
159
160 element_check || rotate_effect
161 }
162}
163
164pub trait ElementUtilsResolver {
165 fn utils(&self) -> Option<ElementWithUtils>;
166}
167
168impl ElementUtilsResolver for TagName {
169 #[inline]
170 fn utils(&self) -> Option<ElementWithUtils> {
171 match self {
172 TagName::Rect => Some(ElementWithUtils::Rect(RectElement)),
173 TagName::Svg => Some(ElementWithUtils::Svg(SvgElement)),
174 TagName::Paragraph => Some(ElementWithUtils::Paragraph(ParagraphElement)),
175 TagName::Image => Some(ElementWithUtils::Image(ImageElement)),
176 TagName::Label => Some(ElementWithUtils::Label(LabelElement)),
177 _ => None,
178 }
179 }
180}
181
182pub enum ElementWithUtils {
183 Rect(RectElement),
184 Svg(SvgElement),
185 Paragraph(ParagraphElement),
186 Image(ImageElement),
187 Label(LabelElement),
188}
189
190impl ElementUtils for ElementWithUtils {
191 fn clip(
192 &self,
193 layout_node: &LayoutNode,
194 node_ref: &DioxusNode,
195 canvas: &Canvas,
196 scale_factor: f32,
197 ) {
198 match self {
199 Self::Rect(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
200 Self::Svg(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
201 Self::Paragraph(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
202 Self::Image(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
203 Self::Label(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
204 }
205 }
206
207 fn is_point_inside_area(
208 &self,
209 point: &CursorPoint,
210 node_ref: &DioxusNode,
211 layout_node: &LayoutNode,
212 scale_factor: f32,
213 ) -> bool {
214 match self {
215 Self::Rect(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
216 Self::Svg(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
217 Self::Paragraph(el) => {
218 el.is_point_inside_area(point, node_ref, layout_node, scale_factor)
219 }
220 Self::Image(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
221 Self::Label(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
222 }
223 }
224
225 fn render(
226 self,
227 layout_node: &LayoutNode,
228 node_ref: &DioxusNode,
229 canvas: &Canvas,
230 font_collection: &mut FontCollection,
231 font_manager: &FontMgr,
232 default_fonts: &[String],
233 images_cache: &mut ImagesCache,
234 scale_factor: f32,
235 ) {
236 match self {
237 Self::Rect(el) => el.render(
238 layout_node,
239 node_ref,
240 canvas,
241 font_collection,
242 font_manager,
243 default_fonts,
244 images_cache,
245 scale_factor,
246 ),
247 Self::Svg(el) => el.render(
248 layout_node,
249 node_ref,
250 canvas,
251 font_collection,
252 font_manager,
253 default_fonts,
254 images_cache,
255 scale_factor,
256 ),
257 Self::Paragraph(el) => el.render(
258 layout_node,
259 node_ref,
260 canvas,
261 font_collection,
262 font_manager,
263 default_fonts,
264 images_cache,
265 scale_factor,
266 ),
267 Self::Image(el) => el.render(
268 layout_node,
269 node_ref,
270 canvas,
271 font_collection,
272 font_manager,
273 default_fonts,
274 images_cache,
275 scale_factor,
276 ),
277 Self::Label(el) => el.render(
278 layout_node,
279 node_ref,
280 canvas,
281 font_collection,
282 font_manager,
283 default_fonts,
284 images_cache,
285 scale_factor,
286 ),
287 }
288 }
289
290 fn drawing_area(
291 &self,
292 layout_node: &LayoutNode,
293 node_ref: &DioxusNode,
294 layout: &Torin<NodeId>,
295 scale_factor: f32,
296 node_style: &StyleState,
297 transform_state: &TransformState,
298 ) -> Area {
299 match self {
300 Self::Rect(el) => el.drawing_area(
301 layout_node,
302 node_ref,
303 layout,
304 scale_factor,
305 node_style,
306 transform_state,
307 ),
308 Self::Svg(el) => el.drawing_area(
309 layout_node,
310 node_ref,
311 layout,
312 scale_factor,
313 node_style,
314 transform_state,
315 ),
316 Self::Paragraph(el) => el.drawing_area(
317 layout_node,
318 node_ref,
319 layout,
320 scale_factor,
321 node_style,
322 transform_state,
323 ),
324 Self::Image(el) => el.drawing_area(
325 layout_node,
326 node_ref,
327 layout,
328 scale_factor,
329 node_style,
330 transform_state,
331 ),
332 Self::Label(el) => el.drawing_area(
333 layout_node,
334 node_ref,
335 layout,
336 scale_factor,
337 node_style,
338 transform_state,
339 ),
340 }
341 }
342
343 fn needs_cached_area(
344 &self,
345 node_ref: &DioxusNode,
346 transform_state: &TransformState,
347 style_state: &StyleState,
348 ) -> bool {
349 match self {
350 Self::Rect(el) => el.needs_cached_area(node_ref, transform_state, style_state),
351 Self::Svg(el) => el.needs_cached_area(node_ref, transform_state, style_state),
352 Self::Paragraph(el) => el.needs_cached_area(node_ref, transform_state, style_state),
353 Self::Image(el) => el.needs_cached_area(node_ref, transform_state, style_state),
354 Self::Label(el) => el.needs_cached_area(node_ref, transform_state, style_state),
355 }
356 }
357}