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