Skip to content

Commit 0f132ea

Browse files
authored
feat: Expose text properties on consumer Node with inheritance (#617)
1 parent 057bede commit 0f132ea

File tree

2 files changed

+106
-5
lines changed

2 files changed

+106
-5
lines changed

consumer/src/node.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub struct Node<'a> {
4242
}
4343

4444
impl<'a> Node<'a> {
45-
pub fn data(&self) -> &NodeData {
45+
pub fn data(&self) -> &'a NodeData {
4646
&self.state.data
4747
}
4848

@@ -406,6 +406,20 @@ impl<'a> Node<'a> {
406406
self.data().scroll_y_max()
407407
}
408408

409+
pub(crate) fn fetch_inherited_property<T>(
410+
&self,
411+
getter: fn(&'a NodeData) -> Option<T>,
412+
) -> Option<T> {
413+
let mut node = *self;
414+
loop {
415+
let value = getter(node.data());
416+
if value.is_some() {
417+
return value;
418+
}
419+
node = node.parent()?;
420+
}
421+
}
422+
409423
pub fn is_text_input(&self) -> bool {
410424
matches!(
411425
self.role(),

consumer/src/text.rs

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
// the LICENSE-MIT file), at your option.
55

66
use accesskit::{
7-
NodeId, Point, Rect, Role, TextDirection, TextPosition as WeakPosition, TextSelection,
7+
Node as NodeData, NodeId, Point, Rect, Role, TextAlign, TextDecoration, TextDirection,
8+
TextPosition as WeakPosition, TextSelection, VerticalOffset,
89
};
910
use alloc::{string::String, vec::Vec};
1011
use core::{cmp::Ordering, fmt, iter::FusedIterator};
@@ -647,7 +648,7 @@ impl<'a> Range<'a> {
647648
return Some(Vec::new());
648649
}
649650
};
650-
let direction = match node.data().text_direction() {
651+
let direction = match node.text_direction() {
651652
Some(direction) => direction,
652653
None => {
653654
return Some(Vec::new());
@@ -844,7 +845,7 @@ fn character_index_at_point(node: &Node, point: Point) -> usize {
844845
return 0;
845846
}
846847
};
847-
let direction = match node.data().text_direction() {
848+
let direction = match node.text_direction() {
848849
Some(direction) => direction,
849850
None => {
850851
return 0;
@@ -867,6 +868,92 @@ fn character_index_at_point(node: &Node, point: Point) -> usize {
867868
character_lengths.len()
868869
}
869870

871+
macro_rules! inherited_properties {
872+
($(($getter:ident, $type:ty, $setter:ident, $test_value:expr)),+) => {
873+
impl Node<'_> {
874+
$(pub fn $getter(&self) -> Option<$type> {
875+
self.fetch_inherited_property(NodeData::$getter)
876+
})*
877+
}
878+
$(#[cfg(test)]
879+
mod $getter {
880+
use accesskit::{Node, NodeId, Role, Tree, TreeUpdate};
881+
use alloc::vec;
882+
#[test]
883+
fn directly_set() {
884+
let update = TreeUpdate {
885+
nodes: vec![
886+
(NodeId(0), {
887+
let mut node = Node::new(Role::TextInput);
888+
node.set_children(vec![NodeId(1)]);
889+
node
890+
}),
891+
(NodeId(1), {
892+
let mut node = Node::new(Role::TextRun);
893+
node.$setter($test_value);
894+
node
895+
}),
896+
],
897+
tree: Some(Tree::new(NodeId(0))),
898+
focus: NodeId(0),
899+
};
900+
let tree = crate::Tree::new(update, false);
901+
assert_eq!(tree.state().node_by_id(NodeId(1)).unwrap().$getter(), Some($test_value));
902+
}
903+
#[test]
904+
fn set_on_parent() {
905+
let update = TreeUpdate {
906+
nodes: vec![
907+
(NodeId(0), {
908+
let mut node = Node::new(Role::TextInput);
909+
node.set_children(vec![NodeId(1)]);
910+
node.$setter($test_value);
911+
node
912+
}),
913+
(NodeId(1), Node::new(Role::TextRun)),
914+
],
915+
tree: Some(Tree::new(NodeId(0))),
916+
focus: NodeId(0),
917+
};
918+
let tree = crate::Tree::new(update, false);
919+
assert_eq!(tree.state().node_by_id(NodeId(1)).unwrap().$getter(), Some($test_value));
920+
}
921+
#[test]
922+
fn unset() {
923+
let update = TreeUpdate {
924+
nodes: vec![
925+
(NodeId(0), {
926+
let mut node = Node::new(Role::TextInput);
927+
node.set_children(vec![NodeId(1)]);
928+
node
929+
}),
930+
(NodeId(1), Node::new(Role::TextRun)),
931+
],
932+
tree: Some(Tree::new(NodeId(0))),
933+
focus: NodeId(0),
934+
};
935+
let tree = crate::Tree::new(update, false);
936+
assert!(tree.state().node_by_id(NodeId(1)).unwrap().$getter().is_none());
937+
}
938+
})*
939+
}
940+
}
941+
942+
inherited_properties! {
943+
(text_direction, TextDirection, set_text_direction, accesskit::TextDirection::RightToLeft),
944+
(font_family, &str, set_font_family, "Inconsolata"),
945+
(language, &str, set_language, "fr"),
946+
(font_size, f64, set_font_size, 24.0),
947+
(font_weight, f64, set_font_weight, 700.0),
948+
(background_color, u32, set_background_color, 0xff),
949+
(foreground_color, u32, set_foreground_color, 0xff00),
950+
(overline, TextDecoration, set_overline, accesskit::TextDecoration::Dotted),
951+
(strikethrough, TextDecoration, set_strikethrough, accesskit::TextDecoration::Dashed),
952+
(underline, TextDecoration, set_underline, accesskit::TextDecoration::Double),
953+
(text_align, TextAlign, set_text_align, accesskit::TextAlign::Justify),
954+
(vertical_offset, VerticalOffset, set_vertical_offset, accesskit::VerticalOffset::Superscript)
955+
}
956+
870957
impl<'a> Node<'a> {
871958
pub(crate) fn text_runs(
872959
&self,
@@ -985,7 +1072,7 @@ impl<'a> Node<'a> {
9851072

9861073
for node in self.text_runs().rev() {
9871074
if let Some(rect) = node.bounding_box_in_coordinate_space(self) {
988-
if let Some(direction) = node.data().text_direction() {
1075+
if let Some(direction) = node.text_direction() {
9891076
let is_past_end = match direction {
9901077
TextDirection::LeftToRight => {
9911078
point.y >= rect.y0 && point.y < rect.y1 && point.x >= rect.x1

0 commit comments

Comments
 (0)