1use glib::{translate::*, Value};
4
5use crate::{
6 ffi, prelude::*, Accessible, AccessibleAutocomplete, AccessibleInvalidState,
7 AccessibleProperty, AccessibleRelation, AccessibleSort, AccessibleState, AccessibleTristate,
8 Orientation,
9};
10pub trait AccessibleExtManual: IsA<Accessible> {
29 #[doc(alias = "gtk_accessible_update_property")]
30 #[doc(alias = "gtk_accessible_update_property_value")]
31 fn update_property(&self, properties: &[Property]) {
32 let mut properties_ptr = vec![];
33 let mut values = vec![];
34 for prop in properties {
35 let (p, v) = prop.to_property_value();
36 properties_ptr.push(p.into_glib());
37 values.push(v);
38 }
39
40 unsafe {
41 ffi::gtk_accessible_update_property_value(
42 self.as_ref().to_glib_none().0,
43 properties.len() as i32,
44 mut_override(properties_ptr.as_ptr()),
45 ToGlibContainerFromSlice::to_glib_none_from_slice(&values).0,
46 )
47 }
48 }
49
50 #[doc(alias = "gtk_accessible_update_relation")]
51 #[doc(alias = "gtk_accessible_update_relation_value")]
52 fn update_relation(&self, relations: &[Relation]) {
53 let mut relations_ptr = vec![];
54 let mut values = vec![];
55 for relation in relations {
56 let (r, v) = relation.to_relation_value();
57 relations_ptr.push(r.into_glib());
58 values.push(v);
59 }
60
61 unsafe {
62 ffi::gtk_accessible_update_relation_value(
63 self.as_ref().to_glib_none().0,
64 relations.len() as i32,
65 mut_override(relations_ptr.as_ptr()),
66 ToGlibContainerFromSlice::to_glib_none_from_slice(&values).0,
67 )
68 }
69 }
70
71 #[doc(alias = "gtk_accessible_update_state")]
72 #[doc(alias = "gtk_accessible_update_state_value")]
73 fn update_state(&self, states: &[State]) {
74 let mut states_ptr = vec![];
75 let mut values = vec![];
76 for state in states {
77 let (s, v) = state.to_state_value();
78 states_ptr.push(s.into_glib());
79 values.push(v);
80 }
81
82 unsafe {
83 ffi::gtk_accessible_update_state_value(
84 self.as_ref().to_glib_none().0,
85 states.len() as i32,
86 mut_override(states_ptr.as_ptr()),
87 ToGlibContainerFromSlice::to_glib_none_from_slice(&values).0,
88 )
89 }
90 }
91}
92
93impl<O: IsA<Accessible>> AccessibleExtManual for O {}
94
95#[derive(Debug)]
99#[non_exhaustive]
100pub enum Property<'p> {
101 Autocomplete(AccessibleAutocomplete),
102 Description(&'p str),
103 HasPopup(bool),
104 KeyShortcuts(&'p str),
105 Label(&'p str),
106 Level(i32),
107 Modal(bool),
108 MultiLine(bool),
109 MultiSelectable(bool),
110 Orientation(Orientation),
111 Placeholder(&'p str),
112 ReadOnly(bool),
113 Required(bool),
114 RoleDescription(&'p str),
115 Sort(AccessibleSort),
116 ValueMax(f64),
117 ValueMin(f64),
118 ValueNow(f64),
119 ValueText(&'p str),
120}
121
122impl Property<'_> {
123 fn to_property_value(&self) -> (AccessibleProperty, Value) {
124 use Property::*;
125
126 match self {
127 Autocomplete(v) => (AccessibleProperty::Autocomplete, v.into_glib().to_value()),
128 Description(v) => (AccessibleProperty::Description, v.to_value()),
129 HasPopup(v) => (AccessibleProperty::HasPopup, v.to_value()),
130 KeyShortcuts(v) => (AccessibleProperty::KeyShortcuts, v.to_value()),
131 Label(v) => (AccessibleProperty::Label, v.to_value()),
132 Level(v) => (AccessibleProperty::Level, v.to_value()),
133 Modal(v) => (AccessibleProperty::Modal, v.to_value()),
134 MultiLine(v) => (AccessibleProperty::MultiLine, v.to_value()),
135 MultiSelectable(v) => (AccessibleProperty::MultiSelectable, v.to_value()),
136 Orientation(v) => (AccessibleProperty::Orientation, v.into_glib().to_value()),
137 Placeholder(v) => (AccessibleProperty::Placeholder, v.to_value()),
138 ReadOnly(v) => (AccessibleProperty::ReadOnly, v.to_value()),
139 Required(v) => (AccessibleProperty::Required, v.to_value()),
140 RoleDescription(v) => (AccessibleProperty::RoleDescription, v.to_value()),
141 Sort(v) => (AccessibleProperty::Sort, v.into_glib().to_value()),
142 ValueMax(v) => (AccessibleProperty::ValueMax, v.to_value()),
143 ValueMin(v) => (AccessibleProperty::ValueMin, v.to_value()),
144 ValueNow(v) => (AccessibleProperty::ValueNow, v.to_value()),
145 ValueText(v) => (AccessibleProperty::ValueText, v.to_value()),
146 }
147 }
148}
149
150#[derive(Debug)]
154#[non_exhaustive]
155pub enum Relation<'r> {
156 ActiveDescendant(&'r Accessible),
157 ColCount(i32),
158 ColIndex(i32),
159 ColIndexText(&'r str),
160 ColSpan(i32),
161 Controls(&'r [&'r Accessible]),
162 DescribedBy(&'r [&'r Accessible]),
163 Details(&'r [&'r Accessible]),
164 ErrorMessage(&'r [&'r Accessible]),
165 FlowTo(&'r [&'r Accessible]),
166 LabelledBy(&'r [&'r Accessible]),
167 Owns(&'r [&'r Accessible]),
168 PosInSet(i32),
169 RowCount(i32),
170 RowIndex(i32),
171 RowIndexText(&'r str),
172 RowSpan(i32),
173 SetSize(i32),
174}
175
176impl Relation<'_> {
177 fn to_relation_value(&self) -> (AccessibleRelation, Value) {
178 use Relation::*;
179
180 fn to_ref_list_value(objects: &[&Accessible]) -> Value {
181 skip_assert_initialized!();
182 let mut value = Value::from_type(glib::Type::POINTER);
183 let list =
184 ToGlibContainerFromSlice::<*mut glib::ffi::GList>::to_glib_container_from_slice(
185 objects,
186 );
187 unsafe {
188 glib::gobject_ffi::g_value_set_pointer(
189 value.to_glib_none_mut().0,
190 list.0 as *mut std::ffi::c_void,
191 );
192 }
193 value
194 }
195
196 match self {
197 ActiveDescendant(v) => (AccessibleRelation::ActiveDescendant, v.to_value()),
198 ColCount(v) => (AccessibleRelation::ColCount, v.to_value()),
199 ColIndex(v) => (AccessibleRelation::ColIndex, v.to_value()),
200 ColIndexText(v) => (AccessibleRelation::ColIndexText, v.to_value()),
201 ColSpan(v) => (AccessibleRelation::ColSpan, v.to_value()),
202 Controls(v) => (AccessibleRelation::Controls, to_ref_list_value(v)),
203 DescribedBy(v) => (AccessibleRelation::DescribedBy, to_ref_list_value(v)),
204 Details(v) => (AccessibleRelation::Details, to_ref_list_value(v)),
205 ErrorMessage(v) => (AccessibleRelation::ErrorMessage, to_ref_list_value(v)),
206 FlowTo(v) => (AccessibleRelation::FlowTo, to_ref_list_value(v)),
207 LabelledBy(v) => (AccessibleRelation::LabelledBy, to_ref_list_value(v)),
208 Owns(v) => (AccessibleRelation::Owns, to_ref_list_value(v)),
209 PosInSet(v) => (AccessibleRelation::PosInSet, v.to_value()),
210 RowCount(v) => (AccessibleRelation::RowCount, v.to_value()),
211 RowIndex(v) => (AccessibleRelation::RowIndex, v.to_value()),
212 RowIndexText(v) => (AccessibleRelation::RowIndexText, v.to_value()),
213 RowSpan(v) => (AccessibleRelation::RowSpan, v.to_value()),
214 SetSize(v) => (AccessibleRelation::SetSize, v.to_value()),
215 }
216 }
217}
218
219#[derive(Debug)]
223#[non_exhaustive]
224pub enum State {
225 Busy(bool),
226 Checked(AccessibleTristate),
227 Disabled(bool),
228 Expanded(Option<bool>),
229 Hidden(bool),
230 Invalid(AccessibleInvalidState),
231 Pressed(AccessibleTristate),
232 Selected(Option<bool>),
233}
234
235impl State {
236 fn to_state_value(&self) -> (AccessibleState, Value) {
237 use State::*;
238
239 fn to_optional_bool_value(b: &Option<bool>) -> Value {
240 skip_assert_initialized!();
241 b.map(|b| b as i32).unwrap_or(-1).to_value()
242 }
243
244 match self {
245 Busy(v) => (AccessibleState::Busy, v.to_value()),
246 Checked(v) => (AccessibleState::Checked, v.into_glib().to_value()),
247 Disabled(v) => (AccessibleState::Disabled, v.to_value()),
248 Expanded(v) => (AccessibleState::Expanded, to_optional_bool_value(v)),
249 Hidden(v) => (AccessibleState::Hidden, v.to_value()),
250 Invalid(v) => (AccessibleState::Invalid, v.into_glib().to_value()),
251 Pressed(v) => (AccessibleState::Pressed, v.into_glib().to_value()),
252 Selected(v) => (AccessibleState::Selected, to_optional_bool_value(v)),
253 }
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use crate::{self as gtk4, Button};
261
262 #[test]
263 fn test_accessible_update_property() {
264 let widget = glib::Object::new::<Button>();
265 widget.update_property(&[
266 Property::Autocomplete(AccessibleAutocomplete::Inline),
267 Property::Description("Test"),
268 Property::HasPopup(true),
269 Property::KeyShortcuts("Test"),
270 Property::Label("Test"),
271 Property::Level(123),
272 Property::Modal(true),
273 Property::MultiLine(true),
274 Property::MultiSelectable(true),
275 Property::Orientation(Orientation::Horizontal),
276 Property::Placeholder("Test"),
277 Property::ReadOnly(true),
278 Property::Required(true),
279 Property::RoleDescription("Test"),
280 Property::Sort(AccessibleSort::Ascending),
281 Property::ValueMax(1.0),
282 Property::ValueMin(1.0),
283 Property::ValueNow(1.0),
284 Property::ValueText("Test"),
285 ]);
286 }
287
288 #[test]
289 fn test_accessible_update_relation() {
290 use crate::prelude::*;
291
292 let widget = glib::Object::new::<Button>();
293 let other1 = glib::Object::new::<Button>();
294 let other2 = glib::Object::new::<Button>();
295 widget.update_relation(&[
296 Relation::ActiveDescendant(other1.upcast_ref()),
297 Relation::ColCount(123),
298 Relation::ColIndex(123),
299 Relation::ColIndexText("Test"),
300 Relation::ColSpan(123),
301 Relation::Controls(&[other1.upcast_ref(), other2.upcast_ref()]),
302 Relation::DescribedBy(&[other1.upcast_ref(), other2.upcast_ref()]),
303 Relation::Details(&[other1.upcast_ref(), other2.upcast_ref()]),
304 Relation::ErrorMessage(&[other1.upcast_ref()]),
305 Relation::FlowTo(&[other1.upcast_ref(), other2.upcast_ref()]),
306 Relation::LabelledBy(&[other1.upcast_ref(), other2.upcast_ref()]),
307 Relation::Owns(&[other1.upcast_ref(), other2.upcast_ref()]),
308 Relation::PosInSet(123),
309 Relation::RowCount(123),
310 Relation::RowIndex(123),
311 Relation::RowIndexText("Test"),
312 Relation::RowSpan(123),
313 Relation::SetSize(123),
314 ]);
315 }
316
317 #[test]
318 fn test_accessible_update_state() {
319 let widget = glib::Object::new::<Button>();
320 widget.update_state(&[
321 State::Busy(true),
322 State::Checked(AccessibleTristate::Mixed),
323 State::Disabled(true),
324 State::Expanded(Some(true)),
325 State::Hidden(true),
326 State::Invalid(AccessibleInvalidState::Grammar),
327 State::Pressed(AccessibleTristate::Mixed),
328 State::Selected(Some(true)),
329 ]);
330 }
331}