Skip to main content

ferroui_base/logical_tree/
logical_extensions.rs

1//! Extension methods for the logical tree, as inherent methods of
2//! [`StyledElement`], the one implementation of `ILogical`.
3
4use crate::{ObjectType, Ref, StyledElement};
5use std::rc::Rc;
6
7/// Iterates the logical ancestors of an element, from its parent to the
8/// root.
9pub struct LogicalAncestors {
10    next: Option<Ref<StyledElement>>,
11}
12
13impl Iterator for LogicalAncestors {
14    type Item = Ref<StyledElement>;
15
16    fn next(&mut self) -> Option<Ref<StyledElement>> {
17        let current = self.next.take()?;
18        self.next = current.parent();
19        Some(current)
20    }
21}
22
23/// Iterates the logical descendants of an element in depth-first
24/// pre-order.
25pub struct LogicalDescendants {
26    /// The snapshots of the children collections being enumerated, with the
27    /// index of the next child to visit in each.
28    stack: Vec<(Rc<Vec<Ref<StyledElement>>>, usize)>,
29    pending: Option<Ref<StyledElement>>,
30}
31
32impl LogicalDescendants {
33    fn push_children(&mut self, logical: &StyledElement) {
34        let children = logical.logical_children().snapshot();
35        if !children.is_empty() {
36            self.stack.push((children, 0));
37        }
38    }
39}
40
41impl Iterator for LogicalDescendants {
42    type Item = Ref<StyledElement>;
43
44    fn next(&mut self) -> Option<Ref<StyledElement>> {
45        if let Some(pending) = self.pending.take() {
46            return Some(pending);
47        }
48
49        loop {
50            let (children, index) = self.stack.last_mut()?;
51            if *index >= children.len() {
52                self.stack.pop();
53                continue;
54            }
55
56            let child = children[*index].clone();
57            *index += 1;
58            self.push_children(&child);
59            return Some(child);
60        }
61    }
62}
63
64impl StyledElement {
65    /// Enumerates the ancestors of the element in the logical tree, from its
66    /// parent to the root.
67    pub fn get_logical_ancestors(&self) -> LogicalAncestors {
68        LogicalAncestors { next: self.parent() }
69    }
70
71    /// Enumerates the element and its ancestors in the logical tree.
72    pub fn get_self_and_logical_ancestors(&self) -> LogicalAncestors {
73        LogicalAncestors { next: Some(self.to_ref()) }
74    }
75
76    /// Finds the first logical ancestor of class `T`, optionally starting
77    /// with the element itself.
78    pub fn find_logical_ancestor_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
79        let mut parent = if include_self { Some(self.to_ref()) } else { self.parent() };
80
81        while let Some(current) = parent {
82            if let Some(result) = current.clone().cast::<T>() {
83                return Some(result);
84            }
85            parent = current.parent();
86        }
87
88        None
89    }
90
91    /// The logical children of the element.
92    // Deviation (DEVIATIONS.md, Logical tree): upstream returns the collection itself; this is a snapshot of it.
93    pub fn get_logical_children(&self) -> Rc<Vec<Ref<StyledElement>>> {
94        self.logical_children().snapshot()
95    }
96
97    /// Enumerates the descendants of the element in the logical tree, in
98    /// depth-first pre-order.
99    pub fn get_logical_descendants(&self) -> LogicalDescendants {
100        let mut result = LogicalDescendants { stack: Vec::new(), pending: None };
101        result.push_children(self);
102        result
103    }
104
105    /// Enumerates the element and its descendants in the logical tree, in
106    /// depth-first pre-order.
107    pub fn get_self_and_logical_descendants(&self) -> LogicalDescendants {
108        let mut result = self.get_logical_descendants();
109        result.pending = Some(self.to_ref());
110        result
111    }
112
113    /// Finds the first logical descendant of class `T` (depth first),
114    /// optionally starting with the element itself.
115    pub fn find_logical_descendant_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
116        if include_self {
117            if let Some(result) = self.to_ref().cast::<T>() {
118                return Some(result);
119            }
120        }
121
122        Self::find_descendant_of_type_core::<T>(self)
123    }
124
125    /// The logical parent of the element.
126    pub fn get_logical_parent(&self) -> Option<Ref<StyledElement>> {
127        self.parent()
128    }
129
130    /// The logical parent of the element, if it is of class `T`.
131    pub fn get_logical_parent_of_type<T: ObjectType>(&self) -> Option<Ref<T>> {
132        self.parent().and_then(|parent| parent.cast::<T>())
133    }
134
135    /// The children of the logical parent of the element, including the
136    /// element itself; empty when the element has no logical parent.
137    // Deviation (DEVIATIONS.md, Logical tree): upstream enumerates the parent's children lazily; this is a snapshot.
138    pub fn get_logical_siblings(&self) -> Rc<Vec<Ref<StyledElement>>> {
139        match self.parent() {
140            Some(parent) => parent.logical_children().snapshot(),
141            None => Rc::default(),
142        }
143    }
144
145    /// Whether the element is a logical ancestor of `target`.
146    // Deviation (DEVIATIONS.md, Logical tree): upstream also accepts a null receiver (and returns false).
147    pub fn is_logical_ancestor_of(&self, target: Option<&StyledElement>) -> bool {
148        let mut current = target.and_then(StyledElement::parent);
149
150        while let Some(parent) = current {
151            if std::ptr::eq::<StyledElement>(&*parent, self) {
152                return true;
153            }
154            current = parent.parent();
155        }
156
157        false
158    }
159
160    fn find_descendant_of_type_core<T: ObjectType>(logical: &StyledElement) -> Option<Ref<T>> {
161        let logical_children = logical.logical_children().snapshot();
162
163        for child in logical_children.iter() {
164            if let Some(result) = child.clone().cast::<T>() {
165                return Some(result);
166            }
167
168            if let Some(child_result) = Self::find_descendant_of_type_core::<T>(child) {
169                return Some(child_result);
170            }
171        }
172
173        None
174    }
175}