Skip to main content

automata_windows/
locator.rs

1use super::{Selector, UIElement, UiError};
2
3/// Scoped element finder: searches within a root element for a selector match.
4pub struct Locator {
5    root: UIElement,
6    selector: Selector,
7}
8
9impl Locator {
10    #[cfg_attr(not(target_os = "windows"), allow(dead_code))]
11    pub(crate) fn new(root: UIElement, selector: Selector) -> Self {
12        Self { root, selector }
13    }
14
15    /// Search the subtree of `root` for the first element matching the selector.
16    /// Returns an error if no match is found.
17    pub fn find(&self) -> Result<UIElement, UiError> {
18        find_in(&self.root, &self.selector)
19    }
20}
21
22fn matches(el: &UIElement, selector: &Selector) -> bool {
23    match selector {
24        Selector::Role { role, name } => {
25            if el.role() != *role {
26                return false;
27            }
28            match name {
29                None => true,
30                Some(n) => el.name_or_empty() == *n,
31            }
32        }
33    }
34}
35
36fn find_in(el: &UIElement, selector: &Selector) -> Result<UIElement, UiError> {
37    let children = el
38        .children()
39        .map_err(|e| UiError::Platform(e.to_string()))?;
40    for child in children {
41        if matches(&child, selector) {
42            return Ok(child);
43        }
44        if let Ok(found) = find_in(&child, selector) {
45            return Ok(found);
46        }
47    }
48    Err(UiError::Internal(format!(
49        "Element not found: {selector:?}"
50    )))
51}