ferroui_base/visual_tree/
visual_extensions.rs1use super::TransformedBounds;
9use crate::input::IInputRoot;
10use crate::layout::{ILayoutManager, ILayoutRoot};
11use crate::rendering::IPresentationSource;
12use crate::media::{Geometry, GeometryHitTestResult};
13use crate::platform::IPlatformSettings;
14use crate::{Matrix, ObjectType, PixelPoint, Point, Rect, Ref, Visual};
15use std::rc::Rc;
16
17#[inline]
23fn render_transform(visual: &Visual) -> Option<Matrix> {
24 visual.render_transform().map(|transform| {
25 let origin = visual.render_transform_origin().to_pixels(visual.bounds().size());
26 let offset = Matrix::create_translation(origin.x, origin.y);
27 -offset * transform.value() * offset
28 })
29}
30
31#[inline]
35fn local_render_transform(visual: &Visual) -> Matrix {
36 let mut result = Matrix::IDENTITY;
37
38 if visual.has_mirror_transform() {
40 let mirror_matrix = Matrix::new(-1.0, 0.0, 0.0, 1.0, visual.bounds().width, 0.0);
41 result *= mirror_matrix;
42 }
43
44 if let Some(render_transform) = render_transform(visual) {
45 result *= render_transform;
46 }
47
48 result
49}
50
51pub(crate) fn local_transform(visual: &Visual) -> Matrix {
54 let mut result = local_render_transform(visual);
55 let top_left = visual.bounds().top_left();
56
57 if top_left != Point::default() {
58 result *= Matrix::create_translation(top_left.x, top_left.y);
59 }
60
61 result
62}
63
64pub struct VisualAncestors {
66 next: Option<Ref<Visual>>,
67}
68
69impl Iterator for VisualAncestors {
70 type Item = Ref<Visual>;
71
72 fn next(&mut self) -> Option<Ref<Visual>> {
73 let current = self.next.take()?;
74 self.next = current.visual_parent();
75 Some(current)
76 }
77}
78
79pub struct VisualDescendants {
81 stack: Vec<(Rc<Vec<Ref<Visual>>>, usize)>,
84 pending: Option<Ref<Visual>>,
85}
86
87impl Iterator for VisualDescendants {
88 type Item = Ref<Visual>;
89
90 fn next(&mut self) -> Option<Ref<Visual>> {
91 if let Some(pending) = self.pending.take() {
92 return Some(pending);
93 }
94
95 loop {
96 let (children, index) = self.stack.last_mut()?;
97 if *index >= children.len() {
98 self.stack.pop();
99 continue;
100 }
101
102 let child = children[*index].clone();
103 *index += 1;
104
105 if let Some(grandchildren) = child.visual_children_snapshot() {
106 if !grandchildren.is_empty() {
107 self.stack.push((grandchildren, 0));
108 }
109 }
110
111 return Some(child);
112 }
113 }
114}
115
116impl Visual {
117 pub fn calculate_distance_from_ancestor(&self, ancestor: Option<&Visual>) -> Option<usize> {
123 let mut result = 0;
124 let mut v = Some(self.to_ref());
125
126 while let Some(current) = v {
127 if ancestor.is_some_and(|a| std::ptr::eq::<Visual>(&*current, a)) {
128 return Some(result);
129 }
130 v = current.visual_parent();
131 result += 1;
132 }
133
134 None
135 }
136
137 pub fn calculate_distance_from_root(&self) -> usize {
139 let mut result = 0;
140 let mut v = self.visual_parent();
141
142 while let Some(current) = v {
143 v = current.visual_parent();
144 result += 1;
145 }
146
147 result
148 }
149
150 pub fn find_common_visual_ancestor(&self, target: &Visual) -> Option<Ref<Visual>> {
152 fn go_upwards(node: &mut Option<Ref<Visual>>, count: usize) {
153 for _ in 0..count {
154 *node = node.as_ref().and_then(|n| n.visual_parent());
155 }
156 }
157
158 let mut v = Some(self.to_ref());
159 let mut t = Some(target.to_ref());
160
161 let first_height = self.calculate_distance_from_root();
165 let second_height = target.calculate_distance_from_root();
166
167 if first_height > second_height {
168 go_upwards(&mut v, first_height - second_height);
169 } else {
170 go_upwards(&mut t, second_height - first_height);
171 }
172
173 if v == t {
174 return v;
175 }
176
177 while let (Some(first), Some(second)) = (&v, &t) {
178 let first_parent = first.visual_parent();
179 let second_parent = second.visual_parent();
180
181 if first_parent == second_parent {
182 return first_parent;
183 }
184
185 v = first_parent;
186 t = second_parent;
187 }
188
189 None
190 }
191
192 pub fn get_visual_ancestors(&self) -> VisualAncestors {
194 VisualAncestors { next: self.visual_parent() }
195 }
196
197 pub fn get_self_and_visual_ancestors(&self) -> VisualAncestors {
199 VisualAncestors { next: Some(self.to_ref()) }
200 }
201
202 pub fn find_ancestor_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
205 self.find_ancestor_of_type_where::<T>(include_self, |_| true)
206 }
207
208 pub fn find_ancestor_of_type_where<T: ObjectType>(
211 &self,
212 include_self: bool,
213 predicate: impl Fn(&T) -> bool,
214 ) -> Option<Ref<T>> {
215 let mut parent = if include_self { Some(self.to_ref()) } else { self.visual_parent() };
216
217 while let Some(current) = parent {
218 if let Some(result) = current.downcast_ref::<T>() {
219 if predicate(result) {
220 return current.downcast::<T>().ok();
221 }
222 }
223 parent = current.visual_parent();
224 }
225
226 None
227 }
228
229 pub fn find_descendant_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
232 self.find_descendant_of_type_where::<T>(include_self, |_| true)
233 }
234
235 pub fn find_descendant_of_type_where<T: ObjectType>(
238 &self,
239 include_self: bool,
240 predicate: impl Fn(&T) -> bool,
241 ) -> Option<Ref<T>> {
242 fn core<T: ObjectType>(visual: &Visual, predicate: &dyn Fn(&T) -> bool) -> Option<Ref<T>> {
243 let children = visual.visual_children_snapshot()?;
244
245 for child in children.iter() {
246 if let Some(result) = child.downcast_ref::<T>() {
247 if predicate(result) {
248 return child.cast::<T>();
249 }
250 }
251
252 if let Some(child_result) = core::<T>(child, predicate) {
253 return Some(child_result);
254 }
255 }
256
257 None
258 }
259
260 if include_self {
261 if let Some(result) = self.downcast_ref::<T>() {
262 if predicate(result) {
263 return self.to_ref().downcast::<T>().ok();
264 }
265 }
266 }
267
268 core::<T>(self, &predicate)
269 }
270
271 pub fn get_transformed_bounds(&self) -> Option<TransformedBounds> {
275 fn visit(visual: &Visual, clip: &mut Rect, transform: &mut Matrix) -> bool {
276 if !visual.is_visible() {
277 return false;
278 }
279
280 let bounds = Rect::from_size(visual.bounds().size());
282
283 let Some(parent) = visual.visual_parent() else {
286 *clip = bounds;
287 return true;
288 };
289
290 if !visit(&parent, clip, transform) {
293 return false;
294 }
295
296 let render_transform = local_render_transform(visual);
299 let position = visual.bounds().position();
300
301 *transform = render_transform * Matrix::create_translation(position.x, position.y) * *transform;
302
303 if visual.clip_to_bounds() {
305 let global_bounds = bounds.transform_to_aabb(*transform);
306 let clip_bounds = global_bounds.intersect(*clip);
307 *clip = clip.intersect(clip_bounds);
308 }
309
310 true
311 }
312
313 let mut clip = Rect::default();
314 let mut transform = Matrix::IDENTITY;
315
316 if visit(self, &mut clip, &mut transform) {
317 Some(TransformedBounds::new(Rect::from_size(self.bounds().size()), clip, transform))
318 } else {
319 None
320 }
321 }
322
323 pub fn get_visual_at(&self, p: Point) -> Option<Ref<Visual>> {
326 self.get_visual_at_filtered(p, &|x: &Visual| x.is_visible())
327 }
328
329 pub fn get_visual_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Option<Ref<Visual>> {
334 let source = self.presentation_source()?;
335 source.hit_tester().hit_test_first(p, self, Some(filter))
336 }
337
338 pub fn get_visual_at_geometry(&self, geometry: &Geometry) -> Option<GeometryHitTestResult> {
341 self.get_visual_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
342 }
343
344 pub fn get_visual_at_geometry_filtered(
350 &self,
351 geometry: &Geometry,
352 filter: &dyn Fn(&Visual) -> bool,
353 ) -> Option<GeometryHitTestResult> {
354 let source = self.presentation_source()?;
355 source.hit_tester().hit_test_first_geometry(geometry, self, Some(filter))
356 }
357
358 pub fn get_visuals_at(&self, p: Point) -> Vec<Ref<Visual>> {
361 self.get_visuals_at_filtered(p, &|x: &Visual| x.is_visible())
362 }
363
364 pub fn get_visuals_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Vec<Ref<Visual>> {
370 match self.presentation_source() {
371 Some(source) => source.hit_tester().hit_test(p, self, Some(filter)),
372 None => Vec::new(),
373 }
374 }
375
376 pub fn get_visuals_at_geometry(&self, geometry: &Geometry) -> Vec<GeometryHitTestResult> {
380 self.get_visuals_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
381 }
382
383 pub fn get_visuals_at_geometry_filtered(
390 &self,
391 geometry: &Geometry,
392 filter: &dyn Fn(&Visual) -> bool,
393 ) -> Vec<GeometryHitTestResult> {
394 match self.presentation_source() {
395 Some(source) => source.hit_tester().hit_test_geometry(geometry, self, Some(filter)),
396 None => Vec::new(),
397 }
398 }
399
400 pub fn get_visual_children(&self) -> Rc<Vec<Ref<Visual>>> {
402 self.visual_children_snapshot().unwrap_or_default()
403 }
404
405 pub fn get_visual_descendants(&self) -> VisualDescendants {
408 let mut stack = Vec::new();
409 if let Some(children) = self.visual_children_snapshot() {
410 if !children.is_empty() {
411 stack.push((children, 0));
412 }
413 }
414 VisualDescendants { stack, pending: None }
415 }
416
417 pub fn get_self_and_visual_descendants(&self) -> VisualDescendants {
420 let mut result = self.get_visual_descendants();
421 result.pending = Some(self.to_ref());
422 result
423 }
424
425 pub fn get_visual_parent(&self) -> Option<Ref<Visual>> {
427 self.visual_parent()
428 }
429
430 pub fn get_visual_parent_of_type<T: ObjectType>(&self) -> Option<Ref<T>> {
432 self.visual_parent().and_then(|parent| parent.downcast::<T>().ok())
433 }
434
435 pub fn get_presentation_source(&self) -> Option<Rc<dyn IPresentationSource>> {
437 self.presentation_source()
438 }
439
440 pub fn get_visual_root(&self) -> Option<Ref<Visual>> {
443 self.presentation_source().and_then(|source| source.root_visual())
444 }
445
446 pub fn get_layout_root(&self) -> Option<Rc<dyn ILayoutRoot>> {
448 self.presentation_source().map(|source| source.layout_root())
449 }
450
451 pub fn get_layout_manager(&self) -> Option<Rc<dyn ILayoutManager>> {
454 self.presentation_source().map(|source| source.layout_root().layout_manager())
455 }
456
457 pub fn get_input_root(&self) -> Option<Rc<dyn IInputRoot>> {
459 self.presentation_source().map(|source| source.input_root())
460 }
461
462 pub fn get_platform_settings(&self) -> Option<Rc<dyn IPlatformSettings>> {
464 self.presentation_source().and_then(|source| source.platform_settings())
465 }
466
467 pub fn is_visual_ancestor_of(&self, target: &Visual) -> bool {
469 let mut current = target.visual_parent();
470
471 while let Some(c) = current {
472 if std::ptr::eq::<Visual>(&*c, self) {
473 return true;
474 }
475 current = c.visual_parent();
476 }
477
478 false
479 }
480
481 pub fn sort_by_z_index(elements: &[Ref<Visual>]) -> Vec<Ref<Visual>> {
485 let mut indexed: Vec<(i32, usize)> =
486 elements.iter().enumerate().map(|(index, element)| (element.z_index(), index)).collect();
487 indexed.sort_by(|x, y| y.0.cmp(&x.0).then(y.1.cmp(&x.1)));
488 indexed.into_iter().map(|(_, index)| elements[index].clone()).collect()
489 }
490
491 pub fn point_to_client(&self, point: PixelPoint) -> Point {
497 let (source, root) = self.source_and_root();
498 let root_point = source.point_to_client(point).unwrap_or_default();
499 root.translate_point(root_point, self).expect("the root is an ancestor of the visual")
500 }
501
502 pub fn point_to_screen(&self, point: Point) -> PixelPoint {
506 let (source, root) = self.source_and_root();
507 let p = self.translate_point(point, &root).expect("the root is an ancestor of the visual");
508 source.point_to_screen(p).unwrap_or_default()
509 }
510
511 pub fn transform_to_visual(&self, to: &Visual) -> Option<Matrix> {
515 let common = self.find_common_visual_ancestor(to)?;
516 let this_offset = Self::get_offset_from(&common, self);
517 let that_offset = Self::get_offset_from(&common, to);
518 let that_offset_inverted = that_offset.try_invert()?;
519
520 Some(that_offset_inverted * this_offset)
521 }
522
523 pub fn translate_point(&self, point: Point, relative_to: &Visual) -> Option<Point> {
527 self.transform_to_visual(relative_to).map(|transform| point.transform(transform))
528 }
529
530 fn source_and_root(&self) -> (Rc<dyn crate::rendering::IPresentationSource>, Ref<Visual>) {
531 let source = self.presentation_source();
532 let root = source.as_ref().and_then(|s| s.root_visual());
533 match (source, root) {
534 (Some(source), Some(root)) => (source, root),
535 _ => panic!("Visual does not belong to a visual tree."),
536 }
537 }
538
539 fn get_offset_from(ancestor: &Visual, visual: &Visual) -> Matrix {
541 let mut result = Matrix::IDENTITY;
542 let mut v = visual.to_ref();
543
544 while !std::ptr::eq::<Visual>(&*v, ancestor) {
545 result *= local_transform(&v);
546
547 v = match v.visual_parent() {
548 Some(parent) => parent,
549 None => panic!("'visual' is not a descendant of 'ancestor'."),
550 };
551 }
552
553 result
554 }
555}