i_slint_compiler/passes/
lower_accessibility.rs1use crate::diagnostics::BuildDiagnostics;
7use crate::expression_tree::{BuiltinFunction, Callable, Expression, NamedReference};
8use crate::langtype::{EnumerationValue, Type};
9use crate::object_tree::{Component, ElementRc};
10
11use smol_str::SmolStr;
12use std::rc::Rc;
13
14pub fn lower_accessibility_properties(component: &Rc<Component>, diag: &mut BuildDiagnostics) {
15 crate::object_tree::recurse_elem_including_sub_components_no_borrow(
16 component,
17 &(),
18 &mut |elem, _| {
19 if elem.borrow().repeated.is_some() {
20 return;
21 };
22 apply_builtin(elem);
23 let accessible_role_set = match elem.borrow().binding("accessible-role") {
24 Some(role) => {
25 if let Expression::EnumerationValue(val) = role.value_expression() {
26 debug_assert_eq!(val.enumeration.name, "AccessibleRole");
27 debug_assert_eq!(val.enumeration.values[0], "none");
28 if val.value == 0 {
29 return;
30 }
31 } else {
32 diag.push_error(
33 "The `accessible-role` property must be a constant expression".into(),
34 &*role,
35 );
36 }
37 true
38 }
39 None => elem.borrow().is_binding_set("accessible-role", false),
41 };
42
43 for prop_name in crate::typeregister::reserved_accessibility_properties()
44 .map(|x| x.0)
45 .chain(["accessible-role", "accessible-orientation", "accessible-live-region"])
46 {
47 if accessible_role_set {
48 if elem.borrow().is_binding_set(prop_name, false) {
49 let nr = NamedReference::new(elem, SmolStr::new_static(prop_name));
50 elem.borrow_mut().accessibility_props.0.insert(prop_name.into(), nr);
51 }
52 } else if let Some(b) = elem.borrow().binding(prop_name) {
53 diag.push_error(
54 format!("The `{prop_name}` property can only be set in combination to `accessible-role`"),
55 &*b,
56 );
57 }
58 }
59 },
60 )
61}
62
63fn apply_builtin(e: &ElementRc) {
64 let bty = if let Some(bty) = e.borrow().builtin_type() { bty } else { return };
65 if bty.name == "Text" {
66 e.borrow_mut().set_binding_if_not_set("accessible-role".into(), || {
67 let enum_ty = crate::typeregister::BUILTIN.enums.AccessibleRole.clone();
68 Expression::EnumerationValue(EnumerationValue {
69 value: enum_ty.values.iter().position(|v| v == "text").unwrap(),
70 enumeration: enum_ty,
71 })
72 });
73 let text_prop = NamedReference::new(e, SmolStr::new_static("text"));
74 e.borrow_mut().set_binding_if_not_set("accessible-label".into(), || {
75 Expression::PropertyReference(text_prop)
76 });
77 } else if bty.name == "TextInput" {
78 e.borrow_mut().set_binding_if_not_set("accessible-role".into(), || {
79 let enum_ty = crate::typeregister::BUILTIN.enums.AccessibleRole.clone();
80 Expression::EnumerationValue(EnumerationValue {
81 value: enum_ty.values.iter().position(|v| v == "text-input").unwrap(),
82 enumeration: enum_ty,
83 })
84 });
85 let text_prop = NamedReference::new(e, SmolStr::new_static("text"));
86 e.borrow_mut().set_binding_if_not_set("accessible-value".into(), || {
87 Expression::PropertyReference(text_prop)
88 });
89 let enabled_prop = NamedReference::new(e, SmolStr::new_static("enabled"));
90 e.borrow_mut().set_binding_if_not_set("accessible-enabled".into(), || {
91 Expression::PropertyReference(enabled_prop)
92 });
93 let read_only_prop = NamedReference::new(e, SmolStr::new_static("read-only"));
94 e.borrow_mut().set_binding_if_not_set("accessible-read-only".into(), || {
95 Expression::PropertyReference(read_only_prop)
96 });
97 {
98 let text_prop = NamedReference::new(e, SmolStr::new_static("text"));
100 let edited_callback = NamedReference::new(e, SmolStr::new_static("edited"));
101 e.borrow_mut().set_binding_if_not_set("accessible-action-set-value".into(), || {
102 Expression::CodeBlock(vec![
103 Expression::SelfAssignment {
104 lhs: Box::new(Expression::PropertyReference(text_prop.clone())),
105 rhs: Box::new(Expression::FunctionParameterReference {
106 index: 0,
107 ty: Type::String,
108 }),
109 op: '=',
110 node: None,
111 },
112 Expression::FunctionCall {
113 function: Callable::Callback(edited_callback),
114 arguments: vec![],
115 source_location: None,
116 },
117 ])
118 });
119 }
120 {
121 e.borrow_mut().set_binding_if_not_set(
122 "accessible-action-set-selection-offsets".into(),
123 || Expression::FunctionCall {
124 function: Callable::Builtin(BuiltinFunction::SetSelectionOffsets),
125 arguments: vec![
126 Expression::ElementReference(Rc::downgrade(e)),
127 Expression::FunctionParameterReference { index: 0, ty: Type::Int32 },
128 Expression::FunctionParameterReference { index: 1, ty: Type::Int32 },
129 ],
130 source_location: None,
131 },
132 );
133 }
134 } else if bty.name == "Image" {
135 e.borrow_mut().set_binding_if_not_set("accessible-role".into(), || {
136 let enum_ty = crate::typeregister::BUILTIN.enums.AccessibleRole.clone();
137 Expression::EnumerationValue(EnumerationValue {
138 value: enum_ty.values.iter().position(|v| v == "image").unwrap(),
139 enumeration: enum_ty,
140 })
141 });
142 }
143}