1use zng_app::widget::info::access::WidgetAccessInfoBuilder;
2use zng_ext_l10n::Lang;
3use zng_wgt::prelude::*;
4
5use std::num::NonZeroU32;
6
7pub use zng_view_api::access::{
8 AccessCmdName, AccessRole, AutoComplete, CurrentKind, Invalid, LiveIndicator, Orientation, Popup, SortDirection,
9};
10
11#[property(CONTEXT)]
15pub fn access_role(child: impl UiNode, role: impl IntoVar<AccessRole>) -> impl UiNode {
16 with_access_state(child, role, |b, v| b.set_role(*v))
17}
18
19#[property(CONTEXT)]
21pub fn access_commands(child: impl UiNode, commands: impl IntoVar<Vec<AccessCmdName>>) -> impl UiNode {
22 with_access_state(child, commands, |b, v| {
23 for cmd in v {
24 b.push_command(*cmd);
25 }
26 })
27}
28
29#[property(WIDGET, default(true))]
39pub fn accessible(child: impl UiNode, accessible: impl IntoVar<bool>) -> impl UiNode {
40 with_access_state(child, accessible, |b, v| {
41 if !*v {
42 b.flag_inaccessible();
43 }
44 })
45}
46
47#[property(CONTEXT)]
54pub fn auto_complete(child: impl UiNode, auto_complete: impl IntoVar<AutoComplete>) -> impl UiNode {
55 with_access_state(child, auto_complete, |b, v| b.set_auto_complete(*v))
56}
57
58#[property(CONTEXT)]
60pub fn checked(child: impl UiNode, checked: impl IntoVar<Option<bool>>) -> impl UiNode {
61 with_access_state(child, checked, |b, v| b.set_checked(*v))
62}
63
64#[property(CONTEXT)]
66pub fn current(child: impl UiNode, kind: impl IntoVar<CurrentKind>) -> impl UiNode {
67 with_access_state(child, kind, |b, v| b.set_current(*v))
68}
69
70#[property(CONTEXT)]
76pub fn error_message(child: impl UiNode, invalid_wgt: impl IntoVar<WidgetId>) -> impl UiNode {
77 with_access_state(child, invalid_wgt, |b, v| b.set_error_message(*v))
78}
79
80#[property(CONTEXT)]
82pub fn active_descendant(child: impl UiNode, descendant: impl IntoVar<WidgetId>) -> impl UiNode {
83 with_access_state(child, descendant, |b, v| b.set_active_descendant(*v))
84}
85
86#[property(CONTEXT)]
94pub fn expanded(child: impl UiNode, expanded: impl IntoVar<bool>) -> impl UiNode {
95 with_access_state(child, expanded, |b, v| b.set_expanded(*v))
96}
97
98#[property(CONTEXT)]
100pub fn popup(child: impl UiNode, popup: impl IntoVar<Popup>) -> impl UiNode {
101 with_access_state(child, popup, |b, v| b.set_popup(*v))
102}
103
104#[property(CONTEXT)]
111pub fn label(child: impl UiNode, label: impl IntoVar<Txt>) -> impl UiNode {
112 with_access_state(child, label, |b, v| b.set_label(v.clone()))
113}
114
115#[property(CONTEXT)]
119pub fn labelled_by_child(child: impl UiNode, enabled: impl IntoVar<bool>) -> impl UiNode {
120 with_access_state(child, enabled, |b, v| {
121 if *v {
122 b.flag_labelled_by_child();
123 }
124 })
125}
126
127#[property(CONTEXT)]
129pub fn level(child: impl UiNode, hierarchical_level: impl IntoVar<NonZeroU32>) -> impl UiNode {
130 with_access_state(child, hierarchical_level, |b, v| b.set_level(*v))
131}
132
133#[property(CONTEXT)]
135pub fn multi_selectable(child: impl UiNode, multi_selectable: impl IntoVar<bool>) -> impl UiNode {
136 with_access_state(child, multi_selectable, |b, v| {
137 if *v {
138 b.flag_multi_selectable()
139 }
140 })
141}
142
143#[property(CONTEXT)]
145pub fn orientation(child: impl UiNode, orientation: impl IntoVar<Orientation>) -> impl UiNode {
146 with_access_state(child, orientation, |b, v| b.set_orientation(*v))
147}
148
149#[property(CONTEXT)]
151pub fn placeholder(child: impl UiNode, placeholder: impl IntoVar<Txt>) -> impl UiNode {
152 with_access_state(child, placeholder, |b, v| b.set_placeholder(v.clone()))
153}
154
155#[property(CONTEXT)]
157pub fn read_only(child: impl UiNode, read_only: impl IntoVar<bool>) -> impl UiNode {
158 with_access_state(child, read_only, |b, v| {
159 if *v {
160 b.flag_read_only()
161 }
162 })
163}
164
165#[property(CONTEXT)]
167pub fn required(child: impl UiNode, required: impl IntoVar<bool>) -> impl UiNode {
168 with_access_state(child, required, |b, v| {
169 if *v {
170 b.flag_required()
171 }
172 })
173}
174
175#[property(CONTEXT)]
177pub fn selected(child: impl UiNode, selected: impl IntoVar<bool>) -> impl UiNode {
178 with_access_state(child, selected, |b, v| {
179 if *v {
180 b.flag_selected()
181 }
182 })
183}
184
185#[property(CONTEXT)]
187pub fn sort(child: impl UiNode, direction: impl IntoVar<SortDirection>) -> impl UiNode {
188 with_access_state(child, direction, |b, v| b.set_sort(*v))
189}
190
191#[property(CONTEXT)]
193pub fn value_max(child: impl UiNode, max: impl IntoVar<f64>) -> impl UiNode {
194 with_access_state(child, max, |b, v| b.set_value_max(*v))
195}
196
197#[property(CONTEXT)]
199pub fn value_min(child: impl UiNode, min: impl IntoVar<f64>) -> impl UiNode {
200 with_access_state(child, min, |b, v| b.set_value_min(*v))
201}
202
203#[property(CONTEXT)]
205pub fn value(child: impl UiNode, value: impl IntoVar<f64>) -> impl UiNode {
206 with_access_state(child, value, |b, v| b.set_value(*v))
207}
208
209#[property(CONTEXT)]
211pub fn value_text(child: impl UiNode, value: impl IntoVar<Txt>) -> impl UiNode {
212 with_access_state(child, value, |b, v| b.set_value_text(v.clone()))
213}
214
215#[property(CONTEXT)]
223pub fn col_count(child: impl UiNode, count: impl IntoVar<usize>) -> impl UiNode {
224 with_access_state(child, count, |b, v| b.set_col_count(*v))
225}
226
227#[property(CONTEXT)]
229pub fn col_index(child: impl UiNode, index: impl IntoVar<usize>) -> impl UiNode {
230 with_access_state(child, index, |b, v| b.set_col_index(*v))
231}
232
233#[property(CONTEXT)]
235pub fn col_span(child: impl UiNode, span: impl IntoVar<usize>) -> impl UiNode {
236 with_access_state(child, span, |b, v| b.set_col_span(*v))
237}
238
239#[property(CONTEXT)]
247pub fn row_count(child: impl UiNode, count: impl IntoVar<usize>) -> impl UiNode {
248 with_access_state(child, count, |b, v| b.set_row_count(*v))
249}
250
251#[property(CONTEXT)]
253pub fn row_index(child: impl UiNode, index: impl IntoVar<usize>) -> impl UiNode {
254 with_access_state(child, index, |b, v| b.set_row_index(*v))
255}
256
257#[property(CONTEXT)]
259pub fn row_span(child: impl UiNode, span: impl IntoVar<usize>) -> impl UiNode {
260 with_access_state(child, span, |b, v| b.set_row_span(*v))
261}
262
263#[property(CONTEXT)]
265pub fn item_count(child: impl UiNode, count: impl IntoVar<usize>) -> impl UiNode {
266 with_access_state(child, count, |b, v| b.set_item_count(*v))
267}
268
269#[property(CONTEXT)]
271pub fn item_index(child: impl UiNode, index: impl IntoVar<usize>) -> impl UiNode {
272 with_access_state(child, index, |b, v| b.set_item_index(*v))
273}
274
275#[property(CONTEXT)]
277pub fn modal(child: impl UiNode, modal: impl IntoVar<bool>) -> impl UiNode {
278 with_access_state(child, modal, |b, v| {
279 if *v {
280 b.flag_modal()
281 }
282 })
283}
284
285#[property(CONTEXT)]
287pub fn controls(child: impl UiNode, controlled: impl IntoVar<Vec<WidgetId>>) -> impl UiNode {
288 with_access_state(child, controlled, |b, v| {
289 for id in v {
290 b.push_controls(*id);
291 }
292 })
293}
294
295#[property(CONTEXT)]
297pub fn described_by(child: impl UiNode, descriptors: impl IntoVar<Vec<WidgetId>>) -> impl UiNode {
298 with_access_state(child, descriptors, |b, v| {
299 for id in v {
300 b.push_described_by(*id);
301 }
302 })
303}
304
305#[property(CONTEXT)]
307pub fn details(child: impl UiNode, details: impl IntoVar<Vec<WidgetId>>) -> impl UiNode {
308 with_access_state(child, details, |b, v| {
309 for id in v {
310 b.push_details(*id);
311 }
312 })
313}
314
315#[property(CONTEXT)]
317pub fn labelled_by(child: impl UiNode, labels: impl IntoVar<Vec<WidgetId>>) -> impl UiNode {
318 with_access_state(child, labels, |b, v| {
319 for id in v {
320 b.push_labelled_by(*id);
321 }
322 })
323}
324
325#[property(CONTEXT)]
327pub fn owns(child: impl UiNode, owned: impl IntoVar<Vec<WidgetId>>) -> impl UiNode {
328 with_access_state(child, owned, |b, v| {
329 for id in v {
330 b.push_owns(*id);
331 }
332 })
333}
334
335#[property(CONTEXT)]
337pub fn flows_to(child: impl UiNode, next_options: impl IntoVar<Vec<WidgetId>>) -> impl UiNode {
338 with_access_state(child, next_options, |b, v| {
339 for id in v {
340 b.push_flows_to(*id);
341 }
342 })
343}
344
345#[property(CONTEXT)]
347pub fn invalid(child: impl UiNode, error: impl IntoVar<Invalid>) -> impl UiNode {
348 with_access_state(child, error, |b, v| b.set_invalid(*v))
349}
350
351#[property(CONTEXT)]
353pub fn lang(child: impl UiNode, lang: impl IntoVar<Lang>) -> impl UiNode {
354 with_access_state(child, lang, |b, v| b.set_lang(v.0.clone()))
355}
356
357#[property(CONTEXT)]
366pub fn scroll_horizontal(child: impl UiNode, normal_x: impl IntoVar<Factor>) -> impl UiNode {
367 with_access_state_var(child, normal_x, |b, v| b.set_scroll_horizontal(v.clone()))
368}
369
370#[property(CONTEXT)]
379pub fn scroll_vertical(child: impl UiNode, normal_y: impl IntoVar<Factor>) -> impl UiNode {
380 with_access_state_var(child, normal_y, |b, v| b.set_scroll_vertical(v.clone()))
381}
382
383#[property(CONTEXT)]
386pub fn live(
387 child: impl UiNode,
388 indicator: impl IntoVar<LiveIndicator>,
389 atomic: impl IntoVar<bool>,
390 busy: impl IntoVar<bool>,
391) -> impl UiNode {
392 let indicator = indicator.into_var();
393 let atomic = atomic.into_var();
394 let busy = busy.into_var();
395 let mut handles = VarHandles::dummy();
396 match_node(child, move |c, op| match op {
397 UiNodeOp::Deinit => {
398 handles.clear();
399 }
400 UiNodeOp::Info { info } => {
401 c.info(info);
402 if let Some(mut builder) = info.access() {
403 if handles.is_dummy() {
404 handles.push(indicator.subscribe(UpdateOp::Info, WIDGET.id()));
405 handles.push(atomic.subscribe(UpdateOp::Info, WIDGET.id()));
406 handles.push(busy.subscribe(UpdateOp::Info, WIDGET.id()));
407 }
408 builder.set_live(indicator.get(), atomic.get(), busy.get());
409 }
410 }
411 _ => {}
412 })
413}
414
415fn with_access_state<T: VarValue>(
416 child: impl UiNode,
417 state: impl IntoVar<T>,
418 set_info: impl Fn(&mut WidgetAccessInfoBuilder, &T) + Send + 'static,
419) -> impl UiNode {
420 with_access_state_var(child, state, move |b, v| v.with(|v| set_info(b, v)))
421}
422
423fn with_access_state_var<T: VarValue, I: IntoVar<T>>(
424 child: impl UiNode,
425 state: I,
426 set_info: impl Fn(&mut WidgetAccessInfoBuilder, &I::Var) + Send + 'static,
427) -> impl UiNode {
428 let state = state.into_var();
429 let mut handle = VarHandle::dummy();
430 match_node(child, move |c, op| match op {
431 UiNodeOp::Deinit => {
432 handle = VarHandle::dummy();
433 }
434 UiNodeOp::Info { info } => {
435 c.info(info);
436 if let Some(mut builder) = info.access() {
437 if handle.is_dummy() {
438 handle = state.subscribe(UpdateOp::Info, WIDGET.id());
439 }
440 set_info(&mut builder, &state)
441 }
442 }
443 _ => {}
444 })
445}