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 if !visual.has_render_transform() {
25 return None;
26 }
27 visual.render_transform().map(|transform| {
28 let origin = visual.render_transform_origin().to_pixels(visual.bounds().size());
29 let offset = Matrix::create_translation(origin.x, origin.y);
30 -offset * transform.value() * offset
31 })
32}
33
34#[inline]
38fn local_render_transform(visual: &Visual) -> Matrix {
39 let mut result = Matrix::IDENTITY;
40
41 if visual.has_mirror_transform() {
43 let mirror_matrix = Matrix::new(-1.0, 0.0, 0.0, 1.0, visual.bounds().width, 0.0);
44 result *= mirror_matrix;
45 }
46
47 if let Some(render_transform) = render_transform(visual) {
48 result *= render_transform;
49 }
50
51 result
52}
53
54pub(crate) fn local_transform(visual: &Visual) -> Matrix {
57 let mut result = local_render_transform(visual);
58 let top_left = visual.bounds().top_left();
59
60 if top_left != Point::default() {
61 result *= Matrix::create_translation(top_left.x, top_left.y);
62 }
63
64 result
65}
66
67pub struct VisualAncestors {
69 next: Option<Ref<Visual>>,
70}
71
72impl Iterator for VisualAncestors {
73 type Item = Ref<Visual>;
74
75 fn next(&mut self) -> Option<Ref<Visual>> {
76 let current = self.next.take()?;
77 self.next = current.visual_parent();
78 Some(current)
79 }
80}
81
82pub struct VisualDescendants {
84 stack: Vec<(Rc<Vec<Ref<Visual>>>, usize)>,
87 pending: Option<Ref<Visual>>,
88}
89
90impl Iterator for VisualDescendants {
91 type Item = Ref<Visual>;
92
93 fn next(&mut self) -> Option<Ref<Visual>> {
94 if let Some(pending) = self.pending.take() {
95 return Some(pending);
96 }
97
98 loop {
99 let (children, index) = self.stack.last_mut()?;
100 if *index >= children.len() {
101 self.stack.pop();
102 continue;
103 }
104
105 let child = children[*index].clone();
106 *index += 1;
107
108 if let Some(grandchildren) = child.visual_children_snapshot() {
109 if !grandchildren.is_empty() {
110 self.stack.push((grandchildren, 0));
111 }
112 }
113
114 return Some(child);
115 }
116 }
117}
118
119impl Visual {
120 pub fn calculate_distance_from_ancestor(&self, ancestor: Option<&Visual>) -> Option<usize> {
126 let mut result = 0;
127 let mut v = Some(self.to_ref());
128
129 while let Some(current) = v {
130 if ancestor.is_some_and(|a| std::ptr::eq::<Visual>(&*current, a)) {
131 return Some(result);
132 }
133 v = current.visual_parent();
134 result += 1;
135 }
136
137 None
138 }
139
140 pub fn calculate_distance_from_root(&self) -> usize {
142 let mut result = 0;
143 let mut v = self.visual_parent();
144
145 while let Some(current) = v {
146 v = current.visual_parent();
147 result += 1;
148 }
149
150 result
151 }
152
153 pub fn find_common_visual_ancestor(&self, target: &Visual) -> Option<Ref<Visual>> {
155 fn go_upwards(node: &mut Option<Ref<Visual>>, count: usize) {
156 for _ in 0..count {
157 *node = node.as_ref().and_then(|n| n.visual_parent());
158 }
159 }
160
161 let mut v = Some(self.to_ref());
162 let mut t = Some(target.to_ref());
163
164 let first_height = self.calculate_distance_from_root();
168 let second_height = target.calculate_distance_from_root();
169
170 if first_height > second_height {
171 go_upwards(&mut v, first_height - second_height);
172 } else {
173 go_upwards(&mut t, second_height - first_height);
174 }
175
176 if v == t {
177 return v;
178 }
179
180 while let (Some(first), Some(second)) = (&v, &t) {
181 let first_parent = first.visual_parent();
182 let second_parent = second.visual_parent();
183
184 if first_parent == second_parent {
185 return first_parent;
186 }
187
188 v = first_parent;
189 t = second_parent;
190 }
191
192 None
193 }
194
195 pub fn get_visual_ancestors(&self) -> VisualAncestors {
197 VisualAncestors { next: self.visual_parent() }
198 }
199
200 pub fn get_self_and_visual_ancestors(&self) -> VisualAncestors {
202 VisualAncestors { next: Some(self.to_ref()) }
203 }
204
205 pub fn find_ancestor_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
208 self.find_ancestor_of_type_where::<T>(include_self, |_| true)
209 }
210
211 pub fn find_ancestor_of_type_where<T: ObjectType>(
214 &self,
215 include_self: bool,
216 predicate: impl Fn(&T) -> bool,
217 ) -> Option<Ref<T>> {
218 let mut parent = if include_self { Some(self.to_ref()) } else { self.visual_parent() };
219
220 while let Some(current) = parent {
221 if let Some(result) = current.downcast_ref::<T>() {
222 if predicate(result) {
223 return current.downcast::<T>().ok();
224 }
225 }
226 parent = current.visual_parent();
227 }
228
229 None
230 }
231
232 pub fn find_descendant_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
235 self.find_descendant_of_type_where::<T>(include_self, |_| true)
236 }
237
238 pub fn find_descendant_of_type_where<T: ObjectType>(
241 &self,
242 include_self: bool,
243 predicate: impl Fn(&T) -> bool,
244 ) -> Option<Ref<T>> {
245 fn core<T: ObjectType>(visual: &Visual, predicate: &dyn Fn(&T) -> bool) -> Option<Ref<T>> {
246 let children = visual.visual_children_snapshot()?;
247
248 for child in children.iter() {
249 if let Some(result) = child.downcast_ref::<T>() {
250 if predicate(result) {
251 return child.cast::<T>();
252 }
253 }
254
255 if let Some(child_result) = core::<T>(child, predicate) {
256 return Some(child_result);
257 }
258 }
259
260 None
261 }
262
263 if include_self {
264 if let Some(result) = self.downcast_ref::<T>() {
265 if predicate(result) {
266 return self.to_ref().downcast::<T>().ok();
267 }
268 }
269 }
270
271 core::<T>(self, &predicate)
272 }
273
274 pub fn get_transformed_bounds(&self) -> Option<TransformedBounds> {
278 fn visit(visual: &Visual, clip: &mut Rect, transform: &mut Matrix) -> bool {
279 if !visual.is_visible() {
280 return false;
281 }
282
283 let bounds = Rect::from_size(visual.bounds().size());
285
286 let Some(parent) = visual.visual_parent() else {
289 *clip = bounds;
290 return true;
291 };
292
293 if !visit(&parent, clip, transform) {
296 return false;
297 }
298
299 let render_transform = local_render_transform(visual);
302 let position = visual.bounds().position();
303
304 *transform = render_transform * Matrix::create_translation(position.x, position.y) * *transform;
305
306 if visual.clip_to_bounds() {
308 let global_bounds = bounds.transform_to_aabb(*transform);
309 let clip_bounds = global_bounds.intersect(*clip);
310 *clip = clip.intersect(clip_bounds);
311 }
312
313 true
314 }
315
316 let mut clip = Rect::default();
317 let mut transform = Matrix::IDENTITY;
318
319 if visit(self, &mut clip, &mut transform) {
320 Some(TransformedBounds::new(Rect::from_size(self.bounds().size()), clip, transform))
321 } else {
322 None
323 }
324 }
325
326 pub fn get_visual_at(&self, p: Point) -> Option<Ref<Visual>> {
329 self.get_visual_at_filtered(p, &|x: &Visual| x.is_visible())
330 }
331
332 pub fn get_visual_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Option<Ref<Visual>> {
337 let source = self.presentation_source()?;
338 source.hit_tester().hit_test_first(p, self, Some(filter))
339 }
340
341 pub fn get_visual_at_geometry(&self, geometry: &Geometry) -> Option<GeometryHitTestResult> {
344 self.get_visual_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
345 }
346
347 pub fn get_visual_at_geometry_filtered(
353 &self,
354 geometry: &Geometry,
355 filter: &dyn Fn(&Visual) -> bool,
356 ) -> Option<GeometryHitTestResult> {
357 let source = self.presentation_source()?;
358 source.hit_tester().hit_test_first_geometry(geometry, self, Some(filter))
359 }
360
361 pub fn get_visuals_at(&self, p: Point) -> Vec<Ref<Visual>> {
364 self.get_visuals_at_filtered(p, &|x: &Visual| x.is_visible())
365 }
366
367 pub fn get_visuals_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Vec<Ref<Visual>> {
373 match self.presentation_source() {
374 Some(source) => source.hit_tester().hit_test(p, self, Some(filter)),
375 None => Vec::new(),
376 }
377 }
378
379 pub fn get_visuals_at_geometry(&self, geometry: &Geometry) -> Vec<GeometryHitTestResult> {
383 self.get_visuals_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
384 }
385
386 pub fn get_visuals_at_geometry_filtered(
393 &self,
394 geometry: &Geometry,
395 filter: &dyn Fn(&Visual) -> bool,
396 ) -> Vec<GeometryHitTestResult> {
397 match self.presentation_source() {
398 Some(source) => source.hit_tester().hit_test_geometry(geometry, self, Some(filter)),
399 None => Vec::new(),
400 }
401 }
402
403 pub fn get_visual_children(&self) -> Rc<Vec<Ref<Visual>>> {
405 self.visual_children_snapshot().unwrap_or_default()
406 }
407
408 pub fn get_visual_descendants(&self) -> VisualDescendants {
411 let mut stack = Vec::new();
412 if let Some(children) = self.visual_children_snapshot() {
413 if !children.is_empty() {
414 stack.push((children, 0));
415 }
416 }
417 VisualDescendants { stack, pending: None }
418 }
419
420 pub fn get_self_and_visual_descendants(&self) -> VisualDescendants {
423 let mut result = self.get_visual_descendants();
424 result.pending = Some(self.to_ref());
425 result
426 }
427
428 pub fn get_visual_parent(&self) -> Option<Ref<Visual>> {
430 self.visual_parent()
431 }
432
433 pub fn get_visual_parent_of_type<T: ObjectType>(&self) -> Option<Ref<T>> {
435 self.visual_parent().and_then(|parent| parent.downcast::<T>().ok())
436 }
437
438 pub fn get_presentation_source(&self) -> Option<Rc<dyn IPresentationSource>> {
440 self.presentation_source()
441 }
442
443 pub fn get_visual_root(&self) -> Option<Ref<Visual>> {
446 self.presentation_source().and_then(|source| source.root_visual())
447 }
448
449 pub fn get_layout_root(&self) -> Option<Rc<dyn ILayoutRoot>> {
451 self.presentation_source().map(|source| source.layout_root())
452 }
453
454 pub fn get_layout_manager(&self) -> Option<Rc<dyn ILayoutManager>> {
457 self.presentation_source().map(|source| source.layout_root().layout_manager())
458 }
459
460 pub fn get_input_root(&self) -> Option<Rc<dyn IInputRoot>> {
462 self.presentation_source().map(|source| source.input_root())
463 }
464
465 pub fn get_platform_settings(&self) -> Option<Rc<dyn IPlatformSettings>> {
467 self.presentation_source().and_then(|source| source.platform_settings())
468 }
469
470 pub fn is_visual_ancestor_of(&self, target: &Visual) -> bool {
472 let mut current = target.visual_parent();
473
474 while let Some(c) = current {
475 if std::ptr::eq::<Visual>(&*c, self) {
476 return true;
477 }
478 current = c.visual_parent();
479 }
480
481 false
482 }
483
484 pub fn sort_by_z_index(elements: &[Ref<Visual>]) -> Vec<Ref<Visual>> {
488 let mut indexed: Vec<(i32, usize)> =
489 elements.iter().enumerate().map(|(index, element)| (element.z_index(), index)).collect();
490 indexed.sort_by(|x, y| y.0.cmp(&x.0).then(y.1.cmp(&x.1)));
491 indexed.into_iter().map(|(_, index)| elements[index].clone()).collect()
492 }
493
494 pub fn point_to_client(&self, point: PixelPoint) -> Point {
500 let (source, root) = self.source_and_root();
501 let root_point = source.point_to_client(point).unwrap_or_default();
502 root.translate_point(root_point, self).expect("the root is an ancestor of the visual")
503 }
504
505 pub fn point_to_screen(&self, point: Point) -> PixelPoint {
509 let (source, root) = self.source_and_root();
510 let p = self.translate_point(point, &root).expect("the root is an ancestor of the visual");
511 source.point_to_screen(p).unwrap_or_default()
512 }
513
514 pub fn transform_to_visual(&self, to: &Visual) -> Option<Matrix> {
518 if let Some(offset) = Self::try_get_offset_from_ancestor(to, self) {
524 return Some(offset);
525 }
526
527 let common = self.find_common_visual_ancestor(to)?;
528 let this_offset = Self::get_offset_from(&common, self);
529 let that_offset = Self::get_offset_from(&common, to);
530 let that_offset_inverted = that_offset.try_invert()?;
531
532 Some(that_offset_inverted * this_offset)
533 }
534
535 pub fn translate_point(&self, point: Point, relative_to: &Visual) -> Option<Point> {
539 self.transform_to_visual(relative_to).map(|transform| point.transform(transform))
540 }
541
542 fn source_and_root(&self) -> (Rc<dyn crate::rendering::IPresentationSource>, Ref<Visual>) {
543 let source = self.presentation_source();
544 let root = source.as_ref().and_then(|s| s.root_visual());
545 match (source, root) {
546 (Some(source), Some(root)) => (source, root),
547 _ => panic!("Visual does not belong to a visual tree."),
548 }
549 }
550
551 fn try_get_offset_from_ancestor(ancestor: &Visual, visual: &Visual) -> Option<Matrix> {
554 let mut result = Matrix::IDENTITY;
555 let mut v = visual.to_ref();
556
557 while !std::ptr::eq::<Visual>(&*v, ancestor) {
558 result *= local_transform(&v);
559 v = v.visual_parent()?;
560 }
561
562 Some(result)
563 }
564
565 fn get_offset_from(ancestor: &Visual, visual: &Visual) -> Matrix {
567 let mut result = Matrix::IDENTITY;
568 let mut v = visual.to_ref();
569
570 while !std::ptr::eq::<Visual>(&*v, ancestor) {
571 result *= local_transform(&v);
572
573 v = match v.visual_parent() {
574 Some(parent) => parent,
575 None => panic!("'visual' is not a descendant of 'ancestor'."),
576 };
577 }
578
579 result
580 }
581}