use super::TransformedBounds;
use crate::input::IInputRoot;
use crate::layout::{ILayoutManager, ILayoutRoot};
use crate::rendering::IPresentationSource;
use crate::media::{Geometry, GeometryHitTestResult};
use crate::platform::IPlatformSettings;
use crate::{Matrix, ObjectType, PixelPoint, Point, Rect, Ref, Visual};
use std::rc::Rc;
#[inline]
fn render_transform(visual: &Visual) -> Option<Matrix> {
if !visual.has_render_transform() {
return None;
}
visual.render_transform().map(|transform| {
let origin = visual.render_transform_origin().to_pixels(visual.bounds().size());
let offset = Matrix::create_translation(origin.x, origin.y);
-offset * transform.value() * offset
})
}
#[inline]
fn local_render_transform(visual: &Visual) -> Matrix {
let mut result = Matrix::IDENTITY;
if visual.has_mirror_transform() {
let mirror_matrix = Matrix::new(-1.0, 0.0, 0.0, 1.0, visual.bounds().width, 0.0);
result *= mirror_matrix;
}
if let Some(render_transform) = render_transform(visual) {
result *= render_transform;
}
result
}
pub(crate) fn local_transform(visual: &Visual) -> Matrix {
let mut result = local_render_transform(visual);
let top_left = visual.bounds().top_left();
if top_left != Point::default() {
result *= Matrix::create_translation(top_left.x, top_left.y);
}
result
}
pub struct VisualAncestors {
next: Option<Ref<Visual>>,
}
impl Iterator for VisualAncestors {
type Item = Ref<Visual>;
fn next(&mut self) -> Option<Ref<Visual>> {
let current = self.next.take()?;
self.next = current.visual_parent();
Some(current)
}
}
pub struct VisualDescendants {
stack: Vec<(Rc<Vec<Ref<Visual>>>, usize)>,
pending: Option<Ref<Visual>>,
}
impl Iterator for VisualDescendants {
type Item = Ref<Visual>;
fn next(&mut self) -> Option<Ref<Visual>> {
if let Some(pending) = self.pending.take() {
return Some(pending);
}
loop {
let (children, index) = self.stack.last_mut()?;
if *index >= children.len() {
self.stack.pop();
continue;
}
let child = children[*index].clone();
*index += 1;
if let Some(grandchildren) = child.visual_children_snapshot() {
if !grandchildren.is_empty() {
self.stack.push((grandchildren, 0));
}
}
return Some(child);
}
}
}
impl Visual {
pub fn calculate_distance_from_ancestor(&self, ancestor: Option<&Visual>) -> Option<usize> {
let mut result = 0;
let mut v = Some(self.to_ref());
while let Some(current) = v {
if ancestor.is_some_and(|a| std::ptr::eq::<Visual>(&*current, a)) {
return Some(result);
}
v = current.visual_parent();
result += 1;
}
None
}
pub fn calculate_distance_from_root(&self) -> usize {
let mut result = 0;
let mut v = self.visual_parent();
while let Some(current) = v {
v = current.visual_parent();
result += 1;
}
result
}
pub fn find_common_visual_ancestor(&self, target: &Visual) -> Option<Ref<Visual>> {
fn go_upwards(node: &mut Option<Ref<Visual>>, count: usize) {
for _ in 0..count {
*node = node.as_ref().and_then(|n| n.visual_parent());
}
}
let mut v = Some(self.to_ref());
let mut t = Some(target.to_ref());
let first_height = self.calculate_distance_from_root();
let second_height = target.calculate_distance_from_root();
if first_height > second_height {
go_upwards(&mut v, first_height - second_height);
} else {
go_upwards(&mut t, second_height - first_height);
}
if v == t {
return v;
}
while let (Some(first), Some(second)) = (&v, &t) {
let first_parent = first.visual_parent();
let second_parent = second.visual_parent();
if first_parent == second_parent {
return first_parent;
}
v = first_parent;
t = second_parent;
}
None
}
pub fn get_visual_ancestors(&self) -> VisualAncestors {
VisualAncestors { next: self.visual_parent() }
}
pub fn get_self_and_visual_ancestors(&self) -> VisualAncestors {
VisualAncestors { next: Some(self.to_ref()) }
}
pub fn find_ancestor_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
self.find_ancestor_of_type_where::<T>(include_self, |_| true)
}
pub fn find_ancestor_of_type_where<T: ObjectType>(
&self,
include_self: bool,
predicate: impl Fn(&T) -> bool,
) -> Option<Ref<T>> {
let mut parent = if include_self { Some(self.to_ref()) } else { self.visual_parent() };
while let Some(current) = parent {
if let Some(result) = current.downcast_ref::<T>() {
if predicate(result) {
return current.downcast::<T>().ok();
}
}
parent = current.visual_parent();
}
None
}
pub fn find_descendant_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
self.find_descendant_of_type_where::<T>(include_self, |_| true)
}
pub fn find_descendant_of_type_where<T: ObjectType>(
&self,
include_self: bool,
predicate: impl Fn(&T) -> bool,
) -> Option<Ref<T>> {
fn core<T: ObjectType>(visual: &Visual, predicate: &dyn Fn(&T) -> bool) -> Option<Ref<T>> {
let children = visual.visual_children_snapshot()?;
for child in children.iter() {
if let Some(result) = child.downcast_ref::<T>() {
if predicate(result) {
return child.cast::<T>();
}
}
if let Some(child_result) = core::<T>(child, predicate) {
return Some(child_result);
}
}
None
}
if include_self {
if let Some(result) = self.downcast_ref::<T>() {
if predicate(result) {
return self.to_ref().downcast::<T>().ok();
}
}
}
core::<T>(self, &predicate)
}
pub fn get_transformed_bounds(&self) -> Option<TransformedBounds> {
fn visit(visual: &Visual, clip: &mut Rect, transform: &mut Matrix) -> bool {
if !visual.is_visible() {
return false;
}
let bounds = Rect::from_size(visual.bounds().size());
let Some(parent) = visual.visual_parent() else {
*clip = bounds;
return true;
};
if !visit(&parent, clip, transform) {
return false;
}
let render_transform = local_render_transform(visual);
let position = visual.bounds().position();
*transform = render_transform * Matrix::create_translation(position.x, position.y) * *transform;
if visual.clip_to_bounds() {
let global_bounds = bounds.transform_to_aabb(*transform);
let clip_bounds = global_bounds.intersect(*clip);
*clip = clip.intersect(clip_bounds);
}
true
}
let mut clip = Rect::default();
let mut transform = Matrix::IDENTITY;
if visit(self, &mut clip, &mut transform) {
Some(TransformedBounds::new(Rect::from_size(self.bounds().size()), clip, transform))
} else {
None
}
}
pub fn get_visual_at(&self, p: Point) -> Option<Ref<Visual>> {
self.get_visual_at_filtered(p, &|x: &Visual| x.is_visible())
}
pub fn get_visual_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Option<Ref<Visual>> {
let source = self.presentation_source()?;
source.hit_tester().hit_test_first(p, self, Some(filter))
}
pub fn get_visual_at_geometry(&self, geometry: &Geometry) -> Option<GeometryHitTestResult> {
self.get_visual_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
}
pub fn get_visual_at_geometry_filtered(
&self,
geometry: &Geometry,
filter: &dyn Fn(&Visual) -> bool,
) -> Option<GeometryHitTestResult> {
let source = self.presentation_source()?;
source.hit_tester().hit_test_first_geometry(geometry, self, Some(filter))
}
pub fn get_visuals_at(&self, p: Point) -> Vec<Ref<Visual>> {
self.get_visuals_at_filtered(p, &|x: &Visual| x.is_visible())
}
pub fn get_visuals_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Vec<Ref<Visual>> {
match self.presentation_source() {
Some(source) => source.hit_tester().hit_test(p, self, Some(filter)),
None => Vec::new(),
}
}
pub fn get_visuals_at_geometry(&self, geometry: &Geometry) -> Vec<GeometryHitTestResult> {
self.get_visuals_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
}
pub fn get_visuals_at_geometry_filtered(
&self,
geometry: &Geometry,
filter: &dyn Fn(&Visual) -> bool,
) -> Vec<GeometryHitTestResult> {
match self.presentation_source() {
Some(source) => source.hit_tester().hit_test_geometry(geometry, self, Some(filter)),
None => Vec::new(),
}
}
pub fn get_visual_children(&self) -> Rc<Vec<Ref<Visual>>> {
self.visual_children_snapshot().unwrap_or_default()
}
pub fn get_visual_descendants(&self) -> VisualDescendants {
let mut stack = Vec::new();
if let Some(children) = self.visual_children_snapshot() {
if !children.is_empty() {
stack.push((children, 0));
}
}
VisualDescendants { stack, pending: None }
}
pub fn get_self_and_visual_descendants(&self) -> VisualDescendants {
let mut result = self.get_visual_descendants();
result.pending = Some(self.to_ref());
result
}
pub fn get_visual_parent(&self) -> Option<Ref<Visual>> {
self.visual_parent()
}
pub fn get_visual_parent_of_type<T: ObjectType>(&self) -> Option<Ref<T>> {
self.visual_parent().and_then(|parent| parent.downcast::<T>().ok())
}
pub fn get_presentation_source(&self) -> Option<Rc<dyn IPresentationSource>> {
self.presentation_source()
}
pub fn get_visual_root(&self) -> Option<Ref<Visual>> {
self.presentation_source().and_then(|source| source.root_visual())
}
pub fn get_layout_root(&self) -> Option<Rc<dyn ILayoutRoot>> {
self.presentation_source().map(|source| source.layout_root())
}
pub fn get_layout_manager(&self) -> Option<Rc<dyn ILayoutManager>> {
self.presentation_source().map(|source| source.layout_root().layout_manager())
}
pub fn get_input_root(&self) -> Option<Rc<dyn IInputRoot>> {
self.presentation_source().map(|source| source.input_root())
}
pub fn get_platform_settings(&self) -> Option<Rc<dyn IPlatformSettings>> {
self.presentation_source().and_then(|source| source.platform_settings())
}
pub fn is_visual_ancestor_of(&self, target: &Visual) -> bool {
let mut current = target.visual_parent();
while let Some(c) = current {
if std::ptr::eq::<Visual>(&*c, self) {
return true;
}
current = c.visual_parent();
}
false
}
pub fn sort_by_z_index(elements: &[Ref<Visual>]) -> Vec<Ref<Visual>> {
let mut indexed: Vec<(i32, usize)> =
elements.iter().enumerate().map(|(index, element)| (element.z_index(), index)).collect();
indexed.sort_by(|x, y| y.0.cmp(&x.0).then(y.1.cmp(&x.1)));
indexed.into_iter().map(|(_, index)| elements[index].clone()).collect()
}
pub fn point_to_client(&self, point: PixelPoint) -> Point {
let (source, root) = self.source_and_root();
let root_point = source.point_to_client(point).unwrap_or_default();
root.translate_point(root_point, self).expect("the root is an ancestor of the visual")
}
pub fn point_to_screen(&self, point: Point) -> PixelPoint {
let (source, root) = self.source_and_root();
let p = self.translate_point(point, &root).expect("the root is an ancestor of the visual");
source.point_to_screen(p).unwrap_or_default()
}
pub fn transform_to_visual(&self, to: &Visual) -> Option<Matrix> {
if let Some(offset) = Self::try_get_offset_from_ancestor(to, self) {
return Some(offset);
}
let common = self.find_common_visual_ancestor(to)?;
let this_offset = Self::get_offset_from(&common, self);
let that_offset = Self::get_offset_from(&common, to);
let that_offset_inverted = that_offset.try_invert()?;
Some(that_offset_inverted * this_offset)
}
pub fn translate_point(&self, point: Point, relative_to: &Visual) -> Option<Point> {
self.transform_to_visual(relative_to).map(|transform| point.transform(transform))
}
fn source_and_root(&self) -> (Rc<dyn crate::rendering::IPresentationSource>, Ref<Visual>) {
let source = self.presentation_source();
let root = source.as_ref().and_then(|s| s.root_visual());
match (source, root) {
(Some(source), Some(root)) => (source, root),
_ => panic!("Visual does not belong to a visual tree."),
}
}
fn try_get_offset_from_ancestor(ancestor: &Visual, visual: &Visual) -> Option<Matrix> {
let mut result = Matrix::IDENTITY;
let mut v = visual.to_ref();
while !std::ptr::eq::<Visual>(&*v, ancestor) {
result *= local_transform(&v);
v = v.visual_parent()?;
}
Some(result)
}
fn get_offset_from(ancestor: &Visual, visual: &Visual) -> Matrix {
let mut result = Matrix::IDENTITY;
let mut v = visual.to_ref();
while !std::ptr::eq::<Visual>(&*v, ancestor) {
result *= local_transform(&v);
v = match v.visual_parent() {
Some(parent) => parent,
None => panic!("'visual' is not a descendant of 'ancestor'."),
};
}
result
}
}