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