use crate::AccessKitNode;
use accesskit::Role;
use std::fmt::{Debug, Formatter};
pub fn by<'a>() -> By<'a> {
By::new()
}
pub struct By<'a> {
label: Option<&'a str>,
label_contains: bool,
include_labels: bool,
#[allow(clippy::type_complexity)]
predicate: Option<Box<dyn Fn(&AccessKitNode<'_>) -> bool + 'a>>,
had_predicate: bool,
role: Option<Role>,
value: Option<&'a str>,
pub(crate) recursive: bool,
}
impl Debug for By<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let By {
label,
label_contains,
include_labels,
predicate,
had_predicate,
role,
value,
recursive,
} = self;
let mut s = f.debug_struct("By");
if let Some(label) = label {
if *label_contains {
s.field("label_contains", &label);
} else {
s.field("label", &label);
}
}
if *include_labels {
s.field("include_labels", &true);
}
if predicate.is_some() || *had_predicate {
s.field("predicate", &"<function>");
}
if let Some(role) = role {
s.field("role", &role);
}
if let Some(value) = value {
s.field("value", &value);
}
if !*recursive {
s.field("recursive", recursive);
}
s.finish()
}
}
impl Default for By<'_> {
fn default() -> Self {
Self::new()
}
}
impl<'a> By<'a> {
pub fn new() -> Self {
Self {
label: None,
label_contains: false,
include_labels: false,
predicate: None,
had_predicate: false,
role: None,
value: None,
recursive: true,
}
}
pub fn label(mut self, label: &'a str) -> Self {
self.label = Some(label);
self
}
pub fn label_contains(mut self, label: &'a str) -> Self {
self.label = Some(label);
self.label_contains = true;
self
}
pub fn include_labels(mut self) -> Self {
self.include_labels = true;
self
}
pub fn predicate(mut self, predicate: impl Fn(&AccessKitNode<'_>) -> bool + 'a) -> Self {
self.predicate = Some(Box::new(predicate));
self.had_predicate = true;
self
}
pub fn role(mut self, role: Role) -> Self {
self.role = Some(role);
self
}
pub fn value(mut self, value: &'a str) -> Self {
self.value = Some(value);
self
}
pub fn recursive(mut self, recursive: bool) -> Self {
self.recursive = recursive;
self
}
pub(crate) fn should_filter_labels(&self) -> bool {
!self.include_labels && self.label.is_some()
}
pub(crate) fn debug_clone_without_predicate(&self) -> Self {
Self {
label: self.label,
label_contains: self.label_contains,
include_labels: self.include_labels,
predicate: None,
had_predicate: self.had_predicate,
role: self.role,
value: self.value,
recursive: self.recursive,
}
}
pub(crate) fn matches(&self, node: &AccessKitNode<'_>) -> bool {
if let Some(label) = self.label {
let node_label = if node.role() == Role::Label {
node.value()
} else {
node.label()
};
if let Some(node_label) = node_label {
if self.label_contains {
if !node_label.contains(label) {
return false;
}
} else if node_label != label {
return false;
}
} else {
return false;
}
}
if let Some(predicate) = &self.predicate {
if !predicate(node) {
return false;
}
}
if let Some(role) = self.role {
if node.role() != role {
return false;
}
}
if let Some(value) = self.value {
if let Some(node_value) = node.value() {
if node_value != value {
return false;
}
} else {
return false;
}
}
true
}
}