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 let scales_effect = !transform_state.scales.is_empty();
160
161 element_check || rotate_effect || scales_effect
162 }
163}
164
165pub trait ElementUtilsResolver {
166 fn utils(&self) -> Option<ElementWithUtils>;
167}
168
169impl ElementUtilsResolver for TagName {
170 #[inline]
171 fn utils(&self) -> Option<ElementWithUtils> {
172 match self {
173 TagName::Rect => Some(ElementWithUtils::Rect(RectElement)),
174 TagName::Svg => Some(ElementWithUtils::Svg(SvgElement)),
175 TagName::Paragraph => Some(ElementWithUtils::Paragraph(ParagraphElement)),
176 TagName::Image => Some(ElementWithUtils::Image(ImageElement)),
177 TagName::Label => Some(ElementWithUtils::Label(LabelElement)),
178 _ => None,
179 }
180 }
181}
182
183pub enum ElementWithUtils {
184 Rect(RectElement),
185 Svg(SvgElement),
186 Paragraph(ParagraphElement),
187 Image(ImageElement),
188 Label(LabelElement),
189}
190
191impl ElementUtils for ElementWithUtils {
192 fn clip(
193 &self,
194 layout_node: &LayoutNode,
195 node_ref: &DioxusNode,
196 canvas: &Canvas,
197 scale_factor: f32,
198 ) {
199 match self {
200 Self::Rect(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
201 Self::Svg(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
202 Self::Paragraph(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
203 Self::Image(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
204 Self::Label(el) => el.clip(layout_node, node_ref, canvas, scale_factor),
205 }
206 }
207
208 fn is_point_inside_area(
209 &self,
210 point: &CursorPoint,
211 node_ref: &DioxusNode,
212 layout_node: &LayoutNode,
213 scale_factor: f32,
214 ) -> bool {
215 match self {
216 Self::Rect(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
217 Self::Svg(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
218 Self::Paragraph(el) => {
219 el.is_point_inside_area(point, node_ref, layout_node, scale_factor)
220 }
221 Self::Image(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
222 Self::Label(el) => el.is_point_inside_area(point, node_ref, layout_node, scale_factor),
223 }
224 }
225
226 fn render(
227 self,
228 layout_node: &LayoutNode,
229 node_ref: &DioxusNode,
230 canvas: &Canvas,
231 font_collection: &mut FontCollection,
232 font_manager: &FontMgr,
233 default_fonts: &[String],
234 images_cache: &mut ImagesCache,
235 scale_factor: f32,
236 ) {
237 match self {
238 Self::Rect(el) => el.render(
239 layout_node,
240 node_ref,
241 canvas,
242 font_collection,
243 font_manager,
244 default_fonts,
245 images_cache,
246 scale_factor,
247 ),
248 Self::Svg(el) => el.render(
249 layout_node,
250 node_ref,
251 canvas,
252 font_collection,
253 font_manager,
254 default_fonts,
255 images_cache,
256 scale_factor,
257 ),
258 Self::Paragraph(el) => el.render(
259 layout_node,
260 node_ref,
261 canvas,
262 font_collection,
263 font_manager,
264 default_fonts,
265 images_cache,
266 scale_factor,
267 ),
268 Self::Image(el) => el.render(
269 layout_node,
270 node_ref,
271 canvas,
272 font_collection,
273 font_manager,
274 default_fonts,
275 images_cache,
276 scale_factor,
277 ),
278 Self::Label(el) => el.render(
279 layout_node,
280 node_ref,
281 canvas,
282 font_collection,
283 font_manager,
284 default_fonts,
285 images_cache,
286 scale_factor,
287 ),
288 }
289 }
290
291 fn drawing_area(
292 &self,
293 layout_node: &LayoutNode,
294 node_ref: &DioxusNode,
295 layout: &Torin<NodeId>,
296 scale_factor: f32,
297 node_style: &StyleState,
298 transform_state: &TransformState,
299 ) -> Area {
300 match self {
301 Self::Rect(el) => el.drawing_area(
302 layout_node,
303 node_ref,
304 layout,
305 scale_factor,
306 node_style,
307 transform_state,
308 ),
309 Self::Svg(el) => el.drawing_area(
310 layout_node,
311 node_ref,
312 layout,
313 scale_factor,
314 node_style,
315 transform_state,
316 ),
317 Self::Paragraph(el) => el.drawing_area(
318 layout_node,
319 node_ref,
320 layout,
321 scale_factor,
322 node_style,
323 transform_state,
324 ),
325 Self::Image(el) => el.drawing_area(
326 layout_node,
327 node_ref,
328 layout,
329 scale_factor,
330 node_style,
331 transform_state,
332 ),
333 Self::Label(el) => el.drawing_area(
334 layout_node,
335 node_ref,
336 layout,
337 scale_factor,
338 node_style,
339 transform_state,
340 ),
341 }
342 }
343
344 fn needs_cached_area(
345 &self,
346 node_ref: &DioxusNode,
347 transform_state: &TransformState,
348 style_state: &StyleState,
349 ) -> bool {
350 match self {
351 Self::Rect(el) => el.needs_cached_area(node_ref, transform_state, style_state),
352 Self::Svg(el) => el.needs_cached_area(node_ref, transform_state, style_state),
353 Self::Paragraph(el) => el.needs_cached_area(node_ref, transform_state, style_state),
354 Self::Image(el) => el.needs_cached_area(node_ref, transform_state, style_state),
355 Self::Label(el) => el.needs_cached_area(node_ref, transform_state, style_state),
356 }
357 }
358}