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 if let Some(manipulation) = visual.manipulation_transform() {
53 result *= manipulation;
54 }
55
56 result
57}
58
59pub(crate) fn local_transform(visual: &Visual) -> Matrix {
62 let mut result = local_render_transform(visual);
63 let top_left = visual.bounds().top_left();
64
65 if top_left != Point::default() {
66 result *= Matrix::create_translation(top_left.x, top_left.y);
67 }
68
69 result
70}
71
72pub struct VisualAncestors {
74 next: Option<Ref<Visual>>,
75}
76
77impl Iterator for VisualAncestors {
78 type Item = Ref<Visual>;
79
80 fn next(&mut self) -> Option<Ref<Visual>> {
81 let current = self.next.take()?;
82 self.next = current.visual_parent();
83 Some(current)
84 }
85}
86
87pub struct VisualDescendants {
89 stack: Vec<(Rc<Vec<Ref<Visual>>>, usize)>,
92 pending: Option<Ref<Visual>>,
93}
94
95impl Iterator for VisualDescendants {
96 type Item = Ref<Visual>;
97
98 fn next(&mut self) -> Option<Ref<Visual>> {
99 if let Some(pending) = self.pending.take() {
100 return Some(pending);
101 }
102
103 loop {
104 let (children, index) = self.stack.last_mut()?;
105 if *index >= children.len() {
106 self.stack.pop();
107 continue;
108 }
109
110 let child = children[*index].clone();
111 *index += 1;
112
113 if let Some(grandchildren) = child.visual_children_snapshot() {
114 if !grandchildren.is_empty() {
115 self.stack.push((grandchildren, 0));
116 }
117 }
118
119 return Some(child);
120 }
121 }
122}
123
124impl Visual {
125 pub fn calculate_distance_from_ancestor(&self, ancestor: Option<&Visual>) -> Option<usize> {
131 let mut result = 0;
132 let mut v = Some(self.to_ref());
133
134 while let Some(current) = v {
135 if ancestor.is_some_and(|a| std::ptr::eq::<Visual>(&*current, a)) {
136 return Some(result);
137 }
138 v = current.visual_parent();
139 result += 1;
140 }
141
142 None
143 }
144
145 pub fn calculate_distance_from_root(&self) -> usize {
147 let mut result = 0;
148 let mut v = self.visual_parent();
149
150 while let Some(current) = v {
151 v = current.visual_parent();
152 result += 1;
153 }
154
155 result
156 }
157
158 pub fn find_common_visual_ancestor(&self, target: &Visual) -> Option<Ref<Visual>> {
160 fn go_upwards(node: &mut Option<Ref<Visual>>, count: usize) {
161 for _ in 0..count {
162 *node = node.as_ref().and_then(|n| n.visual_parent());
163 }
164 }
165
166 let mut v = Some(self.to_ref());
167 let mut t = Some(target.to_ref());
168
169 let first_height = self.calculate_distance_from_root();
173 let second_height = target.calculate_distance_from_root();
174
175 if first_height > second_height {
176 go_upwards(&mut v, first_height - second_height);
177 } else {
178 go_upwards(&mut t, second_height - first_height);
179 }
180
181 if v == t {
182 return v;
183 }
184
185 while let (Some(first), Some(second)) = (&v, &t) {
186 let first_parent = first.visual_parent();
187 let second_parent = second.visual_parent();
188
189 if first_parent == second_parent {
190 return first_parent;
191 }
192
193 v = first_parent;
194 t = second_parent;
195 }
196
197 None
198 }
199
200 pub fn get_visual_ancestors(&self) -> VisualAncestors {
202 VisualAncestors { next: self.visual_parent() }
203 }
204
205 pub fn get_self_and_visual_ancestors(&self) -> VisualAncestors {
207 VisualAncestors { next: Some(self.to_ref()) }
208 }
209
210 pub fn find_ancestor_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
213 self.find_ancestor_of_type_where::<T>(include_self, |_| true)
214 }
215
216 pub fn find_ancestor_of_type_where<T: ObjectType>(
219 &self,
220 include_self: bool,
221 predicate: impl Fn(&T) -> bool,
222 ) -> Option<Ref<T>> {
223 let mut parent = if include_self { Some(self.to_ref()) } else { self.visual_parent() };
224
225 while let Some(current) = parent {
226 if let Some(result) = current.downcast_ref::<T>() {
227 if predicate(result) {
228 return current.downcast::<T>().ok();
229 }
230 }
231 parent = current.visual_parent();
232 }
233
234 None
235 }
236
237 pub fn find_descendant_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
240 self.find_descendant_of_type_where::<T>(include_self, |_| true)
241 }
242
243 pub fn find_descendant_of_type_where<T: ObjectType>(
246 &self,
247 include_self: bool,
248 predicate: impl Fn(&T) -> bool,
249 ) -> Option<Ref<T>> {
250 fn core<T: ObjectType>(visual: &Visual, predicate: &dyn Fn(&T) -> bool) -> Option<Ref<T>> {
251 let children = visual.visual_children_snapshot()?;
252
253 for child in children.iter() {
254 if let Some(result) = child.downcast_ref::<T>() {
255 if predicate(result) {
256 return child.cast::<T>();
257 }
258 }
259
260 if let Some(child_result) = core::<T>(child, predicate) {
261 return Some(child_result);
262 }
263 }
264
265 None
266 }
267
268 if include_self {
269 if let Some(result) = self.downcast_ref::<T>() {
270 if predicate(result) {
271 return self.to_ref().downcast::<T>().ok();
272 }
273 }
274 }
275
276 core::<T>(self, &predicate)
277 }
278
279 pub fn get_transformed_bounds(&self) -> Option<TransformedBounds> {
283 fn visit(visual: &Visual, clip: &mut Rect, transform: &mut Matrix) -> bool {
284 if !visual.is_visible() {
285 return false;
286 }
287
288 let bounds = Rect::from_size(visual.bounds().size());
290
291 let Some(parent) = visual.visual_parent() else {
294 *clip = bounds;
295 return true;
296 };
297
298 if !visit(&parent, clip, transform) {
301 return false;
302 }
303
304 let render_transform = local_render_transform(visual);
307 let position = visual.bounds().position();
308
309 *transform = render_transform * Matrix::create_translation(position.x, position.y) * *transform;
310
311 if visual.clip_to_bounds() {
313 let global_bounds = bounds.transform_to_aabb(*transform);
314 let clip_bounds = global_bounds.intersect(*clip);
315 *clip = clip.intersect(clip_bounds);
316 }
317
318 true
319 }
320
321 let mut clip = Rect::default();
322 let mut transform = Matrix::IDENTITY;
323
324 if visit(self, &mut clip, &mut transform) {
325 Some(TransformedBounds::new(Rect::from_size(self.bounds().size()), clip, transform))
326 } else {
327 None
328 }
329 }
330
331 pub fn get_visual_at(&self, p: Point) -> Option<Ref<Visual>> {
334 self.get_visual_at_filtered(p, &|x: &Visual| x.is_visible())
335 }
336
337 pub fn get_visual_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Option<Ref<Visual>> {
342 let source = self.presentation_source()?;
343 source.hit_tester().hit_test_first(p, self, Some(filter))
344 }
345
346 pub fn get_visual_at_geometry(&self, geometry: &Geometry) -> Option<GeometryHitTestResult> {
349 self.get_visual_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
350 }
351
352 pub fn get_visual_at_geometry_filtered(
358 &self,
359 geometry: &Geometry,
360 filter: &dyn Fn(&Visual) -> bool,
361 ) -> Option<GeometryHitTestResult> {
362 let source = self.presentation_source()?;
363 source.hit_tester().hit_test_first_geometry(geometry, self, Some(filter))
364 }
365
366 pub fn get_visuals_at(&self, p: Point) -> Vec<Ref<Visual>> {
369 self.get_visuals_at_filtered(p, &|x: &Visual| x.is_visible())
370 }
371
372 pub fn get_visuals_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Vec<Ref<Visual>> {
378 match self.presentation_source() {
379 Some(source) => source.hit_tester().hit_test(p, self, Some(filter)),
380 None => Vec::new(),
381 }
382 }
383
384 pub fn get_visuals_at_geometry(&self, geometry: &Geometry) -> Vec<GeometryHitTestResult> {
388 self.get_visuals_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
389 }
390
391 pub fn get_visuals_at_geometry_filtered(
398 &self,
399 geometry: &Geometry,
400 filter: &dyn Fn(&Visual) -> bool,
401 ) -> Vec<GeometryHitTestResult> {
402 match self.presentation_source() {
403 Some(source) => source.hit_tester().hit_test_geometry(geometry, self, Some(filter)),
404 None => Vec::new(),
405 }
406 }
407
408 pub fn get_visual_children(&self) -> Rc<Vec<Ref<Visual>>> {
410 self.visual_children_snapshot().unwrap_or_default()
411 }
412
413 pub fn get_visual_descendants(&self) -> VisualDescendants {
416 let mut stack = Vec::new();
417 if let Some(children) = self.visual_children_snapshot() {
418 if !children.is_empty() {
419 stack.push((children, 0));
420 }
421 }
422 VisualDescendants { stack, pending: None }
423 }
424
425 pub fn get_self_and_visual_descendants(&self) -> VisualDescendants {
428 let mut result = self.get_visual_descendants();
429 result.pending = Some(self.to_ref());
430 result
431 }
432
433 pub fn get_visual_parent(&self) -> Option<Ref<Visual>> {
435 self.visual_parent()
436 }
437
438 pub fn get_visual_parent_of_type<T: ObjectType>(&self) -> Option<Ref<T>> {
440 self.visual_parent().and_then(|parent| parent.downcast::<T>().ok())
441 }
442
443 pub fn get_presentation_source(&self) -> Option<Rc<dyn IPresentationSource>> {
445 self.presentation_source()
446 }
447
448 pub fn get_visual_root(&self) -> Option<Ref<Visual>> {
451 self.presentation_source().and_then(|source| source.root_visual())
452 }
453
454 pub fn get_layout_root(&self) -> Option<Rc<dyn ILayoutRoot>> {
456 self.presentation_source().map(|source| source.layout_root())
457 }
458
459 pub fn get_layout_manager(&self) -> Option<Rc<dyn ILayoutManager>> {
462 self.presentation_source().map(|source| source.layout_root().layout_manager())
463 }
464
465 pub fn get_input_root(&self) -> Option<Rc<dyn IInputRoot>> {
467 self.presentation_source().map(|source| source.input_root())
468 }
469
470 pub fn get_platform_settings(&self) -> Option<Rc<dyn IPlatformSettings>> {
472 self.presentation_source().and_then(|source| source.platform_settings())
473 }
474
475 pub fn is_visual_ancestor_of(&self, target: &Visual) -> bool {
477 let mut current = target.visual_parent();
478
479 while let Some(c) = current {
480 if std::ptr::eq::<Visual>(&*c, self) {
481 return true;
482 }
483 current = c.visual_parent();
484 }
485
486 false
487 }
488
489 pub fn sort_by_z_index(elements: &[Ref<Visual>]) -> Vec<Ref<Visual>> {
493 let mut indexed: Vec<(i32, usize)> =
494 elements.iter().enumerate().map(|(index, element)| (element.z_index(), index)).collect();
495 indexed.sort_by(|x, y| y.0.cmp(&x.0).then(y.1.cmp(&x.1)));
496 indexed.into_iter().map(|(_, index)| elements[index].clone()).collect()
497 }
498
499 pub fn point_to_client(&self, point: PixelPoint) -> Point {
505 let (source, root) = self.source_and_root();
506 let root_point = source.point_to_client(point).unwrap_or_default();
507 root.translate_point(root_point, self).expect("the root is an ancestor of the visual")
508 }
509
510 pub fn point_to_screen(&self, point: Point) -> PixelPoint {
514 let (source, root) = self.source_and_root();
515 let p = self.translate_point(point, &root).expect("the root is an ancestor of the visual");
516 source.point_to_screen(p).unwrap_or_default()
517 }
518
519 pub fn transform_to_visual(&self, to: &Visual) -> Option<Matrix> {
523 if let Some(offset) = Self::try_get_offset_from_ancestor(to, self) {
529 return Some(offset);
530 }
531
532 let common = self.find_common_visual_ancestor(to)?;
533 let this_offset = Self::get_offset_from(&common, self);
534 let that_offset = Self::get_offset_from(&common, to);
535 let that_offset_inverted = that_offset.try_invert()?;
536
537 Some(that_offset_inverted * this_offset)
538 }
539
540 pub fn translate_point(&self, point: Point, relative_to: &Visual) -> Option<Point> {
544 self.transform_to_visual(relative_to).map(|transform| point.transform(transform))
545 }
546
547 fn source_and_root(&self) -> (Rc<dyn crate::rendering::IPresentationSource>, Ref<Visual>) {
548 let source = self.presentation_source();
549 let root = source.as_ref().and_then(|s| s.root_visual());
550 match (source, root) {
551 (Some(source), Some(root)) => (source, root),
552 _ => panic!("Visual does not belong to a visual tree."),
553 }
554 }
555
556 fn try_get_offset_from_ancestor(ancestor: &Visual, visual: &Visual) -> Option<Matrix> {
559 let mut result = Matrix::IDENTITY;
560 let mut v = visual.to_ref();
561
562 while !std::ptr::eq::<Visual>(&*v, ancestor) {
563 result *= local_transform(&v);
564 v = v.visual_parent()?;
565 }
566
567 Some(result)
568 }
569
570 fn get_offset_from(ancestor: &Visual, visual: &Visual) -> Matrix {
572 let mut result = Matrix::IDENTITY;
573 let mut v = visual.to_ref();
574
575 while !std::ptr::eq::<Visual>(&*v, ancestor) {
576 result *= local_transform(&v);
577
578 v = match v.visual_parent() {
579 Some(parent) => parent,
580 None => panic!("'visual' is not a descendant of 'ancestor'."),
581 };
582 }
583
584 result
585 }
586}